diff --git a/emain/emain.ts b/emain/emain.ts index 1c6a1411b..b06764b14 100644 --- a/emain/emain.ts +++ b/emain/emain.ts @@ -1,8 +1,6 @@ // Copyright 2024, Command Line Inc. // SPDX-License-Identifier: Apache-2.0 -import { getBackendHostPort } from "@/app/store/global"; -import * as keyutil from "@/util/keyutil"; import * as electron from "electron"; import fs from "fs"; import * as child_process from "node:child_process"; @@ -10,7 +8,9 @@ import os from "os"; import * as path from "path"; import * as readline from "readline"; import { debounce } from "throttle-debounce"; +import { getBackendHostPort } from "../frontend/app/store/global"; import * as services from "../frontend/app/store/services"; +import * as keyutil from "../frontend/util/keyutil"; const electronApp = electron.app; const isDev = process.env.WAVETERM_DEV; diff --git a/frontend/app/view/directorypreview.less b/frontend/app/view/directorypreview.less index c8b130779..2896e08a0 100644 --- a/frontend/app/view/directorypreview.less +++ b/frontend/app/view/directorypreview.less @@ -51,11 +51,31 @@ border-radius: 3px; &.focused { - background-color: var(--accent-color); + background-color: rgb(from var(--accent-color) r g b / 0.7); + color: var(--main-text-color); + + .dir-table-body-cell { + .dir-table-lastmod, + .dir-table-modestr, + .dir-table-size, + .dir-table-type { + color: var(--main-text-color); + } + } } &:focus { - background-color: var(--accent-color); + background-color: rgb(from var(--accent-color) r g b / 0.7); + color: var(--main-text-color); + + .dir-table-body-cell { + .dir-table-lastmod, + .dir-table-modestr, + .dir-table-size, + .dir-table-type { + color: var(--main-text-color); + } + } } &:hover:not(:focus):not(.focused) { diff --git a/frontend/app/view/directorypreview.tsx b/frontend/app/view/directorypreview.tsx index 8573b3932..a58efddfe 100644 --- a/frontend/app/view/directorypreview.tsx +++ b/frontend/app/view/directorypreview.tsx @@ -26,6 +26,7 @@ interface DirectoryTableProps { enter: boolean; setFocusIndex: (_: number) => void; setFileName: (_: string) => void; + setSearch: (_: string) => void; } const columnHelper = createColumnHelper(); @@ -154,7 +155,7 @@ function cleanMimetype(input: string): string { return truncated.trim(); } -function DirectoryTable({ data, cwd, focusIndex, enter, setFocusIndex, setFileName }: DirectoryTableProps) { +function DirectoryTable({ data, cwd, focusIndex, enter, setFocusIndex, setFileName, setSearch }: DirectoryTableProps) { let settings = jotai.useAtomValue(atoms.settingsConfigAtom); const getIconFromMimeType = React.useCallback( (mimeType: string): string => { @@ -190,8 +191,8 @@ function DirectoryTable({ data, cwd, focusIndex, enter, setFocusIndex, setFileNa size: 25, enableSorting: false, }), - columnHelper.accessor("path", { - cell: (info) => {info.getValue()}, + columnHelper.accessor("name", { + cell: (info) => {info.getValue()}, header: () => Name, sortingFn: "alphanumeric", }), @@ -222,6 +223,7 @@ function DirectoryTable({ data, cwd, focusIndex, enter, setFocusIndex, setFileNa header: () => Type, sortingFn: "alphanumeric", }), + columnHelper.accessor("path", {}), ], [settings] ); @@ -232,13 +234,17 @@ function DirectoryTable({ data, cwd, focusIndex, enter, setFocusIndex, setFileNa columnResizeMode: "onChange", getSortedRowModel: getSortedRowModel(), getCoreRowModel: getCoreRowModel(), + initialState: { sorting: [ { - id: "path", + id: "name", desc: false, }, ], + columnVisibility: { + path: false, + }, }, enableMultiSort: false, enableSortingRemoval: false, @@ -289,6 +295,7 @@ function DirectoryTable({ data, cwd, focusIndex, enter, setFocusIndex, setFileNa enter={enter} setFileName={setFileName} setFocusIndex={setFocusIndex} + setSearch={setSearch} /> ) : ( )} @@ -311,16 +319,17 @@ interface TableBodyProps { enter: boolean; setFocusIndex: (_: number) => void; setFileName: (_: string) => void; + setSearch: (_: string) => void; } -function TableBody({ table, cwd, focusIndex, enter, setFocusIndex, setFileName }: TableBodyProps) { +function TableBody({ table, cwd, focusIndex, enter, setFocusIndex, setFileName, setSearch }: TableBodyProps) { let [refresh, setRefresh] = React.useState(false); React.useEffect(() => { const selected = (table.getSortedRowModel()?.flatRows[focusIndex]?.getValue("path") as string) ?? null; if (selected != null) { - const fullPath = cwd.concat("/", selected); - setFileName(fullPath); + setFileName(selected); + setSearch(""); } }, [enter]); @@ -333,11 +342,11 @@ function TableBody({ table, cwd, focusIndex, enter, setFocusIndex, setFileName } key={row.id} onDoubleClick={() => { const newFileName = row.getValue("path") as string; - const fullPath = cwd.concat("/", newFileName); - setFileName(fullPath); + setFileName(newFileName); + setSearch(""); }} onClick={() => setFocusIndex(idx)} - onContextMenu={(e) => handleFileContextMenu(e, cwd.concat("/", row.getValue("path") as string))} + onContextMenu={(e) => handleFileContextMenu(e, row.getValue("path") as string)} > {row.getVisibleCells().map((cell) => { return ( @@ -378,7 +387,7 @@ function DirectoryPreview({ fileNameAtom }: DirectoryPreviewProps) { const serializedContent = util.base64ToString(file?.data64); let content: FileInfo[] = JSON.parse(serializedContent); let filtered = content.filter((fileInfo) => { - return fileInfo.path.toLowerCase().includes(searchText); + return fileInfo.name.toLowerCase().includes(searchText); }); setContent(filtered); }; @@ -432,6 +441,7 @@ function DirectoryPreview({ fileNameAtom }: DirectoryPreviewProps) { onChange={(e) => setSearchText(e.target.value.toLowerCase())} maxLength={400} autoFocus={true} + value={searchText} /> ); diff --git a/frontend/types/gotypes.d.ts b/frontend/types/gotypes.d.ts index f0c33ba7f..b52a4b03d 100644 --- a/frontend/types/gotypes.d.ts +++ b/frontend/types/gotypes.d.ts @@ -61,7 +61,7 @@ declare global { // wshutil.BlockInputCommand type BlockInputCommand = { - blockid?: string; + blockid: string; command: "controller:input"; inputdata64?: string; signame?: string; @@ -139,6 +139,7 @@ declare global { // fileservice.FileInfo type FileInfo = { path: string; + name: string; notfound?: boolean; size: number; mode: number; @@ -381,4 +382,4 @@ declare global { } -export {} \ No newline at end of file +export {} diff --git a/pkg/service/fileservice/fileservice.go b/pkg/service/fileservice/fileservice.go index a887d4386..210315a45 100644 --- a/pkg/service/fileservice/fileservice.go +++ b/pkg/service/fileservice/fileservice.go @@ -8,6 +8,7 @@ import ( "encoding/base64" "encoding/json" "fmt" + "log" "os" "path/filepath" "time" @@ -25,6 +26,7 @@ type FileService struct{} type FileInfo struct { Path string `json:"path"` // cleaned path + Name string `json:"name"` NotFound bool `json:"notfound,omitempty"` Size int64 `json:"size"` Mode os.FileMode `json:"mode"` @@ -51,6 +53,7 @@ func (fs *FileService) StatFile(path string) (*FileInfo, error) { mimeType := utilfn.DetectMimeType(cleanedPath) return &FileInfo{ Path: cleanedPath, + Name: finfo.Name(), Size: finfo.Size(), Mode: finfo.Mode(), ModeStr: finfo.Mode().String(), @@ -80,6 +83,13 @@ func (fs *FileService) ReadFile(path string) (*FullFile, error) { innerFilesEntries = innerFilesEntries[:1000] } var innerFilesInfo []FileInfo + parent := filepath.Dir(finfo.Path) + parentFileInfo, err := fs.StatFile(parent) + if err == nil && parent != finfo.Path { + log.Printf("adding parent") + parentFileInfo.Name = ".." + innerFilesInfo = append(innerFilesInfo, *parentFileInfo) + } for _, innerFileEntry := range innerFilesEntries { innerFileInfoInt, _ := innerFileEntry.Info() mimeType := utilfn.DetectMimeType(filepath.Join(finfo.Path, innerFileInfoInt.Name())) @@ -90,7 +100,8 @@ func (fs *FileService) ReadFile(path string) (*FullFile, error) { fileSize = innerFileInfoInt.Size() } innerFileInfo := FileInfo{ - Path: innerFileInfoInt.Name(), + Path: filepath.Join(finfo.Path, innerFileInfoInt.Name()), + Name: innerFileInfoInt.Name(), Size: fileSize, Mode: innerFileInfoInt.Mode(), ModeStr: innerFileInfoInt.Mode().String(), diff --git a/pkg/wconfig/settingsconfig.go b/pkg/wconfig/settingsconfig.go index 98d734244..4d23af27a 100644 --- a/pkg/wconfig/settingsconfig.go +++ b/pkg/wconfig/settingsconfig.go @@ -68,7 +68,7 @@ func getSettingsConfigDefaults() SettingsConfigType { "audio": {Icon: "file-audio"}, "application/pdf": {Icon: "file-pdf"}, "application/json": {Icon: "file-lines"}, - "directory": {Icon: "folder", Color: "#2e62d2"}, + "directory": {Icon: "folder", Color: "var(--term-bright-blue)"}, "font": {Icon: "book-font"}, "image": {Icon: "file-image"}, "text": {Icon: "file-lines"},