Farmbot-Web-App/frontend/folders/component.tsx

240 lines
7.0 KiB
TypeScript
Raw Normal View History

import React from "react";
2019-12-18 14:15:23 -07:00
import { BlurableInput, ColorPicker, Row, Col } from "../ui";
2019-12-13 14:26:57 -07:00
import {
FolderUnion,
FolderItemProps,
FolderNodeProps,
FolderProps,
2019-12-18 12:28:15 -07:00
FolderState,
FolderDropButtonProps,
AddFolderBtn,
AddSequenceProps,
ToggleFolderBtnProps
2019-12-13 14:26:57 -07:00
} from "./constants";
2019-12-05 15:40:06 -07:00
import {
createFolder,
deleteFolder,
setFolderName,
toggleFolderOpenState,
toggleFolderEditState,
toggleAll,
updateSearchTerm,
addNewSequenceToFolder,
2019-12-11 12:22:48 -07:00
moveSequence,
setFolderColor
2019-12-05 15:40:06 -07:00
} from "./actions";
import { Link } from "../link";
import { urlFriendly } from "../util";
import { setActiveSequenceByName } from "../sequences/set_active_sequence_by_name";
2019-12-17 17:32:30 -07:00
import { Position, Popover } from "@blueprintjs/core";
2019-12-12 15:56:57 -07:00
import { t } from "../i18next_wrapper";
2019-12-04 15:42:27 -07:00
2019-12-17 16:37:05 -07:00
const FolderListItem = (props: FolderItemProps) => {
const { sequence, onClick } = props;
2019-12-17 13:19:17 -07:00
const url = `/app/sequences/${urlFriendly(sequence.body.name) || ""}`;
2019-12-18 10:33:23 -07:00
const style = props.isMoveTarget ? { border: "1px solid red" } : {};
return <li style={style}>
2019-12-18 12:48:48 -07:00
<i onClick={() => onClick(sequence.uuid)} className="fa fa-arrows">{""}</i>
2019-12-17 13:19:17 -07:00
<Link to={url} key={sequence.uuid} onClick={setActiveSequenceByName}>
2019-12-18 10:33:23 -07:00
{sequence.body.name}
</Link>
</li>;
};
2019-12-18 12:48:48 -07:00
const ToggleFolderBtn = (p: ToggleFolderBtnProps) => {
const klass = `fa fa-${p.expanded ? "plus" : "minus"}-square`;
2019-12-18 13:14:37 -07:00
return <button className="fb-button gray">
<i className={klass} onClick={p.onClick} />
</button>;
2019-12-18 12:48:48 -07:00
};
2019-12-17 16:37:05 -07:00
const DropFolderHereBtn = (props: FolderDropButtonProps) => {
if (props.active) {
2019-12-18 10:33:23 -07:00
return <button className="drag-drop-area visible" onClick={props.onClick}>
2019-12-18 12:28:15 -07:00
Move sequence here
2019-12-18 10:33:23 -07:00
</button>;
} else {
return <span />;
}
};
const AddFolderBtn = ({ folder }: AddFolderBtn) => {
2019-12-18 13:14:37 -07:00
return <button className="fb-button gray">
<i
title={"Create Subfolder"}
onClick={() => createFolder(folder || {})}
className="fa fa-folder" />
</button>;
};
2019-12-18 13:14:37 -07:00
const AddSequence = ({ folderId }: AddSequenceProps) => {
return <button className="fb-button green">
<i className="fa fa-server" onClick={() => addNewSequenceToFolder(folderId)} />
</button>;
};
const FolderButtonCluster = ({ node }: FolderNodeProps) => {
2019-12-18 10:57:03 -07:00
return <div style={{ display: "flex" }}>
<ColorPicker
position={Position.LEFT}
onChange={(color) => setFolderColor(node.id, color)}
current={node.color} />
2019-12-17 16:37:05 -07:00
{node.kind !== "terminal" && <AddFolderBtn folder={{ parent_id: node.id }} />}
2019-12-18 13:14:37 -07:00
<button className="fb-button gray">
<i className="fa fa-trash" onClick={() => deleteFolder(node.id)} />
</button>
<button className="fb-button gray">
<i className="fa fa-pencil" onClick={() => toggleFolderEditState(node.id)} />
</button>
2019-12-17 16:37:05 -07:00
<AddSequence folderId={node.id} />
</div>;
};
const FolderNameEditor = (props: FolderNodeProps) => {
2019-12-18 10:33:23 -07:00
const { node } = props;
if (props.movedSequenceUuid) {
2019-12-17 16:37:05 -07:00
return <DropFolderHereBtn
active={true}
onClick={() => props.onMoveEnd(node.id)} />;
}
const onCommit = (e: React.SyntheticEvent<HTMLInputElement, Event>) => {
const { currentTarget } = e;
return setFolderName(node.id, currentTarget.value)
.then(() => toggleFolderEditState(node.id));
};
let namePart: JSX.Element;
2019-12-18 12:48:48 -07:00
const toggle = () => toggleFolderOpenState(node.id);
if (node.editing) {
namePart = <BlurableInput value={node.name} onCommit={onCommit} />;
} else {
namePart = <span onClick={toggle}> {node.name}</span>;
}
2019-12-18 13:56:55 -07:00
2019-12-18 12:48:48 -07:00
const faIcon = ` fa fa-chevron-${node.open ? "down" : "right"}`;
const STYLE_MOVE_ME: React.StyleHTMLAttributes<HTMLDivElement>["style"] = {
backgroundColor: "#ddd",
borderBottom: "1px solid #aaa",
2019-12-18 14:14:58 -07:00
// display: "flex",
cursor: "pointer",
2019-12-18 13:45:38 -07:00
padding: "0.5rem",
margin: "0.5rem",
height: "3.5rem"
};
2019-12-18 14:14:58 -07:00
return <div className={"folder-block"} style={STYLE_MOVE_ME}>
<i className={faIcon} title={"Open/Close Folder"} onClick={toggle} />
2019-12-18 13:56:55 -07:00
<i className="fa fa-folder" style={{ color: node.color }} />
2019-12-17 17:32:30 -07:00
{namePart}
2019-12-18 13:56:55 -07:00
<Popover>
<i className={"fa fa-ellipsis-v"} />
<FolderButtonCluster {...props} />
</Popover>
</div>;
2019-12-17 16:37:05 -07:00
};
const FolderNode = (props: FolderNodeProps) => {
const { node, sequences } = props;
2019-12-11 07:03:21 -07:00
const names = node
.content
2019-12-17 16:37:05 -07:00
.map(x => <FolderListItem
sequence={sequences[x]}
key={"F" + x}
onClick={props.onMoveStart}
isMoveTarget={props.movedSequenceUuid === x} />);
2019-12-04 15:42:27 -07:00
const children = <ul> {names} </ul>;
const mapper = (n2: FolderUnion) => <FolderNode
node={n2}
key={n2.id}
sequences={sequences}
movedSequenceUuid={props.movedSequenceUuid}
onMoveStart={props.onMoveStart}
onMoveEnd={props.onMoveEnd} />;
const array: FolderUnion[] = node.children || [];
2019-12-17 17:32:30 -07:00
return <div style={{ marginLeft: 10 }}>
2019-12-17 13:19:17 -07:00
<Row>
2019-12-17 16:37:05 -07:00
<Col xs={12} className="color-picker-col">
<FolderNameEditor {...props} />
2019-12-17 13:19:17 -07:00
</Col>
</Row>
{!!node.open && children}
2019-12-17 17:32:30 -07:00
{!!node.open && array.map(mapper)}
2019-12-04 16:26:16 -07:00
</div>;
2019-12-04 15:42:27 -07:00
};
2019-12-13 14:26:57 -07:00
export class Folders extends React.Component<FolderProps, FolderState> {
2019-12-18 13:14:37 -07:00
state: FolderState = { toggleDirection: false };
2019-12-05 15:40:06 -07:00
Graph = (_props: {}) => {
2019-12-12 15:56:57 -07:00
2019-11-22 10:43:30 -07:00
return <div>
2019-12-12 15:56:57 -07:00
{this.props.rootFolder.folders.map(grandparent => {
2019-12-04 15:42:27 -07:00
return <FolderNode
node={grandparent}
key={grandparent.id}
movedSequenceUuid={this.state.movedSequenceUuid}
onMoveStart={this.startSequenceMove}
onMoveEnd={this.endSequenceMove}
2019-12-04 15:42:27 -07:00
sequences={this.props.sequences} />;
})}
2019-11-22 10:43:30 -07:00
</div>;
}
2019-12-05 15:40:06 -07:00
toggleAll = () => {
toggleAll(this.state.toggleDirection);
this.setState({ toggleDirection: !this.state.toggleDirection });
}
startSequenceMove = (seqUuid: string) => {
this.setState({ movedSequenceUuid: seqUuid });
}
endSequenceMove = (folderId: number) => {
moveSequence(this.state.movedSequenceUuid || "", folderId);
this.setState({ movedSequenceUuid: undefined });
}
2019-12-13 14:26:57 -07:00
rootSequences = () => this
.props
.rootFolder
.noFolder
2019-12-17 16:37:05 -07:00
.map(x => <FolderListItem
2019-12-13 14:26:57 -07:00
key={x}
sequence={this.props.sequences[x]}
onClick={this.startSequenceMove}
isMoveTarget={this.state.movedSequenceUuid === x} />);
render() {
return <div>
2019-12-18 13:14:37 -07:00
<div className="panel-top with-button" style={{ marginTop: 0 }}>
2019-12-18 12:48:48 -07:00
<div className="thin-search-wrapper">
<div className="text-input-wrapper">
<i className="fa fa-search" />
<input
value={this.props.searchTerm || ""}
2019-12-18 13:14:37 -07:00
onChange={({ currentTarget }) => {
updateSearchTerm(currentTarget.value);
}}
2019-12-18 12:48:48 -07:00
type="text"
placeholder={t("Search sequences")} />
</div>
</div>
2019-12-18 13:14:37 -07:00
<AddFolderBtn />
2019-12-18 12:48:48 -07:00
<ToggleFolderBtn
expanded={this.state.toggleDirection}
onClick={this.toggleAll} />
<AddSequence />
</div>
2019-12-17 16:37:05 -07:00
<DropFolderHereBtn
onClick={() => this.endSequenceMove(0)}
active={!!this.state.movedSequenceUuid} />
2019-12-18 10:33:23 -07:00
<this.Graph />
<ul> {this.rootSequences()} </ul>
</div>;
}
2019-11-22 10:43:30 -07:00
}