feat(sheets): add undo shortcut

This commit is contained in:
zhengzhijie
2026-07-02 13:43:45 +08:00
parent 0fbdb83f27
commit 8d8271b552
5 changed files with 107 additions and 42 deletions

View File

@@ -80,32 +80,6 @@
}
]
},
"+revision-get": {
"risk": "read",
"flags": [
{
"name": "url",
"kind": "public",
"type": "string",
"required": "xor",
"desc": "Spreadsheet locator"
},
{
"name": "spreadsheet-token",
"kind": "public",
"type": "string",
"required": "xor",
"desc": "Spreadsheet locator"
},
{
"name": "dry-run",
"kind": "system",
"type": "bool",
"required": "optional",
"desc": ""
}
]
},
"+sheet-create": {
"risk": "write",
"flags": [
@@ -4950,37 +4924,29 @@
}
]
},
"+changeset-get": {
"risk": "read",
"+undo": {
"risk": "write",
"flags": [
{
"name": "url",
"kind": "public",
"type": "string",
"required": "xor",
"desc": "Spreadsheet URL (XOR with `--spreadsheet-token`)"
"desc": "Spreadsheet locator"
},
{
"name": "spreadsheet-token",
"kind": "public",
"type": "string",
"required": "xor",
"desc": "Spreadsheet token (XOR with `--url`)"
"desc": "Spreadsheet locator"
},
{
"name": "start-revision",
"kind": "own",
"type": "int",
"required": "required",
"desc": "Start version (CS revision); the before baseline for review (must be >= 1)"
},
{
"name": "end-revision",
"kind": "own",
"type": "int",
"name": "dry-run",
"kind": "system",
"type": "bool",
"required": "optional",
"desc": "End version (CS revision); defaults to the latest revision. Gap (end-start+1) must be <= 20",
"default": "-1"
"desc": ""
}
]
}

View File

@@ -995,6 +995,14 @@ var flagDefs = map[string]commandDef{
{Name: "dry-run", Kind: "system", Type: "bool", Required: "optional"},
},
},
"+undo": {
Risk: "write",
Flags: []flagDef{
{Name: "url", Kind: "public", Type: "string", Required: "xor", Desc: "Spreadsheet locator"},
{Name: "spreadsheet-token", Kind: "public", Type: "string", Required: "xor", Desc: "Spreadsheet locator"},
{Name: "dry-run", Kind: "system", Type: "bool", Required: "optional"},
},
},
"+workbook-create": {
Risk: "write",
Flags: []flagDef{

View File

@@ -0,0 +1,47 @@
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
// SPDX-License-Identifier: MIT
package sheets
import (
"context"
"github.com/larksuite/cli/shortcuts/common"
)
var Undo = common.Shortcut{
Service: "sheets",
Command: "+undo",
Description: "Undo the current user's latest spreadsheet write.",
Risk: "write",
Scopes: []string{"sheets:spreadsheet:write_only"},
AuthTypes: []string{"user"},
HasFormat: true,
Flags: historyLocatorFlags(),
Validate: func(ctx context.Context, runtime *common.RuntimeContext) error {
_, err := resolveSpreadsheetToken(runtime)
return err
},
DryRun: func(ctx context.Context, runtime *common.RuntimeContext) *common.DryRunAPI {
token, _ := resolveSpreadsheetToken(runtime)
return invokeToolDryRun(token, ToolKindWrite, "undo_last", undoInput(token))
},
Execute: func(ctx context.Context, runtime *common.RuntimeContext) error {
token, err := resolveSpreadsheetTokenExec(runtime)
if err != nil {
return err
}
out, err := callTool(ctx, runtime, token, ToolKindWrite, "undo_last", undoInput(token))
if err != nil {
return err
}
runtime.Out(out, nil)
return nil
},
}
func undoInput(token string) map[string]interface{} {
return map[string]interface{}{
"excel_id": token,
}
}

View File

@@ -0,0 +1,43 @@
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
// SPDX-License-Identifier: MIT
package sheets
import "testing"
func TestUndo_DryRun(t *testing.T) {
t.Parallel()
args := []string{"--url", testURL, "--as", "user"}
callURL := dryRunFirstCallURL(t, Undo, args)
if !containsSuffix(callURL, "invoke_write") {
t.Errorf("invoke url = %q, want invoke_write", callURL)
}
body := parseDryRunBody(t, Undo, args)
got := decodeToolInput(t, body, "undo_last")
assertInputEquals(t, got, map[string]interface{}{
"excel_id": testToken,
})
}
func TestExecute_Undo(t *testing.T) {
t.Parallel()
stub := toolOutputStub(testToken, "write", `{"undone":1,"op_id":"op-1","top_doc_revision":2,"new_revision":3}`)
out, err := runShortcutWithStubs(t, Undo, []string{"--url", testURL, "--as", "user"}, stub)
if err != nil {
t.Fatalf("execute failed: %v\nout=%s", err, out)
}
body := decodeRawEnvelopeBody(t, stub.CapturedBody)
input := decodeToolInput(t, body, "undo_last")
assertInputEquals(t, input, map[string]interface{}{
"excel_id": testToken,
})
data := decodeEnvelopeData(t, out)
if data["undone"].(float64) != 1 || data["op_id"] != "op-1" {
t.Fatalf("unexpected output data: %#v", data)
}
}

View File

@@ -160,5 +160,6 @@ func shortcutList() []common.Shortcut {
HistoryList,
HistoryRevert,
HistoryRevertStatus,
Undo,
}
}