mirror of
https://github.com/wavetermdev/backup.git
synced 2026-08-05 13:57:07 -07:00
Tab Settings (#117)
* use Modal component * icons selector * do not limit icons in the backend
This commit is contained in:
@@ -1122,10 +1122,12 @@ interface ModalFooterProps {
|
||||
|
||||
const ModalFooter: React.FC<ModalFooterProps> = ({ onCancel, onOk, cancelLabel = "Cancel", okLabel = "Ok" }) => (
|
||||
<div className="wave-modal-footer">
|
||||
<Button theme="secondary" onClick={onCancel}>
|
||||
{cancelLabel}
|
||||
</Button>
|
||||
<Button onClick={onOk}>{okLabel}</Button>
|
||||
{onCancel && (
|
||||
<Button theme="secondary" onClick={onCancel}>
|
||||
{cancelLabel}
|
||||
</Button>
|
||||
)}
|
||||
{onOk && <Button onClick={onOk}>{okLabel}</Button>}
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
@@ -388,6 +388,25 @@
|
||||
}
|
||||
}
|
||||
|
||||
.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%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.erconn-modal {
|
||||
width: 502px;
|
||||
min-height: 411px;
|
||||
@@ -732,31 +751,32 @@
|
||||
fill: @tab-pink;
|
||||
}
|
||||
|
||||
.tab-colors {
|
||||
.tab-colors,
|
||||
.tab-icons {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
.tab-color-sep {
|
||||
.tab-color-sep,
|
||||
.tab-icon-sep {
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.tab-color-cur {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.tab-color-icon {
|
||||
.tab-color-icon,
|
||||
.tab-icon-icon {
|
||||
width: 1.1em;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.tab-color-name {
|
||||
.tab-color-name,
|
||||
.tab-icon-name {
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
.tab-color-select {
|
||||
.tab-color-select,
|
||||
.tab-icon-select {
|
||||
cursor: pointer;
|
||||
margin: 5px;
|
||||
&:hover {
|
||||
|
||||
@@ -7,8 +7,16 @@ import * as mobx from "mobx";
|
||||
import { boundMethod } from "autobind-decorator";
|
||||
import { If, For } from "tsx-control-statements/components";
|
||||
import cn from "classnames";
|
||||
import { GlobalModel, GlobalCommandRunner, TabColors, MinFontSize, MaxFontSize } from "../../../model/model";
|
||||
import { Toggle, InlineSettingsTextEdit, SettingsError, InfoMessage } from "../common";
|
||||
import {
|
||||
GlobalModel,
|
||||
GlobalCommandRunner,
|
||||
TabColors,
|
||||
MinFontSize,
|
||||
MaxFontSize,
|
||||
TabIcons,
|
||||
Screen,
|
||||
} from "../../../model/model";
|
||||
import { Toggle, InlineSettingsTextEdit, SettingsError, InfoMessage, Modal } from "../common";
|
||||
import { LineType, RendererPluginType, ClientDataType, CommandRtnType } from "../../../types/types";
|
||||
import { ConnectionDropdown } from "../../connections_deprecated/connections";
|
||||
import { PluginModel } from "../../../plugins/plugins";
|
||||
@@ -53,12 +61,13 @@ Are you sure you want to stop web-sharing this tab?
|
||||
class ScreenSettingsModal extends React.Component<{ sessionId: string; screenId: string }, {}> {
|
||||
shareCopied: OV<boolean> = mobx.observable.box(false, { name: "ScreenSettings-shareCopied" });
|
||||
errorMessage: OV<string> = mobx.observable.box(null, { name: "ScreenSettings-errorMessage" });
|
||||
screen: Screen;
|
||||
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
let { sessionId, screenId } = props;
|
||||
let screen = GlobalModel.getScreenById(sessionId, screenId);
|
||||
if (screen == null) {
|
||||
this.screen = GlobalModel.getScreenById(sessionId, screenId);
|
||||
if (this.screen == null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -84,6 +93,15 @@ class ScreenSettingsModal extends React.Component<{ sessionId: string; screenId:
|
||||
commandRtnHandler(prtn, this.errorMessage);
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
selectTabIcon(icon: string): void {
|
||||
if (this.screen.getTabIcon() == icon) {
|
||||
return;
|
||||
}
|
||||
let prtn = GlobalCommandRunner.screenSetSettings(this.screen.screenId, { tabicon: icon }, false);
|
||||
util.commandRtnHandler(prtn, this.errorMessage);
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
handleChangeArchived(val: boolean): void {
|
||||
let { sessionId, screenId } = this.props;
|
||||
@@ -203,108 +221,123 @@ class ScreenSettingsModal extends React.Component<{ sessionId: string; screenId:
|
||||
render() {
|
||||
let { sessionId, screenId } = this.props;
|
||||
let inline = false;
|
||||
let screen = GlobalModel.getScreenById(sessionId, screenId);
|
||||
let screen = this.screen;
|
||||
if (screen == null) {
|
||||
return null;
|
||||
}
|
||||
console.log("screen.getTabIcon()", screen.getTabIcon());
|
||||
let color: string = null;
|
||||
let icon: string = null;
|
||||
let curRemote = GlobalModel.getRemote(GlobalModel.getActiveScreen().getCurRemoteInstance().remoteid);
|
||||
return (
|
||||
<div className={cn("modal screen-settings-modal settings-modal prompt-modal is-active")}>
|
||||
<div className="modal-background" />
|
||||
<div className="modal-content">
|
||||
{this.shareCopied.get() && <div className="copied-indicator" />}
|
||||
<header>
|
||||
<div className="modal-title">tab settings ({screen.name.get()})</div>
|
||||
<div className="close-icon hoverEffect" title="Close (Escape)" onClick={this.closeModal}>
|
||||
<XmarkIcon />
|
||||
</div>
|
||||
</header>
|
||||
<div className="inner-content">
|
||||
<div className="settings-field">
|
||||
<div className="settings-label">Tab Id</div>
|
||||
<div className="settings-input">{screen.screenId}</div>
|
||||
</div>
|
||||
<div className="settings-field">
|
||||
<div className="settings-label">Name</div>
|
||||
<div className="settings-input">
|
||||
<InlineSettingsTextEdit
|
||||
placeholder="name"
|
||||
text={screen.name.get() ?? "(none)"}
|
||||
value={screen.name.get() ?? ""}
|
||||
onChange={this.inlineUpdateName}
|
||||
maxLength={50}
|
||||
showIcon={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="settings-field">
|
||||
<div className="settings-label">Connection</div>
|
||||
<div className="settings-input">
|
||||
<ConnectionDropdown
|
||||
curRemote={curRemote}
|
||||
onSelectRemote={this.selectRemote}
|
||||
allowNewConn={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="settings-field">
|
||||
<div className="settings-label">Tab Color</div>
|
||||
<div className="settings-input">
|
||||
<div className="tab-colors">
|
||||
<div className="tab-color-cur">
|
||||
<SquareIcon className={cn("tab-color-icon", "color-" + screen.getTabColor())} />
|
||||
<span className="tab-color-name">{screen.getTabColor()}</span>
|
||||
</div>
|
||||
<div className="tab-color-sep">|</div>
|
||||
<For each="color" of={TabColors}>
|
||||
<div
|
||||
key={color}
|
||||
className="tab-color-select"
|
||||
onClick={() => this.selectTabColor(color)}
|
||||
>
|
||||
<SquareIcon className={cn("tab-color-icon", "color-" + color)} />
|
||||
</div>
|
||||
</For>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="settings-field">
|
||||
<div className="settings-label">
|
||||
<div>Archived</div>
|
||||
<InfoMessage width={400}>
|
||||
Archive will hide the tab. Commands and output will be retained in history.
|
||||
</InfoMessage>
|
||||
</div>
|
||||
<div className="settings-input">
|
||||
<Toggle checked={screen.archived.get()} onChange={this.handleChangeArchived} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="settings-field">
|
||||
<div className="settings-label">
|
||||
<div>Actions</div>
|
||||
<InfoMessage width={400}>
|
||||
Delete will remove the tab, removing all commands and output from history.
|
||||
</InfoMessage>
|
||||
</div>
|
||||
<div className="settings-input">
|
||||
<div
|
||||
onClick={this.handleDeleteScreen}
|
||||
className="button is-prompt-danger is-outlined is-small"
|
||||
>
|
||||
Delete Tab
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<SettingsError errorMessage={this.errorMessage} />
|
||||
<Modal className="screen-settings-modal">
|
||||
<Modal.Header onClose={this.closeModal} title={`tab settings (${screen.name.get()})`} />
|
||||
<div className="wave-modal-body">
|
||||
<div className="settings-field">
|
||||
<div className="settings-label">Tab Id</div>
|
||||
<div className="settings-input">{screen.screenId}</div>
|
||||
</div>
|
||||
<footer>
|
||||
<div onClick={this.closeModal} className="button is-wave-green is-outlined is-small">
|
||||
Close
|
||||
<div className="settings-field">
|
||||
<div className="settings-label">Name</div>
|
||||
<div className="settings-input">
|
||||
<InlineSettingsTextEdit
|
||||
placeholder="name"
|
||||
text={screen.name.get() ?? "(none)"}
|
||||
value={screen.name.get() ?? ""}
|
||||
onChange={this.inlineUpdateName}
|
||||
maxLength={50}
|
||||
showIcon={true}
|
||||
/>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
<div className="settings-field">
|
||||
<div className="settings-label">Connection</div>
|
||||
<div className="settings-input">
|
||||
<ConnectionDropdown
|
||||
curRemote={curRemote}
|
||||
onSelectRemote={this.selectRemote}
|
||||
allowNewConn={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="settings-field">
|
||||
<div className="settings-label">Tab Color</div>
|
||||
<div className="settings-input">
|
||||
<div className="tab-colors">
|
||||
<div className="tab-color-cur">
|
||||
<SquareIcon className={cn("tab-color-icon", "color-" + screen.getTabColor())} />
|
||||
<span className="tab-color-name">{screen.getTabColor()}</span>
|
||||
</div>
|
||||
<div className="tab-color-sep">|</div>
|
||||
<For each="color" of={TabColors}>
|
||||
<div
|
||||
key={color}
|
||||
className="tab-color-select"
|
||||
onClick={() => this.selectTabColor(color)}
|
||||
>
|
||||
<SquareIcon className={cn("tab-color-icon", "color-" + color)} />
|
||||
</div>
|
||||
</For>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="settings-field">
|
||||
<div className="settings-label">Tab Icon</div>
|
||||
<div className="settings-input">
|
||||
<div className="tab-icons">
|
||||
<div className="tab-icon-cur">
|
||||
<If condition={screen.getTabIcon() == "default"}>
|
||||
<SquareIcon className={cn("tab-color-icon", "color-white")} />
|
||||
</If>
|
||||
<If condition={screen.getTabIcon() != "default"}>
|
||||
<i className={`fa-sharp fa-solid fa-${screen.getTabIcon()}`}></i>
|
||||
</If>
|
||||
<span className="tab-icon-name">{screen.getTabIcon()}</span>
|
||||
</div>
|
||||
<div className="tab-icon-sep">|</div>
|
||||
<For each="icon" of={TabIcons}>
|
||||
<div
|
||||
key={color}
|
||||
className="tab-icon-select"
|
||||
onClick={() => this.selectTabIcon(icon)}
|
||||
>
|
||||
<i className={`fa-sharp fa-solid fa-${icon}`}></i>
|
||||
</div>
|
||||
</For>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="settings-field">
|
||||
<div className="settings-label">
|
||||
<div>Archived</div>
|
||||
<InfoMessage width={400}>
|
||||
Archive will hide the tab. Commands and output will be retained in history.
|
||||
</InfoMessage>
|
||||
</div>
|
||||
<div className="settings-input">
|
||||
<Toggle checked={screen.archived.get()} onChange={this.handleChangeArchived} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="settings-field">
|
||||
<div className="settings-label">
|
||||
<div>Actions</div>
|
||||
<InfoMessage width={400}>
|
||||
Delete will remove the tab, removing all commands and output from history.
|
||||
</InfoMessage>
|
||||
</div>
|
||||
<div className="settings-input">
|
||||
<div
|
||||
onClick={this.handleDeleteScreen}
|
||||
className="button is-prompt-danger is-outlined is-small"
|
||||
>
|
||||
Delete Tab
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<SettingsError errorMessage={this.errorMessage} />
|
||||
</div>
|
||||
</div>
|
||||
<Modal.Footer cancelLabel="Close" onCancel={this.closeModal} />
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,24 +11,19 @@ import cn from "classnames";
|
||||
import { debounce } from "throttle-debounce";
|
||||
import dayjs from "dayjs";
|
||||
import { GlobalCommandRunner, TabColors, TabIcons } from "../../../model/model";
|
||||
import type { LineType, RenderModeType, LineFactoryProps, CommandRtnType } from "../../../types/types";
|
||||
import type { LineType, RenderModeType, LineFactoryProps } from "../../../types/types";
|
||||
import * as T from "../../../types/types";
|
||||
import localizedFormat from "dayjs/plugin/localizedFormat";
|
||||
import { InlineSettingsTextEdit, RemoteStatusLight, Button } from "../../common/common";
|
||||
import { Button } from "../../common/common";
|
||||
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, InputDecoration } from "../../common/common";
|
||||
import { TextField } from "../../common/common";
|
||||
import { ReactComponent as EllipseIcon } from "../../assets/icons/ellipse.svg";
|
||||
import { ReactComponent as Check12Icon } from "../../assets/icons/check12.svg";
|
||||
import { ReactComponent as GlobeIcon } from "../../assets/icons/globe.svg";
|
||||
import { ReactComponent as StatusCircleIcon } from "../../assets/icons/statuscircle.svg";
|
||||
import { ReactComponent as ArrowsUpDownIcon } from "../../assets/icons/arrowsupdown.svg";
|
||||
import { ReactComponent as CircleIcon } from "../../assets/icons/circle.svg";
|
||||
import { ReactComponent as AddIcon } from "../../assets/icons/add.svg";
|
||||
import { ReactComponent as SquareIcon } from "../../assets/icons/tab/square.svg";
|
||||
|
||||
import "./screenview.less";
|
||||
@@ -439,12 +434,12 @@ class ScreenWindowView extends React.Component<{ session: Session; screen: Scree
|
||||
/>
|
||||
</If>
|
||||
<If condition={screen.filterRunning.get()}>
|
||||
<div className='filter-running'>
|
||||
<div className="filter-running">
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="color-yellow"
|
||||
style={{borderRadius: '999px'}}
|
||||
onClick={this.disableFilter}
|
||||
variant="outlined"
|
||||
color="color-yellow"
|
||||
style={{ borderRadius: "999px" }}
|
||||
onClick={this.disableFilter}
|
||||
>
|
||||
Showing Running Commands
|
||||
<i className="fa-sharp fa-solid fa-xmark" />
|
||||
|
||||
@@ -11,7 +11,7 @@ import cn from "classnames";
|
||||
import { debounce } from "throttle-debounce";
|
||||
import dayjs from "dayjs";
|
||||
import localizedFormat from "dayjs/plugin/localizedFormat";
|
||||
import { GlobalModel, GlobalCommandRunner, Session, ScreenLines, Screen } from "../../../model/model";
|
||||
import { GlobalModel, GlobalCommandRunner, Session, Screen, TabIcons } 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";
|
||||
|
||||
@@ -764,10 +764,6 @@ func ScreenSetCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (ss
|
||||
}
|
||||
if pk.Kwargs["tabicon"] != "" {
|
||||
icon := pk.Kwargs["tabicon"]
|
||||
err = validateIcon(icon, "screen tabicon")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
updateMap[sstore.ScreenField_TabIcon] = icon
|
||||
varsUpdated = append(varsUpdated, "tabicon")
|
||||
setNonAnchor = true
|
||||
@@ -1993,15 +1989,6 @@ func validateColor(color string, typeStr string) error {
|
||||
return fmt.Errorf("invalid %s, valid colors are: %s", typeStr, formatStrs(ColorNames, "or", false))
|
||||
}
|
||||
|
||||
func validateIcon(icon string, typeStr string) error {
|
||||
for _, c := range TabIcons {
|
||||
if icon == c {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("invalid %s, valid icons are: %s", typeStr, formatStrs(TabIcons, "or", false))
|
||||
}
|
||||
|
||||
func validateRemoteColor(color string, typeStr string) error {
|
||||
for _, c := range RemoteColorNames {
|
||||
if color == c {
|
||||
|
||||
Reference in New Issue
Block a user