mirror of
https://github.com/wavetermdev/waveterm.git
synced 2024-12-21 16:38:23 +01:00
implement history functions for preview
This commit is contained in:
parent
9a06b43266
commit
e70e08e531
@ -34,7 +34,6 @@ interface DirectoryTableProps {
|
||||
search: string;
|
||||
focusIndex: number;
|
||||
setFocusIndex: (_: number) => void;
|
||||
setFileName: (_: string) => void;
|
||||
setSearch: (_: string) => void;
|
||||
setSelectedPath: (_: string) => void;
|
||||
setRefreshVersion: React.Dispatch<React.SetStateAction<number>>;
|
||||
@ -130,7 +129,6 @@ function DirectoryTable({
|
||||
search,
|
||||
focusIndex,
|
||||
setFocusIndex,
|
||||
setFileName,
|
||||
setSearch,
|
||||
setSelectedPath,
|
||||
setRefreshVersion,
|
||||
@ -301,7 +299,6 @@ function DirectoryTable({
|
||||
table={table}
|
||||
search={search}
|
||||
focusIndex={focusIndex}
|
||||
setFileName={setFileName}
|
||||
setFocusIndex={setFocusIndex}
|
||||
setSearch={setSearch}
|
||||
setSelectedPath={setSelectedPath}
|
||||
@ -314,7 +311,6 @@ function DirectoryTable({
|
||||
table={table}
|
||||
search={search}
|
||||
focusIndex={focusIndex}
|
||||
setFileName={setFileName}
|
||||
setFocusIndex={setFocusIndex}
|
||||
setSearch={setSearch}
|
||||
setSelectedPath={setSelectedPath}
|
||||
@ -332,7 +328,6 @@ interface TableBodyProps {
|
||||
search: string;
|
||||
focusIndex: number;
|
||||
setFocusIndex: (_: number) => void;
|
||||
setFileName: (_: string) => void;
|
||||
setSearch: (_: string) => void;
|
||||
setSelectedPath: (_: string) => void;
|
||||
setRefreshVersion: React.Dispatch<React.SetStateAction<number>>;
|
||||
@ -345,7 +340,6 @@ function TableBody({
|
||||
search,
|
||||
focusIndex,
|
||||
setFocusIndex,
|
||||
setFileName,
|
||||
setSearch,
|
||||
setSelectedPath,
|
||||
setRefreshVersion,
|
||||
@ -478,7 +472,7 @@ function TableBody({
|
||||
key={row.id}
|
||||
onDoubleClick={() => {
|
||||
const newFileName = row.getValue("path") as string;
|
||||
setFileName(newFileName);
|
||||
model.goHistory(newFileName);
|
||||
setSearch("");
|
||||
}}
|
||||
onClick={() => setFocusIndex(idx)}
|
||||
@ -495,7 +489,7 @@ function TableBody({
|
||||
))}
|
||||
</div>
|
||||
),
|
||||
[setSearch, setFileName, handleFileContextMenu, setFocusIndex, focusIndex]
|
||||
[setSearch, handleFileContextMenu, setFocusIndex, focusIndex]
|
||||
);
|
||||
|
||||
const handleScrollbarInitialized = (instance) => {
|
||||
@ -535,7 +529,7 @@ const MemoizedTableBody = React.memo(
|
||||
) as typeof TableBody;
|
||||
|
||||
interface DirectoryPreviewProps {
|
||||
fileNameAtom: jotai.WritableAtom<string, [string], void>;
|
||||
fileNameAtom: jotai.Atom<string>;
|
||||
model: PreviewModel;
|
||||
}
|
||||
|
||||
@ -544,7 +538,7 @@ function DirectoryPreview({ fileNameAtom, model }: DirectoryPreviewProps) {
|
||||
const [focusIndex, setFocusIndex] = useState(0);
|
||||
const [unfilteredData, setUnfilteredData] = useState<FileInfo[]>([]);
|
||||
const [filteredData, setFilteredData] = useState<FileInfo[]>([]);
|
||||
const [fileName, setFileName] = jotai.useAtom(fileNameAtom);
|
||||
const fileName = jotai.useAtomValue(fileNameAtom);
|
||||
const showHiddenFiles = jotai.useAtomValue(model.showHiddenFiles);
|
||||
const [selectedPath, setSelectedPath] = useState("");
|
||||
const [refreshVersion, setRefreshVersion] = jotai.useAtom(model.refreshVersion);
|
||||
@ -597,7 +591,7 @@ function DirectoryPreview({ fileNameAtom, model }: DirectoryPreviewProps) {
|
||||
if (filteredData.length == 0) {
|
||||
return;
|
||||
}
|
||||
setFileName(selectedPath);
|
||||
model.goHistory(selectedPath);
|
||||
setSearchText("");
|
||||
return true;
|
||||
}
|
||||
@ -645,7 +639,6 @@ function DirectoryPreview({ fileNameAtom, model }: DirectoryPreviewProps) {
|
||||
data={filteredData}
|
||||
search={searchText}
|
||||
focusIndex={focusIndex}
|
||||
setFileName={setFileName}
|
||||
setFocusIndex={setFocusIndex}
|
||||
setSearch={setSearchText}
|
||||
setSelectedPath={setSelectedPath}
|
||||
|
@ -7,6 +7,8 @@ import { createBlock, globalStore, useBlockAtom } from "@/store/global";
|
||||
import * as services from "@/store/services";
|
||||
import * as WOS from "@/store/wos";
|
||||
import { getWebServerEndpoint } from "@/util/endpoints";
|
||||
import * as historyutil from "@/util/historyutil";
|
||||
import * as keyutil from "@/util/keyutil";
|
||||
import * as util from "@/util/util";
|
||||
import clsx from "clsx";
|
||||
import * as jotai from "jotai";
|
||||
@ -43,7 +45,7 @@ export class PreviewModel implements ViewModel {
|
||||
ceReadOnly: jotai.PrimitiveAtom<boolean>;
|
||||
isCeView: jotai.PrimitiveAtom<boolean>;
|
||||
|
||||
fileName: jotai.WritableAtom<string, [string], void>;
|
||||
fileName: jotai.Atom<string>;
|
||||
connection: jotai.Atom<string>;
|
||||
statFile: jotai.Atom<Promise<FileInfo>>;
|
||||
fullFile: jotai.Atom<Promise<FullFile>>;
|
||||
@ -80,20 +82,26 @@ export class PreviewModel implements ViewModel {
|
||||
icon: "folder-open",
|
||||
longClick: (e: React.MouseEvent<any>) => {
|
||||
let menuItems: ContextMenuItem[] = [];
|
||||
menuItems.push({ label: "Go to Home", click: () => globalStore.set(this.fileName, "~") });
|
||||
menuItems.push({
|
||||
label: "Go to Home",
|
||||
click: () => this.goHistory("~"),
|
||||
});
|
||||
menuItems.push({
|
||||
label: "Go to Desktop",
|
||||
click: () => globalStore.set(this.fileName, "~/Desktop"),
|
||||
click: () => this.goHistory("~/Desktop"),
|
||||
});
|
||||
menuItems.push({
|
||||
label: "Go to Downloads",
|
||||
click: () => globalStore.set(this.fileName, "~/Downloads"),
|
||||
click: () => this.goHistory("~/Downloads"),
|
||||
});
|
||||
menuItems.push({
|
||||
label: "Go to Documents",
|
||||
click: () => globalStore.set(this.fileName, "~/Documents"),
|
||||
click: () => this.goHistory("~/Documents"),
|
||||
});
|
||||
menuItems.push({
|
||||
label: "Go to Root",
|
||||
click: () => this.goHistory("/"),
|
||||
});
|
||||
menuItems.push({ label: "Go to Root", click: () => globalStore.set(this.fileName, "/") });
|
||||
ContextMenuModel.showContextMenu(menuItems, e);
|
||||
},
|
||||
};
|
||||
@ -164,7 +172,7 @@ export class PreviewModel implements ViewModel {
|
||||
return {
|
||||
elemtype: "iconbutton",
|
||||
icon: "chevron-left",
|
||||
click: this.handleBack.bind(this),
|
||||
click: this.goParentDirectory.bind(this),
|
||||
};
|
||||
});
|
||||
this.endIconButtons = jotai.atom((get) => {
|
||||
@ -188,18 +196,13 @@ export class PreviewModel implements ViewModel {
|
||||
}
|
||||
return null;
|
||||
});
|
||||
this.fileName = jotai.atom<string, [string], void>(
|
||||
(get) => {
|
||||
const file = get(this.blockAtom)?.meta?.file;
|
||||
if (util.isBlank(file)) {
|
||||
return "~";
|
||||
}
|
||||
return file;
|
||||
},
|
||||
(get, set, update) => {
|
||||
services.ObjectService.UpdateObjectMeta(`block:${blockId}`, { file: update });
|
||||
this.fileName = jotai.atom<string>((get) => {
|
||||
const file = get(this.blockAtom)?.meta?.file;
|
||||
if (util.isBlank(file)) {
|
||||
return "~";
|
||||
}
|
||||
);
|
||||
return file;
|
||||
});
|
||||
this.connection = jotai.atom<string>((get) => {
|
||||
return get(this.blockAtom)?.meta?.connection;
|
||||
});
|
||||
@ -232,20 +235,58 @@ export class PreviewModel implements ViewModel {
|
||||
});
|
||||
this.newFileContent = jotai.atom(null) as jotai.PrimitiveAtom<string | null>;
|
||||
|
||||
this.handleBack = this.handleBack.bind(this);
|
||||
this.goParentDirectory = this.goParentDirectory.bind(this);
|
||||
}
|
||||
|
||||
handleBack() {
|
||||
goHistory(newPath: string) {
|
||||
const blockMeta = globalStore.get(this.blockAtom)?.meta;
|
||||
const fileName = globalStore.get(this.fileName);
|
||||
if (fileName == null) {
|
||||
return;
|
||||
}
|
||||
const splitPath = fileName.split("/");
|
||||
console.log("splitPath-1", splitPath);
|
||||
splitPath.pop();
|
||||
console.log("splitPath-2", splitPath);
|
||||
const newPath = splitPath.join("/");
|
||||
globalStore.set(this.fileName, newPath);
|
||||
const updateMeta = historyutil.goHistory("file", fileName, newPath, blockMeta);
|
||||
if (updateMeta == null) {
|
||||
return;
|
||||
}
|
||||
const blockOref = WOS.makeORef("block", this.blockId);
|
||||
services.ObjectService.UpdateObjectMeta(blockOref, updateMeta);
|
||||
}
|
||||
|
||||
goParentDirectory() {
|
||||
const blockMeta = globalStore.get(this.blockAtom)?.meta;
|
||||
const fileName = globalStore.get(this.fileName);
|
||||
if (fileName == null) {
|
||||
return;
|
||||
}
|
||||
const newPath = historyutil.getParentDirectory(fileName);
|
||||
const updateMeta = historyutil.goHistory("file", fileName, newPath, blockMeta);
|
||||
if (updateMeta == null) {
|
||||
return;
|
||||
}
|
||||
const blockOref = WOS.makeORef("block", this.blockId);
|
||||
services.ObjectService.UpdateObjectMeta(blockOref, updateMeta);
|
||||
}
|
||||
|
||||
goHistoryBack() {
|
||||
const blockMeta = globalStore.get(this.blockAtom)?.meta;
|
||||
const curPath = globalStore.get(this.fileName);
|
||||
const updateMeta = historyutil.goHistoryBack("file", curPath, blockMeta, true);
|
||||
if (updateMeta == null) {
|
||||
return;
|
||||
}
|
||||
const blockOref = WOS.makeORef("block", this.blockId);
|
||||
services.ObjectService.UpdateObjectMeta(blockOref, updateMeta);
|
||||
}
|
||||
|
||||
goHistoryForward() {
|
||||
const blockMeta = globalStore.get(this.blockAtom)?.meta;
|
||||
const curPath = globalStore.get(this.fileName);
|
||||
const updateMeta = historyutil.goHistoryForward("file", curPath, blockMeta);
|
||||
if (updateMeta == null) {
|
||||
return;
|
||||
}
|
||||
const blockOref = WOS.makeORef("block", this.blockId);
|
||||
services.ObjectService.UpdateObjectMeta(blockOref, updateMeta);
|
||||
}
|
||||
|
||||
toggleCodeEditorReadOnly(readOnly: boolean) {
|
||||
@ -317,6 +358,23 @@ export class PreviewModel implements ViewModel {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
keyDownHandler(e: WaveKeyboardEvent): boolean {
|
||||
if (keyutil.checkKeyPressed(e, "Cmd:ArrowLeft")) {
|
||||
this.goHistoryBack();
|
||||
return true;
|
||||
}
|
||||
if (keyutil.checkKeyPressed(e, "Cmd:ArrowRight")) {
|
||||
this.goHistoryForward();
|
||||
return true;
|
||||
}
|
||||
if (keyutil.checkKeyPressed(e, "Cmd:ArrowUp")) {
|
||||
// handle up directory
|
||||
this.goParentDirectory();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function makePreviewModel(blockId: string): PreviewModel {
|
||||
|
2
frontend/types/gotypes.d.ts
vendored
2
frontend/types/gotypes.d.ts
vendored
@ -208,6 +208,8 @@ declare global {
|
||||
file?: string;
|
||||
url?: string;
|
||||
connection?: string;
|
||||
history?: string[];
|
||||
"history:forward"?: string[];
|
||||
icon?: string;
|
||||
"icon:color"?: string;
|
||||
frame?: boolean;
|
||||
|
75
frontend/util/historyutil.ts
Normal file
75
frontend/util/historyutil.ts
Normal file
@ -0,0 +1,75 @@
|
||||
// Copyright 2024, Command Line Inc.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import * as util from "@/util/util";
|
||||
|
||||
const MaxHistory = 20;
|
||||
|
||||
// this needs to be fixed for windows
|
||||
function getParentDirectory(path: string): string {
|
||||
if (util.isBlank(path) == null) {
|
||||
// this not great, ideally we'd never be passed a null path
|
||||
return "/";
|
||||
}
|
||||
if (path == "/") {
|
||||
return "/";
|
||||
}
|
||||
const splitPath = path.split("/");
|
||||
splitPath.pop();
|
||||
if (splitPath.length == 1 && splitPath[0] == "") {
|
||||
return "/";
|
||||
}
|
||||
const newPath = splitPath.join("/");
|
||||
return newPath;
|
||||
}
|
||||
|
||||
function goHistoryBack(curValKey: "url" | "file", curVal: string, meta: MetaType, backToParent: boolean): MetaType {
|
||||
const rtnMeta: MetaType = {};
|
||||
const history = (meta?.history ?? []).slice();
|
||||
const historyForward = (meta?.["history:forward"] ?? []).slice();
|
||||
if (history == null || history.length == 0) {
|
||||
if (backToParent) {
|
||||
const parentDir = getParentDirectory(curVal);
|
||||
if (parentDir == curVal) {
|
||||
return null;
|
||||
}
|
||||
historyForward.unshift(curVal);
|
||||
while (historyForward.length > MaxHistory) {
|
||||
historyForward.pop();
|
||||
}
|
||||
return { [curValKey]: parentDir, "history:forward": historyForward };
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
const lastVal = history.pop();
|
||||
historyForward.unshift(curVal);
|
||||
return { [curValKey]: lastVal, history: history, "history:forward": historyForward };
|
||||
}
|
||||
|
||||
function goHistoryForward(curValKey: "url" | "file", curVal: string, meta: MetaType): MetaType {
|
||||
const rtnMeta: MetaType = {};
|
||||
let history = (meta?.history ?? []).slice();
|
||||
const historyForward = (meta?.["history:forward"] ?? []).slice();
|
||||
if (historyForward == null || historyForward.length == 0) {
|
||||
return null;
|
||||
}
|
||||
const lastVal = historyForward.shift();
|
||||
history.push(curVal);
|
||||
if (history.length > MaxHistory) {
|
||||
history.shift();
|
||||
}
|
||||
return { [curValKey]: lastVal, history: history, "history:forward": historyForward };
|
||||
}
|
||||
|
||||
function goHistory(curValKey: "url" | "file", curVal: string, newVal: string, meta: MetaType): MetaType {
|
||||
const rtnMeta: MetaType = {};
|
||||
const history = (meta?.history ?? []).slice();
|
||||
history.push(curVal);
|
||||
if (history.length > MaxHistory) {
|
||||
history.shift();
|
||||
}
|
||||
return { [curValKey]: newVal, history: history, "history:forward": [] };
|
||||
}
|
||||
|
||||
export { getParentDirectory, goHistory, goHistoryBack, goHistoryForward };
|
@ -27,6 +27,7 @@ const (
|
||||
MetaKey_File = "file"
|
||||
MetaKey_Url = "url"
|
||||
MetaKey_Connection = "connection"
|
||||
MetaKey_History = "history" // stores an array of history items specific to the block
|
||||
|
||||
MetaKey_Icon = "icon"
|
||||
MetaKey_IconColor = "icon:color"
|
||||
@ -60,12 +61,14 @@ const (
|
||||
// for typescript typing
|
||||
type MetaTSType struct {
|
||||
// shared
|
||||
View string `json:"view,omitempty"`
|
||||
Controller string `json:"controller,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
File string `json:"file,omitempty"`
|
||||
Url string `json:"url,omitempty"`
|
||||
Connection string `json:"connection,omitempty"`
|
||||
View string `json:"view,omitempty"`
|
||||
Controller string `json:"controller,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
File string `json:"file,omitempty"`
|
||||
Url string `json:"url,omitempty"`
|
||||
Connection string `json:"connection,omitempty"`
|
||||
History []string `json:"history,omitempty"`
|
||||
HistoryForward []string `json:"history:forward,omitempty"`
|
||||
|
||||
Icon string `json:"icon,omitempty"`
|
||||
IconColor string `json:"icon:color,omitempty"`
|
||||
|
Loading…
Reference in New Issue
Block a user