Search Fixes (#84)

This change:
- now clears the search box when entering a new directory
- fixes some styling issues
- adds a .. to the path
- uses the correct path (except on the initial start of the directory
widget)
This commit is contained in:
Sylvie Crowe 2024-06-27 12:30:08 -07:00 committed by GitHub
parent 76c909114e
commit 23e1c8797d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 62 additions and 19 deletions

View File

@ -1,8 +1,6 @@
// Copyright 2024, Command Line Inc. // Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
import { getBackendHostPort } from "@/app/store/global";
import * as keyutil from "@/util/keyutil";
import * as electron from "electron"; import * as electron from "electron";
import fs from "fs"; import fs from "fs";
import * as child_process from "node:child_process"; import * as child_process from "node:child_process";
@ -10,7 +8,9 @@ import os from "os";
import * as path from "path"; import * as path from "path";
import * as readline from "readline"; import * as readline from "readline";
import { debounce } from "throttle-debounce"; import { debounce } from "throttle-debounce";
import { getBackendHostPort } from "../frontend/app/store/global";
import * as services from "../frontend/app/store/services"; import * as services from "../frontend/app/store/services";
import * as keyutil from "../frontend/util/keyutil";
const electronApp = electron.app; const electronApp = electron.app;
const isDev = process.env.WAVETERM_DEV; const isDev = process.env.WAVETERM_DEV;

View File

@ -51,11 +51,31 @@
border-radius: 3px; border-radius: 3px;
&.focused { &.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 { &: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) { &:hover:not(:focus):not(.focused) {

View File

@ -26,6 +26,7 @@ interface DirectoryTableProps {
enter: boolean; enter: boolean;
setFocusIndex: (_: number) => void; setFocusIndex: (_: number) => void;
setFileName: (_: string) => void; setFileName: (_: string) => void;
setSearch: (_: string) => void;
} }
const columnHelper = createColumnHelper<FileInfo>(); const columnHelper = createColumnHelper<FileInfo>();
@ -154,7 +155,7 @@ function cleanMimetype(input: string): string {
return truncated.trim(); 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); let settings = jotai.useAtomValue(atoms.settingsConfigAtom);
const getIconFromMimeType = React.useCallback( const getIconFromMimeType = React.useCallback(
(mimeType: string): string => { (mimeType: string): string => {
@ -190,8 +191,8 @@ function DirectoryTable({ data, cwd, focusIndex, enter, setFocusIndex, setFileNa
size: 25, size: 25,
enableSorting: false, enableSorting: false,
}), }),
columnHelper.accessor("path", { columnHelper.accessor("name", {
cell: (info) => <span className="dir-table-path">{info.getValue()}</span>, cell: (info) => <span className="dir-table-name">{info.getValue()}</span>,
header: () => <span>Name</span>, header: () => <span>Name</span>,
sortingFn: "alphanumeric", sortingFn: "alphanumeric",
}), }),
@ -222,6 +223,7 @@ function DirectoryTable({ data, cwd, focusIndex, enter, setFocusIndex, setFileNa
header: () => <span>Type</span>, header: () => <span>Type</span>,
sortingFn: "alphanumeric", sortingFn: "alphanumeric",
}), }),
columnHelper.accessor("path", {}),
], ],
[settings] [settings]
); );
@ -232,13 +234,17 @@ function DirectoryTable({ data, cwd, focusIndex, enter, setFocusIndex, setFileNa
columnResizeMode: "onChange", columnResizeMode: "onChange",
getSortedRowModel: getSortedRowModel(), getSortedRowModel: getSortedRowModel(),
getCoreRowModel: getCoreRowModel(), getCoreRowModel: getCoreRowModel(),
initialState: { initialState: {
sorting: [ sorting: [
{ {
id: "path", id: "name",
desc: false, desc: false,
}, },
], ],
columnVisibility: {
path: false,
},
}, },
enableMultiSort: false, enableMultiSort: false,
enableSortingRemoval: false, enableSortingRemoval: false,
@ -289,6 +295,7 @@ function DirectoryTable({ data, cwd, focusIndex, enter, setFocusIndex, setFileNa
enter={enter} enter={enter}
setFileName={setFileName} setFileName={setFileName}
setFocusIndex={setFocusIndex} setFocusIndex={setFocusIndex}
setSearch={setSearch}
/> />
) : ( ) : (
<TableBody <TableBody
@ -298,6 +305,7 @@ function DirectoryTable({ data, cwd, focusIndex, enter, setFocusIndex, setFileNa
enter={enter} enter={enter}
setFileName={setFileName} setFileName={setFileName}
setFocusIndex={setFocusIndex} setFocusIndex={setFocusIndex}
setSearch={setSearch}
/> />
)} )}
</div> </div>
@ -311,16 +319,17 @@ interface TableBodyProps {
enter: boolean; enter: boolean;
setFocusIndex: (_: number) => void; setFocusIndex: (_: number) => void;
setFileName: (_: string) => 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); let [refresh, setRefresh] = React.useState(false);
React.useEffect(() => { React.useEffect(() => {
const selected = (table.getSortedRowModel()?.flatRows[focusIndex]?.getValue("path") as string) ?? null; const selected = (table.getSortedRowModel()?.flatRows[focusIndex]?.getValue("path") as string) ?? null;
if (selected != null) { if (selected != null) {
const fullPath = cwd.concat("/", selected); setFileName(selected);
setFileName(fullPath); setSearch("");
} }
}, [enter]); }, [enter]);
@ -333,11 +342,11 @@ function TableBody({ table, cwd, focusIndex, enter, setFocusIndex, setFileName }
key={row.id} key={row.id}
onDoubleClick={() => { onDoubleClick={() => {
const newFileName = row.getValue("path") as string; const newFileName = row.getValue("path") as string;
const fullPath = cwd.concat("/", newFileName); setFileName(newFileName);
setFileName(fullPath); setSearch("");
}} }}
onClick={() => setFocusIndex(idx)} 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) => { {row.getVisibleCells().map((cell) => {
return ( return (
@ -378,7 +387,7 @@ function DirectoryPreview({ fileNameAtom }: DirectoryPreviewProps) {
const serializedContent = util.base64ToString(file?.data64); const serializedContent = util.base64ToString(file?.data64);
let content: FileInfo[] = JSON.parse(serializedContent); let content: FileInfo[] = JSON.parse(serializedContent);
let filtered = content.filter((fileInfo) => { let filtered = content.filter((fileInfo) => {
return fileInfo.path.toLowerCase().includes(searchText); return fileInfo.name.toLowerCase().includes(searchText);
}); });
setContent(filtered); setContent(filtered);
}; };
@ -432,6 +441,7 @@ function DirectoryPreview({ fileNameAtom }: DirectoryPreviewProps) {
onChange={(e) => setSearchText(e.target.value.toLowerCase())} onChange={(e) => setSearchText(e.target.value.toLowerCase())}
maxLength={400} maxLength={400}
autoFocus={true} autoFocus={true}
value={searchText}
/> />
</div> </div>
<DirectoryTable <DirectoryTable
@ -441,6 +451,7 @@ function DirectoryPreview({ fileNameAtom }: DirectoryPreviewProps) {
enter={enter} enter={enter}
setFileName={setFileName} setFileName={setFileName}
setFocusIndex={setFocusIndex} setFocusIndex={setFocusIndex}
setSearch={setSearchText}
/> />
</> </>
); );

View File

@ -61,7 +61,7 @@ declare global {
// wshutil.BlockInputCommand // wshutil.BlockInputCommand
type BlockInputCommand = { type BlockInputCommand = {
blockid?: string; blockid: string;
command: "controller:input"; command: "controller:input";
inputdata64?: string; inputdata64?: string;
signame?: string; signame?: string;
@ -139,6 +139,7 @@ declare global {
// fileservice.FileInfo // fileservice.FileInfo
type FileInfo = { type FileInfo = {
path: string; path: string;
name: string;
notfound?: boolean; notfound?: boolean;
size: number; size: number;
mode: number; mode: number;
@ -381,4 +382,4 @@ declare global {
} }
export {} export {}

View File

@ -8,6 +8,7 @@ import (
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
"fmt" "fmt"
"log"
"os" "os"
"path/filepath" "path/filepath"
"time" "time"
@ -25,6 +26,7 @@ type FileService struct{}
type FileInfo struct { type FileInfo struct {
Path string `json:"path"` // cleaned path Path string `json:"path"` // cleaned path
Name string `json:"name"`
NotFound bool `json:"notfound,omitempty"` NotFound bool `json:"notfound,omitempty"`
Size int64 `json:"size"` Size int64 `json:"size"`
Mode os.FileMode `json:"mode"` Mode os.FileMode `json:"mode"`
@ -51,6 +53,7 @@ func (fs *FileService) StatFile(path string) (*FileInfo, error) {
mimeType := utilfn.DetectMimeType(cleanedPath) mimeType := utilfn.DetectMimeType(cleanedPath)
return &FileInfo{ return &FileInfo{
Path: cleanedPath, Path: cleanedPath,
Name: finfo.Name(),
Size: finfo.Size(), Size: finfo.Size(),
Mode: finfo.Mode(), Mode: finfo.Mode(),
ModeStr: finfo.Mode().String(), ModeStr: finfo.Mode().String(),
@ -80,6 +83,13 @@ func (fs *FileService) ReadFile(path string) (*FullFile, error) {
innerFilesEntries = innerFilesEntries[:1000] innerFilesEntries = innerFilesEntries[:1000]
} }
var innerFilesInfo []FileInfo 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 { for _, innerFileEntry := range innerFilesEntries {
innerFileInfoInt, _ := innerFileEntry.Info() innerFileInfoInt, _ := innerFileEntry.Info()
mimeType := utilfn.DetectMimeType(filepath.Join(finfo.Path, innerFileInfoInt.Name())) mimeType := utilfn.DetectMimeType(filepath.Join(finfo.Path, innerFileInfoInt.Name()))
@ -90,7 +100,8 @@ func (fs *FileService) ReadFile(path string) (*FullFile, error) {
fileSize = innerFileInfoInt.Size() fileSize = innerFileInfoInt.Size()
} }
innerFileInfo := FileInfo{ innerFileInfo := FileInfo{
Path: innerFileInfoInt.Name(), Path: filepath.Join(finfo.Path, innerFileInfoInt.Name()),
Name: innerFileInfoInt.Name(),
Size: fileSize, Size: fileSize,
Mode: innerFileInfoInt.Mode(), Mode: innerFileInfoInt.Mode(),
ModeStr: innerFileInfoInt.Mode().String(), ModeStr: innerFileInfoInt.Mode().String(),

View File

@ -68,7 +68,7 @@ func getSettingsConfigDefaults() SettingsConfigType {
"audio": {Icon: "file-audio"}, "audio": {Icon: "file-audio"},
"application/pdf": {Icon: "file-pdf"}, "application/pdf": {Icon: "file-pdf"},
"application/json": {Icon: "file-lines"}, "application/json": {Icon: "file-lines"},
"directory": {Icon: "folder", Color: "#2e62d2"}, "directory": {Icon: "folder", Color: "var(--term-bright-blue)"},
"font": {Icon: "book-font"}, "font": {Icon: "book-font"},
"image": {Icon: "file-image"}, "image": {Icon: "file-image"},
"text": {Icon: "file-lines"}, "text": {Icon: "file-lines"},