Compare commits

..

3 Commits

Author SHA1 Message Date
Red Adaya cdeef49ec1 fix tabs freeze on touchpad scroll 2023-12-24 15:31:48 +08:00
Red Adaya 7e128c791b only pop modal when purging is successful 2023-12-23 11:34:56 +08:00
Red Adaya 09c4a42557 immediately hide modal when deleting workspace 2023-12-22 07:06:10 +08:00
92 changed files with 1536 additions and 29453 deletions
-57
View File
@@ -1,57 +0,0 @@
name: "Build MacOS x64"
on: workflow_dispatch
env:
WAVETERM_VERSION: 0.5.3
GO_VERSION: '1.21.5'
NODE_VERSION: '21.5.0'
jobs:
runbuild-x64:
name: "Build MacOS x64"
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v4
with:
go-version: ${{env.GO_VERSION}}
cache-dependency-path: |
wavesrv/go.sum
waveshell/go.sum
- run: brew tap scripthaus-dev/scripthaus
- run: brew install scripthaus
- uses: actions/setup-node@v4
with:
node-version: ${{env.NODE_VERSION}}
cache: 'yarn'
- run: yarn --frozen-lockfile
- run: scripthaus run build-package
- uses: actions/upload-artifact@v3
with:
name: waveterm-build-darwin-x64
path: out/make/zip/darwin/x64/*.zip
retention-days: 2
runbuild-arm64:
name: "Build MacOS arm64"
runs-on: macos-latest-xlarge
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v4
with:
go-version: ${{env.GO_VERSION}}
cache-dependency-path: |
wavesrv/go.sum
waveshell/go.sum
- run: brew tap scripthaus-dev/scripthaus
- run: brew install scripthaus
- uses: actions/setup-node@v4
with:
node-version: ${{env.NODE_VERSION}}
cache: 'yarn'
- run: yarn --frozen-lockfile
- run: scripthaus run build-package
- uses: actions/upload-artifact@v3
with:
name: waveterm-build-darwin-arm64
path: out/make/zip/darwin/arm64/*.zip
retention-days: 2
-20
View File
@@ -1,20 +0,0 @@
# Open-Source Acknowledgements
We make use of many amazing open-source projects to build Wave Terminal. Here are the links to the latest acknowledgements for each of our components, including license disclaimers for each dependency:
- [Frontend](./disclaimers/frontend.md)
- [Backend](./disclaimers/backend.md)
## Generating license disclaimers
The license disclaimers for the backend are generated using the [go-licenses](https://github.com/google/go-licenses) tool. We supply a template file ([`go_licenses_report.tpl`](./go_licenses_report.tpl)) to generate a pretty print of the disclaimers for each dependency. This outputs to the file [`backend.md`](./disclaimers/backend.md).
The license disclaimers for the frontend are generated using the [`yarn licenses` tool](https://classic.yarnpkg.com/lang/en/docs/cli/licenses/). This outputs to the file [`frontend.md`](./disclaimers/frontend.md).
These three disclaimer files linked above will be periodically regenerated to reflect new dependencies.
The [`scripthaus.md` file](../scripthaus.md) contains scripts to genrate the disclaimers and package them. To manually generate the disclaimers, run the following from the repository root directory:
```bash
scripthaus run generate-license-disclaimers
```
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
-16
View File
@@ -1,16 +0,0 @@
# Wave Terminal Backend Acknowledgements
The following sets forth attribution notices for third party software that may be contained in portions of the Wave Terminal product.
{{ range . }}
## {{ .Name }}
* Name: {{ .Name }}
* Version: {{ .Version }}
* License: [{{ .LicenseName }}]({{ .LicenseURL }})
```txt
{{ .LicenseText }}
```
-----
{{ end }}
+1 -1
View File
@@ -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.3
VERSION=0.5.2
rm -rf temp
mkdir temp
mkdir temp/x64
+2 -5
View File
@@ -1,7 +1,4 @@
go 1.21
toolchain go1.21.5
go 1.18
use ./wavesrv
use ./waveshell
use ./waveshell
-18
View File
@@ -1,25 +1,7 @@
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/renameio/v2 v2.0.0/go.mod h1:BtmJXm5YlszgC+TD4HOEEUFgkJP3nLxehU6hfe7jRt4=
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/wavetermdev/ssh_config v0.0.0-20240109090616-36c8da3d7376 h1:tFhJgTu7lgd+hldLfPSzDCoWUpXI8wHKR3rxq5jTLkQ=
github.com/wavetermdev/ssh_config v0.0.0-20240109090616-36c8da3d7376/go.mod h1:q2RIzfka+BXARoNexmF9gkxEX7DmvbW9P4hIVx2Kg4M=
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=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+12 -13
View File
@@ -2,7 +2,7 @@
"name": "waveterm",
"author": "Command Line Inc",
"productName": "Wave",
"version": "0.5.3",
"version": "0.5.2",
"main": "dist/emain.js",
"license": "Apache-2.0",
"dependencies": {
@@ -13,7 +13,6 @@
"@tanstack/react-table": "^8.10.3",
"@types/semver": "^7.5.6",
"autobind-decorator": "^2.4.0",
"base64-js": "^1.5.1",
"classnames": "^2.3.1",
"dayjs": "^1.11.3",
"dompurify": "^3.0.2",
@@ -27,6 +26,7 @@
"papaparse": "^5.4.1",
"react": "^18.1.0",
"react-dom": "^18.1.0",
"react-json-view": "^1.21.3",
"react-markdown": "^9.0.0",
"remark": "^15.0.1",
"remark-gfm": "^4.0.0",
@@ -35,8 +35,7 @@
"tsx-control-statements": "^4.1.1",
"uuid": "^9.0.0",
"winston": "^3.8.2",
"xterm": "^5.0.0",
"xterm-addon-web-links": "^0.9.0"
"xterm": "^5.0.0"
},
"devDependencies": {
"@babel/cli": "^7.17.10",
@@ -50,17 +49,17 @@
"@babel/preset-env": "^7.18.2",
"@babel/preset-react": "^7.23.3",
"@babel/preset-typescript": "^7.17.12",
"@electron-forge/cli": "^7.2.0",
"@electron-forge/maker-deb": "^7.2.0",
"@electron-forge/maker-rpm": "^7.2.0",
"@electron-forge/maker-snap": "^7.2.0",
"@electron-forge/maker-squirrel": "^7.2.0",
"@electron-forge/maker-zip": "^7.2.0",
"@electron-forge/cli": "^6.0.0-beta.70",
"@electron-forge/maker-deb": "^6.0.0-beta.70",
"@electron-forge/maker-rpm": "^6.0.0-beta.70",
"@electron-forge/maker-snap": "^6.4.2",
"@electron-forge/maker-squirrel": "^6.0.0-beta.70",
"@electron-forge/maker-zip": "^6.0.0-beta.70",
"@electron/rebuild": "^3.4.0",
"@svgr/webpack": "^8.1.0",
"@types/classnames": "^2.3.1",
"@types/electron": "^1.6.10",
"@types/node": "20.11.0",
"@types/node": "20.10.3",
"@types/papaparse": "^5.3.10",
"@types/react": "^18.0.12",
"@types/sprintf-js": "^1.1.3",
@@ -71,7 +70,7 @@
"babel-plugin-jsx-control-statements": "^4.1.2",
"copy-webpack-plugin": "^11.0.0",
"css-loader": "^6.7.1",
"electron": "28.1.3",
"electron": "27.1.3",
"file-loader": "^6.2.0",
"http-server": "^14.1.1",
"less": "^4.1.2",
@@ -82,7 +81,7 @@
"raw-loader": "^4.0.2",
"react-split-it": "^2.0.0",
"style-loader": "^3.3.1",
"typescript": "^5.0.0",
"typescript": "^4.7.3",
"webpack": "^5.73.0",
"webpack-bundle-analyzer": "^4.10.1",
"webpack-cli": "^5.1.4",
-12
View File
@@ -100,15 +100,3 @@ scripthaus run fullbuild-waveshell
echo building wavesrv
scripthaus run build-wavesrv
```
```bash
# @scripthaus command generate-license-disclaimers
DISCLAIMER_DIR="./acknowledgements"
DISCLAIMER_OUTPUT_DIR="$DISCLAIMER_DIR/disclaimers"
if [ -d "$DISCLAIMER_OUTPUT_DIR" ]; then
rm -rf "$DISCLAIMER_OUTPUT_DIR"
fi
mkdir "$DISCLAIMER_OUTPUT_DIR"
go run github.com/google/go-licenses@latest report ./wavesrv/... ./waveshell/... --template "$DISCLAIMER_DIR/go_licenses_report.tpl" --ignore github.com/wavetermdev/waveterm > "$DISCLAIMER_OUTPUT_DIR/backend.md"
yarn licenses generate-disclaimer > "$DISCLAIMER_OUTPUT_DIR/frontend.md"
```
+5 -46
View File
@@ -476,26 +476,17 @@ a.a-block {
}
}
.icon.color-default,
.icon.color-green {
path,
circle {
fill: @tab-green;
}
i {
color: @tab-green;
}
}
.icon.color-red {
path,
circle {
fill: @tab-red;
}
}
i {
color: @tab-red;
.icon.color-green {
path,
circle {
fill: @tab-green;
}
}
@@ -504,10 +495,6 @@ a.a-block {
circle {
fill: @tab-orange;
}
i {
color: @tab-orange;
}
}
.icon.color-blue {
@@ -515,10 +502,6 @@ a.a-block {
circle {
fill: @tab-blue;
}
i {
color: @tab-blue;
}
}
.icon.color-yellow {
@@ -526,10 +509,6 @@ a.a-block {
circle {
fill: @tab-yellow;
}
i {
color: @tab-yellow;
}
}
.icon.color-pink {
@@ -537,10 +516,6 @@ a.a-block {
circle {
fill: @tab-pink;
}
i {
color: @tab-pink;
}
}
.icon.color-mint {
@@ -548,10 +523,6 @@ a.a-block {
circle {
fill: @tab-mint;
}
i {
color: @tab-mint;
}
}
.icon.color-cyan {
@@ -559,10 +530,6 @@ a.a-block {
circle {
fill: @tab-cyan;
}
i {
color: @tab-cyan;
}
}
.icon.color-violet {
@@ -570,10 +537,6 @@ a.a-block {
circle {
fill: @tab-violet;
}
i {
color: @tab-violet;
}
}
.icon.color-white {
@@ -581,10 +544,6 @@ a.a-block {
circle {
fill: @tab-white;
}
i {
color: @tab-white;
}
}
.status-icon.status-connected {
+8 -2
View File
@@ -16,9 +16,14 @@ import { PluginsView } from "./pluginsview/pluginsview";
import { BookmarksView } from "./bookmarks/bookmarks";
import { HistoryView } from "./history/history";
import { ConnectionsView } from "./connections/connections";
import {
ScreenSettingsModal,
SessionSettingsModal,
LineSettingsModal,
ClientSettingsModal,
} from "./common/modals/settings";
import { MainSideBar } from "./sidebar/sidebar";
import { DisconnectedModal, ClientStopModal } from "./common/modals";
import { ModalsProvider } from "./common/modals/provider";
import { DisconnectedModal, ClientStopModal, ModalsProvider } from "./common/modals/modals";
import { ErrorBoundary } from "./common/error/errorboundary";
import "./app.less";
@@ -69,6 +74,7 @@ class App extends React.Component<{}, {}> {
}
render() {
let clientSettingsModal = GlobalModel.clientSettingsModal.get();
let remotesModel = GlobalModel.remotesModel;
let disconnected = !GlobalModel.ws.open.get() || !GlobalModel.waveSrvRunning.get();
let hasClientStop = GlobalModel.getHasClientStop();
-5
View File
@@ -7,12 +7,7 @@ export const SCREEN_SETTINGS = "screenSettings";
export const SESSION_SETTINGS = "sessionSettings";
export const LINE_SETTINGS = "lineSettings";
export const CLIENT_SETTINGS = "clientSettings";
export const TAB_SWITCHER = "tabSwitcher";
export const LineContainer_Main = "main";
export const LineContainer_History = "history";
export const LineContainer_Sidebar = "sidebar";
export const ConfirmKey_HideShellPrompt = "hideshellprompt";
export const NoStrPos = -1;
+7 -18
View File
@@ -188,14 +188,14 @@
position: relative;
display: flex;
align-items: center;
color: @term-bright-white;
color: #9e9e9e;
transition: color 250ms cubic-bezier(0.4, 0, 0.23, 1);
}
input[type="checkbox"] + label > span {
display: flex;
justify-content: center;
align-items: center;
margin-right: 10px;
margin-right: 16px;
width: 20px;
height: 20px;
background: transparent;
@@ -205,6 +205,10 @@
transition: all 250ms cubic-bezier(0.4, 0, 0.23, 1);
}
input[type="checkbox"] + label:hover,
input[type="checkbox"]:focus + label {
color: #fff;
}
input[type="checkbox"] + label:hover > span,
input[type="checkbox"]:focus + label > span {
background: rgba(255, 255, 255, 0.1);
@@ -352,7 +356,7 @@
background-color: @markdown-highlight;
color: @term-white;
font-family: @terminal-font;
border-radius: 4px;
display: inline-block;
}
code.inline {
@@ -403,13 +407,6 @@
background-color: @markdown-highlight;
margin: 4px 10px 4px 10px;
padding: 6px 6px 6px 10px;
border-radius: 4px;
}
pre.selected {
border-style: solid;
outline-width: 2px;
border-color: @term-green;
}
.title.is-1 {
@@ -840,14 +837,6 @@
}
}
}
&.no-label {
height: 34px;
input {
height: 32px;
}
}
}
.wave-input-decoration {
+37 -138
View File
@@ -11,7 +11,6 @@ import cn from "classnames";
import { If } from "tsx-control-statements/components";
import type { RemoteType } from "../../types/types";
import ReactDOM from "react-dom";
import { GlobalModel } from "../../model/model";
import { ReactComponent as CheckIcon } from "../assets/icons/line/check.svg";
import { ReactComponent as CopyIcon } from "../assets/icons/history/copy.svg";
@@ -100,57 +99,23 @@ class Toggle extends React.Component<{ checked: boolean; onChange: (value: boole
}
class Checkbox extends React.Component<
{
checked?: boolean;
defaultChecked?: boolean;
onChange: (value: boolean) => void;
label: React.ReactNode;
className?: string;
id?: string;
},
{ checkedInternal: boolean }
{ checked: boolean; onChange: (value: boolean) => void; label: React.ReactNode; id: string },
{}
> {
generatedId;
static idCounter = 0;
constructor(props) {
super(props);
this.state = {
checkedInternal: this.props.checked !== undefined ? this.props.checked : Boolean(this.props.defaultChecked),
};
this.generatedId = `checkbox-${Checkbox.idCounter++}`;
}
componentDidUpdate(prevProps) {
if (this.props.checked !== undefined && this.props.checked !== prevProps.checked) {
this.setState({ checkedInternal: this.props.checked });
}
}
handleChange = (e) => {
const newChecked = e.target.checked;
if (this.props.checked === undefined) {
this.setState({ checkedInternal: newChecked });
}
this.props.onChange(newChecked);
};
render() {
const { label, className, id } = this.props;
const { checkedInternal } = this.state;
const checkboxId = id || this.generatedId;
const { checked, onChange, label, id } = this.props;
return (
<div className={cn("checkbox", className)}>
<div className="checkbox">
<input
type="checkbox"
id={checkboxId}
checked={checkedInternal}
onChange={this.handleChange}
aria-checked={checkedInternal}
id={id}
checked={checked}
onChange={(e) => onChange(e.target.checked)}
aria-checked={checked}
role="checkbox"
/>
<label htmlFor={checkboxId}>
<label htmlFor={id}>
<span></span>
{label}
</label>
@@ -266,8 +231,6 @@ interface ButtonProps {
rightIcon?: React.ReactNode;
color?: string;
style?: React.CSSProperties;
autoFocus?: boolean;
className?: string;
}
class Button extends React.Component<ButtonProps> {
@@ -294,7 +257,6 @@ class Button extends React.Component<ButtonProps> {
onClick={this.handleClick}
disabled={disabled}
style={style}
autoFocus={this.props.autoFocus}
>
{leftIcon && <span className="icon-left">{leftIcon}</span>}
{children}
@@ -321,24 +283,25 @@ export default IconButton;
interface LinkButtonProps extends ButtonProps {
href: string;
rel?: string;
target?: string;
}
class LinkButton extends React.Component<LinkButtonProps> {
class LinkButton extends IconButton {
render() {
const { leftIcon, rightIcon, children, className, ...rest } = this.props;
// @ts-ignore
const { href, target, leftIcon, rightIcon, children, theme, variant }: LinkButtonProps = this.props;
return (
<a {...rest} className={cn(`wave-button link-button`, className)}>
{leftIcon && <span className="icon-left">{leftIcon}</span>}
{children}
{rightIcon && <span className="icon-right">{rightIcon}</span>}
<a href={href} target={target} className={`wave-button link-button`}>
<button {...this.props} className={`icon-button ${theme} ${variant}`}>
{leftIcon && <span className="icon-left">{leftIcon}</span>}
{children}
{rightIcon && <span className="icon-right">{rightIcon}</span>}
</button>
</a>
);
}
}
interface StatusProps {
status: "green" | "red" | "gray" | "yellow";
text: string;
@@ -369,7 +332,7 @@ interface TextFieldDecorationProps {
endDecoration?: React.ReactNode;
}
interface TextFieldProps {
label?: string;
label: string;
value?: string;
className?: string;
onChange?: (value: string) => void;
@@ -482,11 +445,10 @@ class TextField extends React.Component<TextFieldProps, TextFieldState> {
return (
<div
className={cn("wave-textfield", className, {
className={cn(`wave-textfield ${className || ""}`, {
focused: focused,
error: error,
disabled: disabled,
"no-label": !label,
})}
onFocus={this.handleComponentFocus}
onBlur={this.handleComponentBlur}
@@ -494,17 +456,15 @@ class TextField extends React.Component<TextFieldProps, TextFieldState> {
>
{decoration?.startDecoration && <>{decoration.startDecoration}</>}
<div className="wave-textfield-inner">
<If condition={label}>
<label
className={cn("wave-textfield-inner-label", {
float: this.state.hasContent || this.state.focused || placeholder,
"offset-left": decoration?.startDecoration,
})}
htmlFor={label}
>
{label}
</label>
</If>
<label
className={cn("wave-textfield-inner-label", {
float: this.state.hasContent || this.state.focused || placeholder,
"offset-left": decoration?.startDecoration,
})}
htmlFor={label}
>
{label}
</label>
<input
className={cn("wave-textfield-inner-input", { "offset-left": decoration?.startDecoration })}
ref={this.inputRef}
@@ -814,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" rel={"noopener"}>
<a href={newUrl} target="_blank" rel={"noopener"}>
{props.children}
</a>
);
@@ -829,67 +789,9 @@ function CodeRenderer(props: any): any {
}
@mobxReact.observer
class CodeBlockMarkdown extends React.Component<
{ children: React.ReactNode; blockText: string; codeSelectSelectedIndex?: number },
{}
> {
blockIndex: number;
blockRef: React.RefObject<HTMLPreElement>;
constructor(props) {
super(props);
this.blockRef = React.createRef();
this.blockIndex = GlobalModel.inputModel.addCodeBlockToCodeSelect(this.blockRef);
}
render() {
let codeText = this.props.blockText;
let clickHandler: (e: React.MouseEvent<HTMLElement>, blockIndex: number) => void;
let inputModel = GlobalModel.inputModel;
clickHandler = (e: React.MouseEvent<HTMLElement>, blockIndex: number) => {
inputModel.setCodeSelectSelectedCodeBlock(blockIndex);
};
let selected = this.blockIndex == this.props.codeSelectSelectedIndex;
return (
<pre
ref={this.blockRef}
className={cn({ selected: selected })}
onClick={(event) => clickHandler(event, this.blockIndex)}
>
{this.props.children}
</pre>
);
}
}
@mobxReact.observer
class Markdown extends React.Component<
{ text: string; style?: any; extraClassName?: string; codeSelect?: boolean },
{}
> {
CodeBlockRenderer(props: any, codeSelect: boolean, codeSelectIndex: number): any {
let codeText = codeSelect ? props.node.children[0].children[0].value : props.children;
if (codeText) {
codeText = codeText.replace(/\n$/, ""); // remove trailing newline
}
if (codeSelect) {
return (
<CodeBlockMarkdown blockText={codeText} codeSelectSelectedIndex={codeSelectIndex}>
{props.children}
</CodeBlockMarkdown>
);
} else {
let clickHandler = (e: React.MouseEvent<HTMLElement>) => {
navigator.clipboard.writeText(codeText);
};
return <pre onClick={(event) => clickHandler(event)}>{props.children}</pre>;
}
}
class Markdown extends React.Component<{ text: string; style?: any; extraClassName?: string }, {}> {
render() {
let text = this.props.text;
let codeSelect = this.props.codeSelect;
let curCodeSelectIndex = GlobalModel.inputModel.getCodeSelectSelectedIndex();
let markdownComponents = {
a: LinkRenderer,
h1: (props) => HeaderRenderer(props, 1),
@@ -898,8 +800,7 @@ class Markdown extends React.Component<
h4: (props) => HeaderRenderer(props, 4),
h5: (props) => HeaderRenderer(props, 5),
h6: (props) => HeaderRenderer(props, 6),
code: (props) => CodeRenderer(props),
pre: (props) => this.CodeBlockRenderer(props, codeSelect, curCodeSelectIndex),
code: CodeRenderer,
};
return (
<div className={cn("markdown content", this.props.extraClassName)} style={this.props.style}>
@@ -1181,18 +1082,16 @@ class Dropdown extends React.Component<DropdownProps, DropdownState> {
}
interface ModalHeaderProps {
onClose?: () => void;
onClose: () => void;
title: string;
}
const ModalHeader: React.FC<ModalHeaderProps> = ({ onClose, title }) => (
<div className="wave-modal-header">
{<div className="wave-modal-title">{title}</div>}
<If condition={onClose}>
<IconButton theme="secondary" variant="ghost" onClick={onClose}>
<i className="fa-sharp fa-solid fa-xmark"></i>
</IconButton>
</If>
<IconButton theme="secondary" variant="ghost" onClick={onClose}>
<i className="fa-sharp fa-solid fa-xmark"></i>
</IconButton>
</div>
);
@@ -1242,7 +1141,7 @@ class Modal extends React.Component<ModalProps> {
}
render() {
return ReactDOM.createPortal(this.renderModal(), document.getElementById("app"));
return ReactDOM.createPortal(this.renderModal(), document.getElementById("app") );
}
}
-114
View File
@@ -1,114 +0,0 @@
@import "../../../app/common/themes/themes.less";
.about-modal {
.wave-modal-content {
gap: 24px;
.wave-modal-body {
margin-bottom: 0;
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 24px;
.about-section {
display: flex;
align-items: center;
gap: 16px;
align-self: stretch;
width: 100%;
.logo-wrapper {
width: 72px;
height: 72px;
flex-shrink: 0;
img {
border-radius: 10px;
}
}
.text-wrapper {
display: flex;
align-items: flex-start;
flex-direction: column;
gap: 4px;
align-self: stretch;
font-style: normal;
line-height: 20px;
div:first-child {
color: @term-bright-white;
font-size: 14.5px;
}
div:last-child {
color: @term-white;
text-align: left;
}
}
.status {
div {
display: flex;
align-items: center;
margin-bottom: 5px;
i {
font-size: 16px;
margin-right: 10px;
}
}
div:first-child + div {
color: @term-white;
}
}
.status.updated {
div {
display: flex;
align-items: center;
margin-bottom: 5px;
i {
color: @term-green;
}
}
}
.status.outdated {
div {
i {
color: @term-yellow;
}
}
button {
margin-top: 5px;
}
}
}
.about-section:nth-child(3) {
display: flex;
align-items: flex-start;
gap: 10px;
.wave-button-link {
display: flex;
align-items: center;
i {
font-size: 16px;
}
}
}
.about-section:last-child {
margin-bottom: 24px;
color: @term-white;
}
}
}
}
-136
View File
@@ -1,136 +0,0 @@
// Copyright 2023, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import * as React from "react";
import * as mobxReact from "mobx-react";
import * as mobx from "mobx";
import { boundMethod } from "autobind-decorator";
import { GlobalModel } from "../../../model/model";
import { Modal, LinkButton } from "../common";
import * as util from "../../../util/util";
import logo from "../../assets/waveterm-logo-with-bg.svg";
import "./about.less";
// @ts-ignore
const VERSION = __WAVETERM_VERSION__;
// @ts-ignore
let BUILD = __WAVETERM_BUILD__;
@mobxReact.observer
class AboutModal extends React.Component<{}, {}> {
@boundMethod
closeModal(): void {
mobx.action(() => {
GlobalModel.modalsModel.popModal();
})();
}
@boundMethod
isUpToDate(): boolean {
return true;
}
@boundMethod
updateApp(): void {
// GlobalCommandRunner.updateApp();
}
@boundMethod
getStatus(isUpToDate: boolean): JSX.Element {
// TODO no up-to-date status reporting
return (
<div className="status updated">
<div className="text-selectable">
Client Version {VERSION} ({BUILD})
</div>
</div>
);
if (isUpToDate) {
return (
<div className="status updated">
<div>
<i className="fa-sharp fa-solid fa-circle-check" />
<span>Up to Date</span>
</div>
<div className="selectable">
Client Version {VERSION} ({BUILD})
</div>
</div>
);
}
return (
<div className="status outdated">
<div>
<i className="fa-sharp fa-solid fa-triangle-exclamation" />
<span>Outdated Version</span>
</div>
<div className="selectable">
Client Version {VERSION} ({BUILD})
</div>
<div>
<button onClick={this.updateApp} className="button color-green text-secondary">
Update
</button>
</div>
</div>
);
}
render() {
return (
<Modal className="about-modal">
<Modal.Header onClose={this.closeModal} title="About" />
<div className="wave-modal-body">
<div className="about-section">
<div className="logo-wrapper">
<img src={logo} alt="logo" />
</div>
<div className="text-wrapper">
<div>Wave Terminal</div>
<div className="text-standard">
Modern Terminal for
<br />
Seamless Workflow
</div>
</div>
</div>
<div className="about-section text-standard">{this.getStatus(this.isUpToDate())}</div>
<div className="about-section">
<LinkButton
className="secondary solid"
href={util.makeExternLink("https://github.com/wavetermdev/waveterm")}
target="_blank"
leftIcon={<i className="fa-brands fa-github"></i>}
>
Github
</LinkButton>
<LinkButton
className="secondary solid"
href={util.makeExternLink("https://www.waveterm.dev/")}
target="_blank"
leftIcon={<i className="fa-sharp fa-light fa-globe"></i>}
>
Website
</LinkButton>
<LinkButton
className="secondary solid"
href={util.makeExternLink(
"https://github.com/wavetermdev/waveterm/blob/main/acknowledgements/README.md"
)}
target="_blank"
rel={"noopener"}
leftIcon={<i className="fa-sharp fa-light fa-heart"></i>}
>
Acknowledgements
</LinkButton>
</div>
<div className="about-section text-standard">&copy; 2023 Command Line Inc.</div>
</div>
</Modal>
);
}
}
export { AboutModal };
-11
View File
@@ -1,11 +0,0 @@
@import "../../../app/common/themes/themes.less";
.alert-modal {
width: 500px;
.wave-modal-content {
.wave-modal-body {
padding: 40px 20px;
}
}
}
-75
View File
@@ -1,75 +0,0 @@
// Copyright 2023, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import * as React from "react";
import * as mobxReact from "mobx-react";
import { boundMethod } from "autobind-decorator";
import { If } from "tsx-control-statements/components";
import { Markdown, Modal, Button, Checkbox } from "../common";
import { GlobalModel, GlobalCommandRunner } from "../../../model/model";
import "./alert.less";
@mobxReact.observer
class AlertModal extends React.Component<{}, {}> {
@boundMethod
closeModal(): void {
GlobalModel.cancelAlert();
}
@boundMethod
handleOK(): void {
GlobalModel.confirmAlert();
}
@boundMethod
handleDontShowAgain(checked: boolean) {
let message = GlobalModel.alertMessage.get();
if (message.confirmflag == null) {
return;
}
GlobalCommandRunner.clientSetConfirmFlag(message.confirmflag, checked);
}
render() {
let message = GlobalModel.alertMessage.get();
let title = message?.title ?? (message?.confirm ? "Confirm" : "Alert");
let isConfirm = message?.confirm ?? false;
return (
<Modal className="alert-modal">
<Modal.Header onClose={this.closeModal} title={title} />
<div className="wave-modal-body">
<If condition={message?.markdown}>
<Markdown text={message?.message ?? ""} />
</If>
<If condition={!message?.markdown}>{message?.message}</If>
<If condition={message.confirmflag}>
<Checkbox
onChange={this.handleDontShowAgain}
label={"Don't show me this again"}
className="dontshowagain-text"
/>
</If>
</div>
<div className="wave-modal-footer">
<If condition={isConfirm}>
<Button theme="secondary" onClick={this.closeModal}>
Cancel
</Button>
<Button autoFocus={true} onClick={this.handleOK}>
Ok
</Button>
</If>
<If condition={!isConfirm}>
<Button autoFocus={true} onClick={this.handleOK}>
Ok
</Button>
</If>
</div>
</Modal>
);
}
}
export { AlertModal };
-11
View File
@@ -1,11 +0,0 @@
@import "../../../app/common/themes/themes.less";
.clientstop-modal {
.inner-content {
display: flex;
flex-direction: column;
padding: 30px;
gap: 20px;
align-items: center;
}
}

Some files were not shown because too many files have changed in this diff Show More