Skip to content

Commit

Permalink
Merge pull request #188 from guardian/pm-copy-clipboard
Browse files Browse the repository at this point in the history
Add copy to clipboard option to workspace context menu
  • Loading branch information
philmcmahon authored Dec 22, 2023
2 parents 5d36306 + dc1f225 commit b6bef38
Showing 1 changed file with 58 additions and 5 deletions.
63 changes: 58 additions & 5 deletions frontend/src/js/components/workspace/Workspaces.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { listUsers } from '../../actions/users/listUsers';
import DocumentIcon from 'react-icons/lib/ti/document';
import {Icon, Loader, Menu, Popup} from 'semantic-ui-react';
import WorkspaceSummary from './WorkspaceSummary';
import { ColumnsConfig, isTreeLeaf, isTreeNode, TreeEntry, TreeLeaf } from '../../types/Tree';
import {ColumnsConfig, isTreeLeaf, isTreeNode, TreeEntry, TreeLeaf} from '../../types/Tree';
import {isWorkspaceLeaf, Workspace, WorkspaceEntry} from '../../types/Workspaces';
import { GiantState } from '../../types/redux/GiantState';
import { GiantDispatch } from '../../types/redux/GiantDispatch';
Expand Down Expand Up @@ -73,6 +73,13 @@ type State = {
}
}

type ContextMenuEntry = {
key: string
content: string;
icon: string;

}

class WorkspacesUnconnected extends React.Component<Props, State> {

stringSort = (a: string, b: string) => {
Expand Down Expand Up @@ -496,12 +503,46 @@ class WorkspacesUnconnected extends React.Component<Props, State> {
});
};

/**
* Searches through tree beginning at startNode for entryId, if successful returns an array of nodes between startNode and entryId
* @param entryId
* @param startNode
*/
getEntryTreeNodes (entryId: string, startNode: TreeEntry<WorkspaceEntry>): TreeEntry<WorkspaceEntry>[] | undefined {
if (startNode.id === entryId) {
return [startNode]
}
if (isTreeNode(startNode)) {
for (const child of startNode.children) {
const result = this.getEntryTreeNodes(entryId, child)
if (result !== undefined) {
return [startNode, ...result]
}
}
}
return undefined
}

getEntryPath (entryId: string, workspaceRootNode: TreeEntry<WorkspaceEntry>): string {
const pathArray = this.getEntryTreeNodes(entryId, workspaceRootNode)
if (pathArray) {
const path = pathArray.map(p => p.name).join("/")
console.log(path)
return path
}
return "unknown"
}


renderContextMenu(entry: TreeEntry<WorkspaceEntry>, positionX: number, positionY: number, currentUser: PartialUser) {
renderContextMenu(entry: TreeEntry<WorkspaceEntry>, positionX: number, positionY: number, currentUser: PartialUser, workspace: Workspace) {
const copyFilenameContent = "Copy file name"
const copyFilePathContent = "Copy file path"
const items = [
{key : "copyFilename", content: copyFilenameContent, icon: "copy"},
{key : "copyFilePath", content: copyFilePathContent, icon: "copy"},
// or 'pencil alternate'
{ key: "rename", content: "Rename", icon: "pen square" },
{ key: "remove", content: "Remove from workspace", icon: "trash" },
{ key: "remove", content: "Remove from workspace", icon: "trash" }
];

if (entry.data.addedBy.username === currentUser.username && isWorkspaceLeaf(entry.data)) {
Expand All @@ -519,6 +560,7 @@ class WorkspacesUnconnected extends React.Component<Props, State> {
vertical
onItemClick={(e, menuItemProps) => {
const workspaceId = this.props.match.params.id;
let closeMenuDelay = 0;
if (menuItemProps.content === 'Rename') {
this.props.setEntryBeingRenamed(entry);
}
Expand All @@ -528,6 +570,16 @@ class WorkspacesUnconnected extends React.Component<Props, State> {
this.props.resetFocusedAndSelectedEntries();
}

if (menuItemProps.content === copyFilenameContent || menuItemProps.content === copyFilePathContent) {
const text = menuItemProps.content === copyFilenameContent ? entry.name : this.getEntryPath(entry.id, workspace.rootNode);
navigator.clipboard.writeText(text);
const menuItem = items.find((i: ContextMenuEntry) => i.content === menuItemProps.content)
if (menuItem) {
menuItem.content = 'Copied!'
menuItem.icon = 'check'
closeMenuDelay = 700;
}
}

if (menuItemProps.content === "Delete file") {
this.setState({
Expand All @@ -542,7 +594,7 @@ class WorkspacesUnconnected extends React.Component<Props, State> {
if (menuItemProps.content === 'Reprocess source file' && (isWorkspaceLeaf(entry.data))) {
this.props.reprocessBlob(workspaceId, entry.data.uri)
}
this.closeContextMenu();
setTimeout(() => this.closeContextMenu(), closeMenuDelay);
}}
/>
</DetectClickOutside>;
Expand Down Expand Up @@ -640,7 +692,8 @@ class WorkspacesUnconnected extends React.Component<Props, State> {
this.state.contextMenu.entry,
this.state.contextMenu.positionX,
this.state.contextMenu.positionY,
this.props.currentUser
this.props.currentUser,
this.props.currentWorkspace
)
: null
}
Expand Down

0 comments on commit b6bef38

Please sign in to comment.