mirror of
https://github.com/wavetermdev/backup.git
synced 2026-04-22 15:26:58 -07:00
Compare commits
45 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 426f9546e5 | |||
| d410e5d07f | |||
| e66f34c9b5 | |||
| 58e971276e | |||
| 2d08037782 | |||
| 226699732d | |||
| 03b1e410e7 | |||
| 38c784bf8e | |||
| 40af311e5b | |||
| 112fda912f | |||
| f2eb383cc3 | |||
| 8d71f5538c | |||
| 7a37fdb942 | |||
| 80f7162691 | |||
| a639d72e30 | |||
| ce252d479b | |||
| d8d19ea035 | |||
| 21ab82e2e2 | |||
| 781ebe8154 | |||
| ad225ed28a | |||
| 633cb8fbd0 | |||
| 4ccd62f12a | |||
| b733724c7d | |||
| 4ff5dcf1e0 | |||
| f9d0e63d0c | |||
| ea9cb37de1 | |||
| 8200a312b9 | |||
| 3b65e9941a | |||
| 535fd0d7d9 | |||
| 96980b2f83 | |||
| b6c880c6ff | |||
| 1feffc8a11 | |||
| f442236679 | |||
| 414937911e | |||
| 5d39815dea | |||
| 96f636c2da | |||
| 112d002c2a | |||
| 4adcf6d92e | |||
| e79dcaf910 | |||
| e6186cd694 | |||
| 58551d6a2a | |||
| 2b8adfe40e | |||
| ce4b6d413c | |||
| 8a938744f7 | |||
| 87bf3f7a65 |
@@ -0,0 +1,81 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
schedule:
|
||||
- cron: '36 5 * * 5'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
# Runner size impacts CodeQL analysis time. To learn more, please see:
|
||||
# - https://gh.io/recommended-hardware-resources-for-running-codeql
|
||||
# - https://gh.io/supported-runners-and-hardware-resources
|
||||
# - https://gh.io/using-larger-runners
|
||||
# Consider using larger runners for possible analysis time improvements.
|
||||
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
|
||||
timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'go', 'javascript-typescript' ]
|
||||
# CodeQL supports [ 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' ]
|
||||
# Use only 'java-kotlin' to analyze code written in Java, Kotlin or both
|
||||
# Use only 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
|
||||
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
|
||||
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||
# queries: security-extended,security-and-quality
|
||||
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
|
||||
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
||||
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
||||
|
||||
# - run: |
|
||||
# echo "Run, Build Application using script"
|
||||
# ./location_of_script_within_repo/buildscript.sh
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
@@ -25,6 +25,11 @@ Wave Terminal works with MacOS and Linux (preliminary).
|
||||
|
||||
Install Wave Terminal from: [www.waveterm.dev/download](https://www.waveterm.dev/download)
|
||||
|
||||
Also available as a homebrew cask for MacOS:
|
||||
```
|
||||
brew install --cask wave
|
||||
```
|
||||
|
||||
## Links
|
||||
|
||||
* Homepage — https://www.waveterm.dev
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
# assumes we have Wave-darwin-x64-[version].zip and Wave-darwin-arm64-[version].zip in current directory
|
||||
VERSION=0.5.1
|
||||
VERSION=0.5.2
|
||||
rm -rf temp
|
||||
mkdir temp
|
||||
mkdir temp/x64
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
||||
+3
-1
@@ -2,7 +2,7 @@
|
||||
"name": "waveterm",
|
||||
"author": "Command Line Inc",
|
||||
"productName": "Wave",
|
||||
"version": "0.5.1",
|
||||
"version": "0.5.2",
|
||||
"main": "dist/emain.js",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
@@ -11,11 +11,13 @@
|
||||
"@table-nav/react": "^0.0.7",
|
||||
"@tanstack/match-sorter-utils": "^8.8.4",
|
||||
"@tanstack/react-table": "^8.10.3",
|
||||
"@types/semver": "^7.5.6",
|
||||
"autobind-decorator": "^2.4.0",
|
||||
"classnames": "^2.3.1",
|
||||
"dayjs": "^1.11.3",
|
||||
"dompurify": "^3.0.2",
|
||||
"electron-squirrel-startup": "^1.0.0",
|
||||
"framer-motion": "^10.16.16",
|
||||
"mobx": "6.12",
|
||||
"mobx-react": "^7.5.0",
|
||||
"monaco-editor": "^0.44.0",
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ node_modules/.bin/electron-rebuild
|
||||
```bash
|
||||
# @scripthaus command electron
|
||||
# @scripthaus cd :playbook
|
||||
WAVETERM_DEV=1 PCLOUD_ENDPOINT="https://ot2e112zx5.execute-api.us-west-2.amazonaws.com/dev" node_modules/.bin/electron dist-dev/emain.js
|
||||
WAVETERM_DEV=1 PCLOUD_ENDPOINT="https://ot2e112zx5.execute-api.us-west-2.amazonaws.com/dev" PCLOUD_WS_ENDPOINT="wss://5lfzlg5crl.execute-api.us-west-2.amazonaws.com/dev/" node_modules/.bin/electron dist-dev/emain.js
|
||||
```
|
||||
|
||||
```bash
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,3 +3,11 @@ 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";
|
||||
|
||||
export const LineContainer_Main = "main";
|
||||
export const LineContainer_History = "history";
|
||||
export const LineContainer_Sidebar = "sidebar";
|
||||
|
||||
@@ -134,7 +134,7 @@
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 40px;
|
||||
height: 23px;
|
||||
height: 22px;
|
||||
|
||||
input {
|
||||
opacity: 0;
|
||||
@@ -160,8 +160,8 @@
|
||||
content: "";
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
left: 3px;
|
||||
bottom: 3px;
|
||||
left: 2px;
|
||||
bottom: 2px;
|
||||
background-color: @term-white;
|
||||
transition: 0.5s;
|
||||
border-radius: 50%;
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+27
-45
@@ -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>,
|
||||
@@ -387,7 +388,7 @@ class TextField extends React.Component<TextFieldProps, TextFieldState> {
|
||||
// Method to handle blur at the component level
|
||||
@boundMethod
|
||||
handleComponentBlur() {
|
||||
if (this.inputRef.current && this.inputRef.current.contains(document.activeElement)) {
|
||||
if (this.inputRef.current?.contains(document.activeElement)) {
|
||||
this.inputRef.current.blur();
|
||||
}
|
||||
}
|
||||
@@ -440,7 +441,7 @@ class TextField extends React.Component<TextFieldProps, TextFieldState> {
|
||||
const { focused, internalValue, error } = this.state;
|
||||
|
||||
// Decide if the input should behave as controlled or uncontrolled
|
||||
const inputValue = value !== undefined ? value : internalValue;
|
||||
const inputValue = value ?? internalValue;
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -507,34 +508,10 @@ class NumberField extends TextField {
|
||||
}
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
handleKeyDown(event: React.KeyboardEvent<HTMLInputElement>) {
|
||||
// Allow backspace, delete, tab, escape, and enter
|
||||
if (
|
||||
[46, 8, 9, 27, 13].includes(event.keyCode) ||
|
||||
// Allow: Ctrl+A, Ctrl+C, Ctrl+X
|
||||
((event.keyCode === 65 || event.keyCode === 67 || event.keyCode === 88) && event.ctrlKey === true) ||
|
||||
// Allow: home, end, left, right
|
||||
(event.keyCode >= 35 && event.keyCode <= 39)
|
||||
) {
|
||||
return; // let it happen, don't do anything
|
||||
}
|
||||
// Ensure that it is a number and stop the keypress
|
||||
if (
|
||||
(event.shiftKey || event.keyCode < 48 || event.keyCode > 57) &&
|
||||
(event.keyCode < 96 || event.keyCode > 105)
|
||||
) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
// Use the render method from TextField but add the onKeyDown handler
|
||||
const renderedTextField = super.render();
|
||||
|
||||
return React.cloneElement(renderedTextField, {
|
||||
onKeyDown: this.handleKeyDown,
|
||||
});
|
||||
return React.cloneElement(renderedTextField);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -572,7 +549,7 @@ class PasswordField extends TextField {
|
||||
render() {
|
||||
const { decoration, className, placeholder, maxLength, label } = this.props;
|
||||
const { focused, internalValue, error, passwordVisible } = this.state;
|
||||
const inputValue = this.props.value !== undefined ? this.props.value : internalValue;
|
||||
const inputValue = this.props.value ?? internalValue;
|
||||
|
||||
// The input should always receive the real value
|
||||
const inputProps = {
|
||||
@@ -797,7 +774,7 @@ class InfoMessage extends React.Component<{ width: number; children: React.React
|
||||
function LinkRenderer(props: any): any {
|
||||
let newUrl = "https://extern?" + encodeURIComponent(props.href);
|
||||
return (
|
||||
<a href={newUrl} target="_blank">
|
||||
<a href={newUrl} target="_blank" rel={"noopener"}>
|
||||
{props.children}
|
||||
</a>
|
||||
);
|
||||
@@ -864,7 +841,7 @@ interface DropdownDecorationProps {
|
||||
}
|
||||
|
||||
interface DropdownProps {
|
||||
label: string;
|
||||
label?: string;
|
||||
options: { value: string; label: string }[];
|
||||
value?: string;
|
||||
className?: string;
|
||||
@@ -1031,7 +1008,7 @@ class Dropdown extends React.Component<DropdownProps, DropdownState> {
|
||||
const { label, options, value, placeholder, decoration, className, required } = this.props;
|
||||
const { isOpen, internalValue, highlightedIndex, isTouched } = this.state;
|
||||
|
||||
const currentValue = value !== undefined ? value : internalValue;
|
||||
const currentValue = value ?? internalValue;
|
||||
const selectedOptionLabel =
|
||||
options.find((option) => option.value === currentValue)?.label || placeholder || internalValue;
|
||||
|
||||
@@ -1051,7 +1028,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 +1045,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 +1056,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 +1088,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>
|
||||
@@ -1159,7 +1141,7 @@ class Modal extends React.Component<ModalProps> {
|
||||
}
|
||||
|
||||
render() {
|
||||
return ReactDOM.createPortal(this.renderModal(), document.getElementById("app") as HTMLElement);
|
||||
return ReactDOM.createPortal(this.renderModal(), document.getElementById("app") );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -647,7 +745,7 @@
|
||||
.client-settings-modal {
|
||||
.settings-field {
|
||||
.settings-label {
|
||||
width: 150px;
|
||||
width: 157px;
|
||||
}
|
||||
.dropdown-menu {
|
||||
min-width: 7.25em;
|
||||
|
||||
@@ -11,12 +11,22 @@ import dayjs from "dayjs";
|
||||
import localizedFormat from "dayjs/plugin/localizedFormat";
|
||||
import { GlobalModel, GlobalCommandRunner, RemotesModel } from "../../../model/model";
|
||||
import * as T from "../../../types/types";
|
||||
import { Markdown } from "../common";
|
||||
import {
|
||||
Markdown,
|
||||
Toggle,
|
||||
Modal,
|
||||
TextField,
|
||||
NumberField,
|
||||
InputDecoration,
|
||||
Dropdown,
|
||||
PasswordField,
|
||||
Tooltip,
|
||||
Button,
|
||||
Status,
|
||||
} from "../common";
|
||||
import * as util from "../../../util/util";
|
||||
import * as textmeasure from "../../../util/textmeasure";
|
||||
import { Toggle, Modal } from "../common";
|
||||
import { ClientDataType } from "../../../types/types";
|
||||
import { TextField, NumberField, InputDecoration, Dropdown, PasswordField, Tooltip, Button, Status } from "../common";
|
||||
|
||||
import { ReactComponent as WarningIcon } from "../../assets/icons/line/triangle-exclamation.svg";
|
||||
import shield from "../../assets/icons/shield_check.svg";
|
||||
@@ -39,18 +49,18 @@ const PasswordUnchangedSentinel = "--unchanged--";
|
||||
|
||||
@mobxReact.observer
|
||||
class ModalsProvider extends React.Component {
|
||||
renderModals() {
|
||||
const modals = GlobalModel.modalsModel.activeModals;
|
||||
|
||||
render() {
|
||||
let store = GlobalModel.modalsModel.store.slice();
|
||||
if (GlobalModel.needsTos()) {
|
||||
return <TosModal />;
|
||||
}
|
||||
|
||||
return modals.map((ModalComponent, index) => <ModalComponent key={index} />);
|
||||
}
|
||||
|
||||
render() {
|
||||
return <>{this.renderModals()}</>;
|
||||
let rtn: JSX.Element[] = [];
|
||||
for (let i = 0; i < store.length; i++) {
|
||||
let entry = store[i];
|
||||
let Comp = entry.component;
|
||||
rtn.push(<Comp key={entry.uniqueKey} />);
|
||||
}
|
||||
return <>{rtn}</>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,7 +289,11 @@ class TosModal extends React.Component<{}, {}> {
|
||||
</div>
|
||||
</div>
|
||||
<div className="item">
|
||||
<a target="_blank" href={util.makeExternLink("https://discord.gg/XfvZ334gwU")}>
|
||||
<a
|
||||
target="_blank"
|
||||
href={util.makeExternLink("https://discord.gg/XfvZ334gwU")}
|
||||
rel={"noopener"}
|
||||
>
|
||||
<img src={help} alt="Help" />
|
||||
</a>
|
||||
<div className="item-inner">
|
||||
@@ -288,7 +302,11 @@ class TosModal extends React.Component<{}, {}> {
|
||||
Get help, submit feature requests, report bugs, or just chat with fellow
|
||||
terminal enthusiasts.
|
||||
<br />
|
||||
<a target="_blank" href={util.makeExternLink("https://discord.gg/XfvZ334gwU")}>
|
||||
<a
|
||||
target="_blank"
|
||||
href={util.makeExternLink("https://discord.gg/XfvZ334gwU")}
|
||||
rel={"noopener"}
|
||||
>
|
||||
Join the Wave Discord Channel
|
||||
</a>
|
||||
</div>
|
||||
@@ -298,6 +316,7 @@ class TosModal extends React.Component<{}, {}> {
|
||||
<a
|
||||
target="_blank"
|
||||
href={util.makeExternLink("https://github.com/wavetermdev/waveterm")}
|
||||
rel={"noopener"}
|
||||
>
|
||||
<img src={github} alt="Github" />
|
||||
</a>
|
||||
@@ -309,6 +328,7 @@ class TosModal extends React.Component<{}, {}> {
|
||||
<a
|
||||
target="_blank"
|
||||
href={util.makeExternLink("https://github.com/wavetermdev/waveterm")}
|
||||
rel={"noopener"}
|
||||
>
|
||||
Github (wavetermdev/waveterm)
|
||||
</a>
|
||||
@@ -416,6 +436,7 @@ class AboutModal extends React.Component<{}, {}> {
|
||||
<a
|
||||
className="wave-button wave-button-link color-standard"
|
||||
href={util.makeExternLink("https://github.com/wavetermdev/waveterm")}
|
||||
rel={"noopener"}
|
||||
target="_blank"
|
||||
>
|
||||
<i className="fa-brands fa-github"></i>
|
||||
@@ -424,6 +445,7 @@ class AboutModal extends React.Component<{}, {}> {
|
||||
<a
|
||||
className="wave-button wave-button-link color-standard"
|
||||
href={util.makeExternLink("https://www.waveterm.dev/")}
|
||||
rel={"noopener"}
|
||||
target="_blank"
|
||||
>
|
||||
<i className="fa-sharp fa-light fa-globe"></i>
|
||||
@@ -432,6 +454,7 @@ class AboutModal extends React.Component<{}, {}> {
|
||||
<a
|
||||
className="wave-button wave-button-link color-standard"
|
||||
href={util.makeExternLink("https://github.com/wavetermdev/waveterm/blob/main/LICENSE")}
|
||||
rel={"noopener"}
|
||||
target="_blank"
|
||||
>
|
||||
<i className="fa-sharp fa-light fa-book-blank"></i>
|
||||
@@ -751,7 +774,6 @@ class CreateRemoteConnModal extends React.Component<{}, {}> {
|
||||
label="Connect Mode"
|
||||
options={[
|
||||
{ value: "startup", label: "startup" },
|
||||
{ value: "key", label: "key" },
|
||||
{ value: "auto", label: "auto" },
|
||||
{ value: "manual", label: "manual" },
|
||||
]}
|
||||
@@ -844,7 +866,7 @@ class ViewRemoteConnDetailModal extends React.Component<{}, {}> {
|
||||
|
||||
@boundMethod
|
||||
openEditModal(): void {
|
||||
GlobalModel.remotesModel.openEditModal();
|
||||
GlobalModel.remotesModel.startEditAuth();
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
@@ -957,7 +979,7 @@ class ViewRemoteConnDetailModal extends React.Component<{}, {}> {
|
||||
</Button>
|
||||
);
|
||||
if (remote.local) {
|
||||
installNowButton = <></>;
|
||||
installNowButton = <></>;
|
||||
updateAuthButton = <></>;
|
||||
cancelInstallButton = <></>;
|
||||
}
|
||||
@@ -1113,74 +1135,47 @@ class ViewRemoteConnDetailModal extends React.Component<{}, {}> {
|
||||
|
||||
@mobxReact.observer
|
||||
class EditRemoteConnModal extends React.Component<{}, {}> {
|
||||
internalTempAlias: OV<string>;
|
||||
internalTempKeyFile: OV<string>;
|
||||
internalTempPassword: OV<string>;
|
||||
tempAlias: OV<string>;
|
||||
tempKeyFile: OV<string>;
|
||||
tempPassword: OV<string>;
|
||||
tempConnectMode: OV<string>;
|
||||
tempAuthMode: OV<string>;
|
||||
model: RemotesModel;
|
||||
|
||||
constructor(props: { remotesModel?: RemotesModel }) {
|
||||
super(props);
|
||||
this.model = GlobalModel.remotesModel;
|
||||
this.internalTempAlias = mobx.observable.box(null, { name: "EditRemoteSettings-internalTempAlias" });
|
||||
this.internalTempKeyFile = mobx.observable.box(null, { name: "EditRemoteSettings-internalTempKeyFile" });
|
||||
this.internalTempPassword = mobx.observable.box(null, { name: "EditRemoteSettings-internalTempPassword" });
|
||||
this.tempAlias = mobx.observable.box(null, { name: "EditRemoteSettings-tempAlias" });
|
||||
this.tempAuthMode = mobx.observable.box(null, { name: "EditRemoteSettings-tempAuthMode" });
|
||||
this.tempKeyFile = mobx.observable.box(null, { name: "EditRemoteSettings-tempKeyFile" });
|
||||
this.tempPassword = mobx.observable.box(null, { name: "EditRemoteSettings-tempPassword" });
|
||||
this.tempConnectMode = mobx.observable.box(null, { name: "EditRemoteSettings-tempConnectMode" });
|
||||
}
|
||||
|
||||
@mobx.computed
|
||||
get selectedRemoteId() {
|
||||
return this.model.selectedRemoteId.get();
|
||||
}
|
||||
|
||||
@mobx.computed
|
||||
get selectedRemote(): T.RemoteType {
|
||||
return GlobalModel.getRemote(this.selectedRemoteId);
|
||||
}
|
||||
|
||||
@mobx.computed
|
||||
get remoteEdit(): T.RemoteEditType {
|
||||
return this.model.remoteEdit.get();
|
||||
}
|
||||
|
||||
@mobx.computed
|
||||
get isAuthEditMode(): boolean {
|
||||
return this.model.isAuthEditMode();
|
||||
}
|
||||
|
||||
@mobx.computed
|
||||
get tempAuthMode(): mobx.IObservableValue<string> {
|
||||
return mobx.observable.box(this.selectedRemote?.authtype, {
|
||||
name: "EditRemoteConnModal-authMode",
|
||||
});
|
||||
}
|
||||
|
||||
@mobx.computed
|
||||
get tempConnectMode(): mobx.IObservableValue<string> {
|
||||
return mobx.observable.box(this.selectedRemote?.connectmode, {
|
||||
name: "EditRemoteConnModal-connectMode",
|
||||
});
|
||||
}
|
||||
|
||||
@mobx.computed
|
||||
get tempAlias(): mobx.IObservableValue<string> {
|
||||
return mobx.observable.box(this.internalTempAlias.get() || this.selectedRemote.remotealias, {
|
||||
name: "EditRemoteConnModal-alias",
|
||||
});
|
||||
}
|
||||
|
||||
@mobx.computed
|
||||
get tempKeyFile(): mobx.IObservableValue<string> {
|
||||
return mobx.observable.box(this.internalTempKeyFile.get() || this.remoteEdit?.keystr, {
|
||||
name: "EditRemoteConnModal-keystr",
|
||||
});
|
||||
}
|
||||
|
||||
@mobx.computed
|
||||
get tempPassword(): mobx.IObservableValue<string> {
|
||||
const oldPassword = this.remoteEdit?.haspassword ? PasswordUnchangedSentinel : "";
|
||||
const newPassword = this.internalTempPassword.get() || oldPassword;
|
||||
return mobx.observable.box(newPassword, {
|
||||
name: "EditRemoteConnModal-password",
|
||||
});
|
||||
componentDidMount(): void {
|
||||
mobx.action(() => {
|
||||
this.tempAlias.set(this.selectedRemote?.remotealias);
|
||||
this.tempKeyFile.set(this.remoteEdit?.keystr);
|
||||
this.tempPassword.set(this.remoteEdit?.haspassword ? PasswordUnchangedSentinel : "");
|
||||
this.tempConnectMode.set(this.selectedRemote?.connectmode);
|
||||
this.tempAuthMode.set(this.selectedRemote?.authtype);
|
||||
})();
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
@@ -1192,21 +1187,35 @@ class EditRemoteConnModal extends React.Component<{}, {}> {
|
||||
@boundMethod
|
||||
handleChangeKeyFile(value: string): void {
|
||||
mobx.action(() => {
|
||||
this.internalTempKeyFile.set(value);
|
||||
this.tempKeyFile.set(value);
|
||||
})();
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
handleChangePassword(value: string): void {
|
||||
mobx.action(() => {
|
||||
this.internalTempPassword.set(value);
|
||||
this.tempPassword.set(value);
|
||||
})();
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
handleChangeAlias(value: string): void {
|
||||
mobx.action(() => {
|
||||
this.internalTempAlias.set(value);
|
||||
this.tempAlias.set(value);
|
||||
})();
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
handleChangeAuthMode(value: string): void {
|
||||
mobx.action(() => {
|
||||
this.tempAuthMode.set(value);
|
||||
})();
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
handleChangeConnectMode(value: string): void {
|
||||
mobx.action(() => {
|
||||
this.tempConnectMode.set(value);
|
||||
})();
|
||||
}
|
||||
|
||||
@@ -1236,10 +1245,13 @@ class EditRemoteConnModal extends React.Component<{}, {}> {
|
||||
submitRemote(): void {
|
||||
let authMode = this.tempAuthMode.get();
|
||||
let kwargs: Record<string, string> = {};
|
||||
if (!util.isStrEq(this.tempKeyFile.get(), this.remoteEdit?.keystr)) {
|
||||
if (authMode == "key" || authMode == "key+password") {
|
||||
if (authMode == "key" || authMode == "key+password") {
|
||||
let keyStrEq = util.isStrEq(this.tempKeyFile.get(), this.remoteEdit?.keystr);
|
||||
if (!keyStrEq) {
|
||||
kwargs["key"] = this.tempKeyFile.get();
|
||||
} else {
|
||||
}
|
||||
} else {
|
||||
if (!util.isBlank(this.tempKeyFile.get())) {
|
||||
kwargs["key"] = "";
|
||||
}
|
||||
}
|
||||
@@ -1289,11 +1301,9 @@ class EditRemoteConnModal extends React.Component<{}, {}> {
|
||||
|
||||
render() {
|
||||
let authMode = this.tempAuthMode.get();
|
||||
|
||||
if (this.remoteEdit === null || !this.isAuthEditMode) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal className="erconn-modal">
|
||||
<Modal.Header title="Edit Connection" onClose={this.model.closeModal} />
|
||||
@@ -1331,9 +1341,7 @@ class EditRemoteConnModal extends React.Component<{}, {}> {
|
||||
{ value: "key+password", label: "key+password" },
|
||||
]}
|
||||
value={this.tempAuthMode.get()}
|
||||
onChange={(val: string) => {
|
||||
this.tempAuthMode.set(val);
|
||||
}}
|
||||
onChange={this.handleChangeAuthMode}
|
||||
decoration={{
|
||||
endDecoration: (
|
||||
<InputDecoration>
|
||||
@@ -1400,14 +1408,11 @@ class EditRemoteConnModal extends React.Component<{}, {}> {
|
||||
label="Connect Mode"
|
||||
options={[
|
||||
{ value: "startup", label: "startup" },
|
||||
{ value: "key", label: "key" },
|
||||
{ value: "auto", label: "auto" },
|
||||
{ value: "manual", label: "manual" },
|
||||
]}
|
||||
value={this.tempConnectMode.get()}
|
||||
onChange={(val: string) => {
|
||||
this.tempConnectMode.set(val);
|
||||
}}
|
||||
onChange={this.handleChangeConnectMode}
|
||||
/>
|
||||
</div>
|
||||
<If condition={!util.isBlank(this.remoteEdit?.errorstr)}>
|
||||
|
||||
@@ -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 };
|
||||
|
||||
+331
-314
File diff suppressed because it is too large
Load Diff
+73
-29
@@ -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 appconst from "../appconst";
|
||||
|
||||
import { ReactComponent as CheckIcon } from "../assets/icons/line/check.svg";
|
||||
import { ReactComponent as CommentIcon } from "../assets/icons/line/comment.svg";
|
||||
@@ -75,11 +76,14 @@ class SmallLineAvatar extends React.Component<{ line: LineType; cmd: Cmd; onRigh
|
||||
iconTitle = "success";
|
||||
} else {
|
||||
icon = <XmarkIcon className="fail" />;
|
||||
iconTitle = "fail";
|
||||
iconTitle = "exitcode " + exitcode;
|
||||
}
|
||||
} else if (status == "hangup" || status == "error") {
|
||||
} else if (status == "hangup") {
|
||||
icon = <WarningIcon className="warning" />;
|
||||
iconTitle = status;
|
||||
} else if (status == "error") {
|
||||
icon = <XmarkIcon className="fail" />;
|
||||
iconTitle = "error";
|
||||
} else if (status == "running" || "detached") {
|
||||
icon = <RotateIcon className="warning spin" />;
|
||||
iconTitle = "running";
|
||||
@@ -126,7 +130,7 @@ class LineCmd extends React.Component<
|
||||
isOverflow: OV<boolean> = mobx.observable.box(false, {
|
||||
name: "line-overflow",
|
||||
});
|
||||
isMinimised: OV<boolean> = mobx.observable.box(false, {
|
||||
isMinimized: OV<boolean> = mobx.observable.box(false, {
|
||||
name: "line-minimised",
|
||||
});
|
||||
isCmdExpanded: OV<boolean> = mobx.observable.box(false, {
|
||||
@@ -351,12 +355,23 @@ class LineCmd extends React.Component<
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
clickMinimise() {
|
||||
clickMinimize() {
|
||||
mobx.action(() => {
|
||||
this.isMinimised.set(!this.isMinimised.get());
|
||||
this.isMinimized.set(!this.isMinimized.get());
|
||||
})();
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
clickMoveToSidebar() {
|
||||
let { line } = this.props;
|
||||
GlobalCommandRunner.screenSidebarAddLine(line.lineid);
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
clickRemoveFromSidebar() {
|
||||
GlobalCommandRunner.screenSidebarRemove();
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
handleResizeButton() {
|
||||
console.log("resize button");
|
||||
@@ -439,6 +454,7 @@ class LineCmd extends React.Component<
|
||||
mobx.action(() => {
|
||||
GlobalModel.lineSettingsModal.set(line.linenum);
|
||||
})();
|
||||
GlobalModel.modalsModel.pushModal(appconst.LINE_SETTINGS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -593,6 +609,14 @@ class LineCmd extends React.Component<
|
||||
{ name: "computed-shouldCmdFocus" }
|
||||
)
|
||||
.get();
|
||||
let isInSidebar = mobx
|
||||
.computed(
|
||||
() => {
|
||||
return screen.isSidebarOpen() && screen.isLineIdInSidebar(line.lineid);
|
||||
},
|
||||
{ name: "computed-isInSidebar" }
|
||||
)
|
||||
.get();
|
||||
let isStatic = staticRender;
|
||||
let isRunning = cmd.isRunning();
|
||||
let isExpanded = this.isCmdExpanded.get();
|
||||
@@ -617,6 +641,7 @@ class LineCmd extends React.Component<
|
||||
if (rtnStateDiffSize < 10) {
|
||||
rtnStateDiffSize = Math.max(termFontSize, 10);
|
||||
}
|
||||
let containerType = screen.getContainerType();
|
||||
return (
|
||||
<div
|
||||
className={mainDivCn}
|
||||
@@ -634,38 +659,57 @@ class LineCmd extends React.Component<
|
||||
{this.renderMeta1(cmd)}
|
||||
<If condition={!hidePrompt}>{this.renderCmdText(cmd)}</If>
|
||||
</div>
|
||||
<div
|
||||
key="pin"
|
||||
title="Pin"
|
||||
className={cn("line-icon", { active: line.pinned })}
|
||||
onClick={this.clickPin}
|
||||
style={{ display: "none" }}
|
||||
>
|
||||
<PinIcon className="icon" />
|
||||
</div>
|
||||
<div
|
||||
key="bookmark"
|
||||
title="Bookmark"
|
||||
className={cn("line-icon", "line-bookmark", "hoverEffect")}
|
||||
onClick={this.clickBookmark}
|
||||
>
|
||||
<FavoritesIcon className="icon" />
|
||||
</div>
|
||||
<div
|
||||
key="minimise"
|
||||
title={`${this.isMinimised.get() ? "Maximise" : "Minimise"}`}
|
||||
className={cn(
|
||||
"line-icon",
|
||||
"line-minimise",
|
||||
"hoverEffect",
|
||||
this.isMinimised.get() ? "line-icon-show" : ""
|
||||
)}
|
||||
onClick={this.clickMinimise}
|
||||
>
|
||||
{this.isMinimised.get() ? <PlusIcon className="icon plus" /> : <MinusIcon className="icon" />}
|
||||
<i className="fa-sharp fa-regular fa-bookmark" />
|
||||
</div>
|
||||
<If condition={containerType == appconst.LineContainer_Main}>
|
||||
<div
|
||||
key="minimize"
|
||||
title={`${this.isMinimized.get() ? "Maximise" : "Minimize"}`}
|
||||
className={cn(
|
||||
"line-icon",
|
||||
"line-minimize",
|
||||
"hoverEffect",
|
||||
this.isMinimized.get() ? "line-icon-show" : ""
|
||||
)}
|
||||
onClick={this.clickMinimize}
|
||||
>
|
||||
<If condition={this.isMinimized.get()}>
|
||||
<i className="fa-sharp fa-regular fa-circle-plus" />
|
||||
</If>
|
||||
<If condition={!this.isMinimized.get()}>
|
||||
<i className="fa-sharp fa-regular fa-circle-minus" />
|
||||
</If>
|
||||
</div>
|
||||
<div
|
||||
className="line-icon line-sidebar"
|
||||
onClick={this.clickMoveToSidebar}
|
||||
title="Move to Sidebar"
|
||||
>
|
||||
<i className="fa-sharp fa-solid fa-right-to-line" />
|
||||
</div>
|
||||
</If>
|
||||
<If condition={containerType == appconst.LineContainer_Sidebar}>
|
||||
<div
|
||||
className="line-icon line-sidebar"
|
||||
onClick={this.clickRemoveFromSidebar}
|
||||
title="Move to Sidebar"
|
||||
>
|
||||
<i className="fa-sharp fa-solid fa-left-to-line" />
|
||||
</div>
|
||||
</If>
|
||||
</div>
|
||||
<If condition={!this.isMinimised.get()}>
|
||||
<If condition={isInSidebar}>
|
||||
<div className="sidebar-message" style={{ fontSize: termFontSize }}>
|
||||
showing in sidebar =>
|
||||
</div>
|
||||
</If>
|
||||
<If condition={!this.isMinimized.get() && !isInSidebar}>
|
||||
<ErrorBoundary plugin={rendererPlugin?.name} lineContext={lineutil.getRendererContext(line)}>
|
||||
<If condition={rendererPlugin == null && !isNoneRenderer}>
|
||||
<TerminalRenderer
|
||||
|
||||
+6
-11
@@ -35,11 +35,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-message {
|
||||
color: @term-yellow;
|
||||
}
|
||||
|
||||
.line-header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding-bottom: 0.7rem;
|
||||
width: 100%;
|
||||
line-height: 1.2;
|
||||
|
||||
&.is-expanded {
|
||||
height: auto;
|
||||
@@ -54,9 +59,8 @@
|
||||
visibility: hidden;
|
||||
cursor: pointer;
|
||||
padding: 3px;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
border-radius: 50%;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.line-icon-show {
|
||||
@@ -307,15 +311,6 @@
|
||||
right: -4px;
|
||||
}
|
||||
|
||||
&.num-4 {
|
||||
}
|
||||
|
||||
&.num-5 {
|
||||
}
|
||||
|
||||
&.num-6 {
|
||||
}
|
||||
|
||||
&.status-done {
|
||||
background-color: #555;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@ type ScreenInterface = {
|
||||
setAnchorFields(anchorLine: number, anchorOffset: number, reason: string): void;
|
||||
getSelectedLine(): number;
|
||||
getAnchor(): { anchorLine: number; anchorOffset: number };
|
||||
isLineIdInSidebar(lineId: string): boolean;
|
||||
getLineByNum(lineNum: number): T.LineType;
|
||||
};
|
||||
|
||||
// <Line key={line.lineid} line={line} screen={screen} width={width} visible={this.visibleMap.get(lineNumStr)} staticRender={this.staticRender.get()} onHeightChange={this.onHeightChange} overrideCollapsed={this.collapsedMap.get(lineNumStr)} topBorder={topBorder} renderMode={renderMode}/>;
|
||||
@@ -298,6 +300,10 @@ class LinesView extends React.Component<
|
||||
if (newLine == 0) {
|
||||
return;
|
||||
}
|
||||
let line = screen.getLineByNum(newLine);
|
||||
if (line == null || screen.isLineIdInSidebar(line.lineid)) {
|
||||
return;
|
||||
}
|
||||
let lidx = this.findClosestLineIndex(newLine);
|
||||
this.setLineVisible(newLine, true);
|
||||
// console.log("update selected line", this.lastSelectedLine, "=>", newLine, sprintf("anchor=%d:%d", screen.anchorLine, screen.anchorOffset));
|
||||
@@ -351,7 +357,7 @@ class LinesView extends React.Component<
|
||||
}
|
||||
}
|
||||
|
||||
handleResize(entries: any) {
|
||||
handleResize(entries: ResizeObserverEntry[]) {
|
||||
let linesElem = this.linesRef.current;
|
||||
if (linesElem == null) {
|
||||
return;
|
||||
|
||||
+12
-5
@@ -7,11 +7,11 @@ let MagicLayout = {
|
||||
CmdInputHeight: 101, // height of full cmd-input div
|
||||
CmdInputBottom: 12, // .cmd-input
|
||||
|
||||
LineHeaderHeight: 46, // .line-header
|
||||
LinePadding: 24, // .line-header (12px * 2)
|
||||
WindowHeightOffset: 6, // .window-view, height is calc(100%-0.5rem)
|
||||
LineHeaderHeight: 46, // .line-header
|
||||
LinePadding: 24, // .line-header (12px * 2)
|
||||
WindowHeightOffset: 6, // .window-view, height is calc(100%-0.5rem)
|
||||
LinesBottomPadding: 10, // .lines, padding
|
||||
LineMarginTop: 12, // .line, margin
|
||||
LineMarginTop: 12, // .line, margin
|
||||
|
||||
ScreenMaxContentWidthBuffer: 50,
|
||||
ScreenMaxContentHeightBuffer: 0, // calc below
|
||||
@@ -21,12 +21,19 @@ let MagicLayout = {
|
||||
// the 3 is for descenders, which get cut off in the terminal without this
|
||||
TermDescendersHeight: 3,
|
||||
TermWidthBuffer: 15,
|
||||
|
||||
TabWidth: 175,
|
||||
|
||||
ScreenSidebarWidthPadding: 5,
|
||||
ScreenSidebarMinWidth: 200,
|
||||
ScreenSidebarHeaderHeight: 28,
|
||||
};
|
||||
|
||||
let m = MagicLayout;
|
||||
|
||||
// add up all the line overhead + padding. subtract 2 so we don't see the border of neighboring line
|
||||
m.ScreenMaxContentHeightBuffer = m.LineHeaderHeight + m.LinePadding + m.WindowHeightOffset + m.LinesBottomPadding + m.LineMarginTop - 2;
|
||||
m.ScreenMaxContentHeightBuffer =
|
||||
m.LineHeaderHeight + m.LinePadding + m.WindowHeightOffset + m.LinesBottomPadding + m.LineMarginTop - 2;
|
||||
|
||||
(window as any).MagicLayout = MagicLayout;
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
position: relative;
|
||||
font-size: 12.5px;
|
||||
line-height: 20px;
|
||||
backdrop-filter: blur(4px);
|
||||
|
||||
.title-bar-drag {
|
||||
-webkit-app-region: drag;
|
||||
@@ -320,4 +321,13 @@
|
||||
top: -3px;
|
||||
}
|
||||
}
|
||||
|
||||
.updateBanner {
|
||||
font-weight: bold;
|
||||
|
||||
.icon {
|
||||
font-weight: normal;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,14 +8,14 @@ import { boundMethod } from "autobind-decorator";
|
||||
import cn from "classnames";
|
||||
import dayjs from "dayjs";
|
||||
import type { RemoteType } from "../../types/types";
|
||||
import { If, For } from "tsx-control-statements/components";
|
||||
import { If } from "tsx-control-statements/components";
|
||||
import { compareLoose } from "semver";
|
||||
|
||||
import { ReactComponent as LeftChevronIcon } from "../assets/icons/chevron_left.svg";
|
||||
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";
|
||||
@@ -23,8 +23,9 @@ import { ReactComponent as AddIcon } from "../assets/icons/add.svg";
|
||||
import { ReactComponent as ActionsIcon } from "../assets/icons/tab/actions.svg";
|
||||
|
||||
import localizedFormat from "dayjs/plugin/localizedFormat";
|
||||
import { GlobalModel, GlobalCommandRunner, Session } from "../../model/model";
|
||||
import { GlobalModel, GlobalCommandRunner, Session, VERSION } from "../../model/model";
|
||||
import { sortAndFilterRemotes, isBlank, openLink } from "../../util/util";
|
||||
import * as constants from "../appconst";
|
||||
|
||||
import "./sidebar.less";
|
||||
|
||||
@@ -130,9 +131,7 @@ class MainSideBar extends React.Component<{}, {}> {
|
||||
|
||||
@boundMethod
|
||||
handleSettingsClick(): void {
|
||||
mobx.action(() => {
|
||||
GlobalModel.clientSettingsModal.set(true);
|
||||
})();
|
||||
GlobalModel.modalsModel.pushModal(constants.CLIENT_SETTINGS);
|
||||
}
|
||||
|
||||
@boundMethod
|
||||
@@ -142,6 +141,7 @@ class MainSideBar extends React.Component<{}, {}> {
|
||||
mobx.action(() => {
|
||||
GlobalModel.sessionSettingsModal.set(session.sessionId);
|
||||
})();
|
||||
GlobalModel.modalsModel.pushModal(constants.SESSION_SETTINGS);
|
||||
}
|
||||
|
||||
getSessions() {
|
||||
@@ -196,6 +196,11 @@ class MainSideBar extends React.Component<{}, {}> {
|
||||
}
|
||||
let isCollapsed = this.collapsed.get();
|
||||
let mainView = GlobalModel.activeMainView.get();
|
||||
let clientData = GlobalModel.clientData.get();
|
||||
let needsUpdate = false;
|
||||
if (!clientData?.clientopts.noreleasecheck && !isBlank(clientData?.releaseinfo?.latestversion)) {
|
||||
needsUpdate = compareLoose(VERSION, clientData.releaseinfo.latestversion) < 0;
|
||||
}
|
||||
return (
|
||||
<div className={cn("main-sidebar", { collapsed: isCollapsed }, { "is-dev": GlobalModel.isDev })}>
|
||||
<div className="title-bar-drag" />
|
||||
@@ -243,6 +248,15 @@ class MainSideBar extends React.Component<{}, {}> {
|
||||
</div>
|
||||
<div className="middle hideScrollbarUntillHover">{this.getSessions()}</div>
|
||||
<div className="bottom">
|
||||
<If condition={needsUpdate}>
|
||||
<div
|
||||
className="item hoverEffect unselectable updateBanner"
|
||||
onClick={() => openLink("https://www.waveterm.dev/download")}
|
||||
>
|
||||
<i className="fa-sharp fa-regular fa-circle-up icon" />
|
||||
Update Available
|
||||
</div>
|
||||
</If>
|
||||
<If condition={GlobalModel.isDev}>
|
||||
<div className="item hoverEffect unselectable" onClick={this.handlePluginsClick}>
|
||||
<AppsIcon className="icon" />
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user