mirror of https://github.com/stashapp/stash.git
Overhaul look and feel of folder select (#527)
This commit is contained in:
parent
e9c68897d7
commit
328db57d6c
|
@ -4,6 +4,10 @@ query Configuration {
|
|||
}
|
||||
}
|
||||
|
||||
query Directories($path: String) {
|
||||
directories(path: $path)
|
||||
}
|
||||
query Directory($path: String) {
|
||||
directory(path: $path) {
|
||||
path
|
||||
parent
|
||||
directories
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@ type Query {
|
|||
"""Returns the current, complete configuration"""
|
||||
configuration: ConfigResult!
|
||||
"""Returns an array of paths for the given path"""
|
||||
directories(path: String): [String!]!
|
||||
directory(path: String): Directory!
|
||||
|
||||
# Metadata
|
||||
|
||||
|
|
|
@ -117,3 +117,10 @@ type ConfigResult {
|
|||
general: ConfigGeneralResult!
|
||||
interface: ConfigInterfaceResult!
|
||||
}
|
||||
|
||||
"""Directory structure of a path"""
|
||||
type Directory {
|
||||
path: String!
|
||||
parent: String
|
||||
directories: [String!]!
|
||||
}
|
||||
|
|
|
@ -12,12 +12,18 @@ func (r *queryResolver) Configuration(ctx context.Context) (*models.ConfigResult
|
|||
return makeConfigResult(), nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) Directories(ctx context.Context, path *string) ([]string, error) {
|
||||
func (r *queryResolver) Directory(ctx context.Context, path *string) (*models.Directory, error) {
|
||||
var dirPath = ""
|
||||
if path != nil {
|
||||
dirPath = *path
|
||||
}
|
||||
return utils.ListDir(dirPath), nil
|
||||
currentDir := utils.GetDir(dirPath)
|
||||
|
||||
return &models.Directory{
|
||||
Path: currentDir,
|
||||
Parent: utils.GetParent(currentDir),
|
||||
Directories: utils.ListDir(currentDir),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func makeConfigResult() *models.ConfigResult {
|
||||
|
|
|
@ -96,15 +96,6 @@ func EmptyDir(path string) error {
|
|||
|
||||
// ListDir will return the contents of a given directory path as a string slice
|
||||
func ListDir(path string) []string {
|
||||
if path == "" {
|
||||
path = GetHomeDirectory()
|
||||
}
|
||||
|
||||
absolutePath, err := filepath.Abs(path)
|
||||
if err == nil {
|
||||
path = absolutePath
|
||||
}
|
||||
|
||||
files, err := ioutil.ReadDir(path)
|
||||
if err != nil {
|
||||
path = filepath.Dir(path)
|
||||
|
@ -133,3 +124,25 @@ func GetHomeDirectory() string {
|
|||
}
|
||||
return currentUser.HomeDir
|
||||
}
|
||||
|
||||
func GetDir(path string) string {
|
||||
if path == "" {
|
||||
path = GetHomeDirectory()
|
||||
}
|
||||
|
||||
absolutePath, err := filepath.Abs(path)
|
||||
if err == nil {
|
||||
path = absolutePath
|
||||
}
|
||||
return absolutePath
|
||||
}
|
||||
|
||||
func GetParent(path string) *string {
|
||||
isRoot := path[len(path)-1:] == "/"
|
||||
if isRoot {
|
||||
return nil
|
||||
} else {
|
||||
parentPath := filepath.Clean(path + "/..")
|
||||
return &parentPath
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import { Button, InputGroup, Form, Modal } from "react-bootstrap";
|
||||
import { LoadingIndicator } from "src/components/Shared";
|
||||
import { useDirectories } from "src/core/StashService";
|
||||
import { useDirectory } from "src/core/StashService";
|
||||
|
||||
interface IProps {
|
||||
directories: string[];
|
||||
|
@ -12,13 +13,18 @@ export const FolderSelect: React.FC<IProps> = (props: IProps) => {
|
|||
const [currentDirectory, setCurrentDirectory] = useState<string>("");
|
||||
const [isDisplayingDialog, setIsDisplayingDialog] = useState<boolean>(false);
|
||||
const [selectedDirectories, setSelectedDirectories] = useState<string[]>([]);
|
||||
const { data, error, loading } = useDirectories(currentDirectory);
|
||||
const { data, error, loading } = useDirectory(currentDirectory);
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedDirectories(props.directories);
|
||||
}, [props.directories]);
|
||||
|
||||
const selectableDirectories: string[] = data?.directories ?? [];
|
||||
useEffect(() => {
|
||||
if (currentDirectory === "" && data?.directory.path)
|
||||
setCurrentDirectory(data.directory.path);
|
||||
}, [currentDirectory, data]);
|
||||
|
||||
const selectableDirectories: string[] = data?.directory.directories ?? [];
|
||||
|
||||
function onSelectDirectory() {
|
||||
selectedDirectories.push(currentDirectory);
|
||||
|
@ -36,6 +42,19 @@ export const FolderSelect: React.FC<IProps> = (props: IProps) => {
|
|||
props.onDirectoriesChanged(newSelectedDirectories);
|
||||
}
|
||||
|
||||
const topDirectory = data?.directory?.parent ? (
|
||||
<li className="folder-list-parent folder-list-item">
|
||||
<Button
|
||||
variant="link"
|
||||
onClick={() =>
|
||||
data.directory.parent && setCurrentDirectory(data.directory.parent)
|
||||
}
|
||||
>
|
||||
<FormattedMessage defaultMessage="Up a directory" id="up-dir" />
|
||||
</Button>
|
||||
</li>
|
||||
) : null;
|
||||
|
||||
function renderDialog() {
|
||||
return (
|
||||
<Modal
|
||||
|
@ -52,11 +71,11 @@ export const FolderSelect: React.FC<IProps> = (props: IProps) => {
|
|||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||
setCurrentDirectory(e.currentTarget.value)
|
||||
}
|
||||
defaultValue={currentDirectory}
|
||||
value={currentDirectory}
|
||||
spellCheck={false}
|
||||
/>
|
||||
<InputGroup.Append>
|
||||
{!data || !data.directories || loading ? (
|
||||
{!data || !data.directory || loading ? (
|
||||
<LoadingIndicator inline />
|
||||
) : (
|
||||
""
|
||||
|
@ -64,12 +83,12 @@ export const FolderSelect: React.FC<IProps> = (props: IProps) => {
|
|||
</InputGroup.Append>
|
||||
</InputGroup>
|
||||
<ul className="folder-list">
|
||||
{topDirectory}
|
||||
{selectableDirectories.map((path) => {
|
||||
return (
|
||||
<li key={path} className="folder-item">
|
||||
<li key={path} className="folder-list-item">
|
||||
<Button
|
||||
variant="link"
|
||||
key={path}
|
||||
onClick={() => setCurrentDirectory(path)}
|
||||
>
|
||||
{path}
|
||||
|
|
|
@ -75,3 +75,41 @@
|
|||
min-width: 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.folder-list {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding-top: 1rem;
|
||||
|
||||
&-item {
|
||||
white-space: nowrap;
|
||||
|
||||
.btn-link {
|
||||
border: none;
|
||||
color: black;
|
||||
font-weight: 400;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
&:last-child::before {
|
||||
content: "└ \1F4C1";
|
||||
}
|
||||
|
||||
&::before {
|
||||
content: "├ \1F4C1";
|
||||
display: inline-block;
|
||||
padding-right: 1rem;
|
||||
transform: scale(1.5);
|
||||
}
|
||||
}
|
||||
|
||||
&-parent {
|
||||
&::before {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.btn-link {
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -173,8 +173,8 @@ export const useLatestVersion = () =>
|
|||
});
|
||||
|
||||
export const useConfiguration = () => GQL.useConfigurationQuery();
|
||||
export const useDirectories = (path?: string) =>
|
||||
GQL.useDirectoriesQuery({ variables: { path } });
|
||||
export const useDirectory = (path?: string) =>
|
||||
GQL.useDirectoryQuery({ variables: { path } });
|
||||
|
||||
export const performerMutationImpactedQueries = [
|
||||
"findPerformers",
|
||||
|
|
Loading…
Reference in New Issue