From 8ac1943d5625dba4802809b8871f29b605c78061 Mon Sep 17 00:00:00 2001 From: Mike Sawka Date: Mon, 8 Jan 2024 22:58:32 -0800 Subject: [PATCH] Add Icon / HotKey to Delete Line (Cmd-D) (#214) * work on cmd-d to delete a selected line * call stoppropagation when code.tsx captures keyboard input * finish up with line delete. add a trash icon to line. prevent delete when cmd is running (show error msg) --- src/app/common/modals/modals.less | 4 ++++ src/app/common/modals/settings.tsx | 17 ++++++++------ src/app/line/linecomps.tsx | 9 ++++++++ src/model/model.ts | 37 +++++++++++++++++++++++++++++- src/plugins/code/code.tsx | 16 ++++++++----- wavesrv/pkg/cmdrunner/cmdrunner.go | 7 +++++- wavesrv/pkg/sstore/dbops.go | 27 +++++++++++++++++++--- 7 files changed, 99 insertions(+), 18 deletions(-) diff --git a/src/app/common/modals/modals.less b/src/app/common/modals/modals.less index 7a874418..3dcf8e4a 100644 --- a/src/app/common/modals/modals.less +++ b/src/app/common/modals/modals.less @@ -596,6 +596,10 @@ gap: 4px; align-self: stretch; width: 100%; + + .settings-input .hotkey { + color: @text-secondary; + } } } } diff --git a/src/app/common/modals/settings.tsx b/src/app/common/modals/settings.tsx index bceca6cd..e02117eb 100644 --- a/src/app/common/modals/settings.tsx +++ b/src/app/common/modals/settings.tsx @@ -17,7 +17,16 @@ import { Screen, Session, } from "../../../model/model"; -import { Toggle, InlineSettingsTextEdit, SettingsError, InfoMessage, Modal, Dropdown, Tooltip } from "../common"; +import { + Toggle, + InlineSettingsTextEdit, + SettingsError, + InfoMessage, + Modal, + Dropdown, + Tooltip, + Button, +} from "../common"; import { LineType, RendererPluginType, ClientDataType, CommandRtnType, RemoteType } from "../../../types/types"; import { PluginModel } from "../../../plugins/plugins"; import * as util from "../../../util/util"; @@ -632,12 +641,6 @@ class LineSettingsModal extends React.Component<{}, {}> { /> -
-
Archived
-
- -
-
diff --git a/src/app/line/linecomps.tsx b/src/app/line/linecomps.tsx index e0732f17..5cd1b618 100644 --- a/src/app/line/linecomps.tsx +++ b/src/app/line/linecomps.tsx @@ -354,6 +354,12 @@ class LineCmd extends React.Component< GlobalCommandRunner.lineBookmark(line.lineid); } + @boundMethod + clickDelete() { + let { line } = this.props; + GlobalCommandRunner.lineDelete(line.lineid, true); + } + @boundMethod clickMinimize() { mobx.action(() => { @@ -659,6 +665,9 @@ class LineCmd extends React.Component< {this.renderMeta1(cmd)} {this.renderCmdText(cmd)} +
+ +
{ + return GlobalModel.submitCommand("line", "delete", [lineArg], { nohist: "1" }, interactive); + } + lineSet(lineArg: string, opts: { renderer?: string }): Promise { let kwargs = { nohist: "1" }; if ("renderer" in opts) { diff --git a/src/plugins/code/code.tsx b/src/plugins/code/code.tsx index 24fc305c..172bb45d 100644 --- a/src/plugins/code/code.tsx +++ b/src/plugins/code/code.tsx @@ -3,7 +3,8 @@ import * as React from "react"; import * as T from "../../types/types"; -import Editor from "@monaco-editor/react"; +import Editor, { Monaco } from "@monaco-editor/react"; +import type * as MonacoTypes from "monaco-editor/esm/vs/editor/editor.api"; import { Markdown } from "../../app/common/common"; import { GlobalModel, GlobalCommandRunner } from "../../model/model"; import Split from "react-split-it"; @@ -146,21 +147,24 @@ class SourceCodeRenderer extends React.Component< } }; - handleEditorDidMount = (editor, monaco) => { + handleEditorDidMount = (editor: MonacoTypes.editor.IStandaloneCodeEditor, monaco: Monaco) => { this.monacoEditor = editor; this.setInitialLanguage(editor); this.setEditorHeight(); - editor.onKeyDown((e) => { - if (e.code === "KeyS" && (e.ctrlKey || e.metaKey) && this.state.isSave) { + editor.onKeyDown((e: MonacoTypes.IKeyboardEvent) => { + if (e.code === "KeyS" && e.metaKey && this.state.isSave) { e.preventDefault(); + e.stopPropagation(); this.doSave(); } - if (e.code === "KeyD" && (e.ctrlKey || e.metaKey)) { + if (e.code === "KeyD" && e.metaKey) { e.preventDefault(); + e.stopPropagation(); this.doClose(); } - if (e.code === "KeyP" && (e.ctrlKey || e.metaKey)) { + if (e.code === "KeyP" && e.metaKey) { e.preventDefault(); + e.stopPropagation(); this.togglePreview(); } }); diff --git a/wavesrv/pkg/cmdrunner/cmdrunner.go b/wavesrv/pkg/cmdrunner/cmdrunner.go index d0af9581..7ce5f543 100644 --- a/wavesrv/pkg/cmdrunner/cmdrunner.go +++ b/wavesrv/pkg/cmdrunner/cmdrunner.go @@ -3440,7 +3440,7 @@ func LineDeleteCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (s } err = sstore.DeleteLinesByIds(ctx, ids.ScreenId, lineIds) if err != nil { - return nil, fmt.Errorf("/line:delete error purging lines: %v", err) + return nil, fmt.Errorf("/line:delete error deleting lines: %v", err) } update := &sstore.ModelUpdate{} for _, lineId := range lineIds { @@ -3451,6 +3451,11 @@ func LineDeleteCommand(ctx context.Context, pk *scpacket.FeCommandPacketType) (s } update.Lines = append(update.Lines, lineObj) } + screen, err := sstore.FixupScreenSelectedLine(ctx, ids.ScreenId) + if err != nil { + return nil, fmt.Errorf("/line:delete error fixing up screen: %v", err) + } + update.Screens = []*sstore.ScreenType{screen} return update, nil } diff --git a/wavesrv/pkg/sstore/dbops.go b/wavesrv/pkg/sstore/dbops.go index 1f0dbd42..d2653cca 100644 --- a/wavesrv/pkg/sstore/dbops.go +++ b/wavesrv/pkg/sstore/dbops.go @@ -2039,6 +2039,29 @@ func SetLineArchivedById(ctx context.Context, screenId string, lineId string, ar return txErr } +// returns updated screen (only if updated) +func FixupScreenSelectedLine(ctx context.Context, screenId string) (*ScreenType, error) { + return WithTxRtn(ctx, func(tx *TxWrap) (*ScreenType, error) { + query := `SELECT selectedline FROM screen WHERE screenid = ?` + sline := tx.GetInt(query, screenId) + query = `SELECT linenum FROM line WHERE screenid = ? AND linenum = ?` + if tx.Exists(query, screenId, sline) { + // selected line is valid + return nil, nil + } + query = `SELECT min(linenum) FROM line WHERE screenid = ? AND linenum > ?` + newSLine := tx.GetInt(query, screenId, sline) + if newSLine == 0 { + query = `SELECT max(linenum) FROM line WHERE screenid = ? AND linenum < ?` + newSLine = tx.GetInt(query, screenId, sline) + } + // newSLine might be 0, but that's ok (because that means there are no lines) + query = `UPDATE screen SET selectedline = ? WHERE screenid = ?` + tx.Exec(query, newSLine, screenId) + return GetScreenById(tx.Context(), screenId) + }) +} + func DeleteLinesByIds(ctx context.Context, screenId string, lineIds []string) error { txErr := WithTx(ctx, func(tx *TxWrap) error { isWS := isWebShare(tx, screenId) @@ -2046,9 +2069,8 @@ func DeleteLinesByIds(ctx context.Context, screenId string, lineIds []string) er query := `SELECT status FROM cmd WHERE screenid = ? AND lineid = ?` cmdStatus := tx.GetString(query, screenId, lineId) if cmdStatus == CmdStatusRunning { - return fmt.Errorf("cannot delete line[%s:%s], cmd is running", screenId, lineId) + return fmt.Errorf("cannot delete line[%s], cmd is running", lineId) } - query = `DELETE FROM line WHERE screenid = ? AND lineid = ?` tx.Exec(query, screenId, lineId) query = `DELETE FROM cmd WHERE screenid = ? AND lineid = ?` @@ -2056,7 +2078,6 @@ func DeleteLinesByIds(ctx context.Context, screenId string, lineIds []string) er // don't delete history anymore, just remove lineid reference query = `UPDATE history SET lineid = '', linenum = 0 WHERE screenid = ? AND lineid = ?` tx.Exec(query, screenId, lineId) - if isWS { insertScreenLineUpdate(tx, screenId, lineId, UpdateType_LineDel) }