diff --git a/app/actions/api.ts b/app/actions/api.ts index a5cc3a79..82263a29 100644 --- a/app/actions/api.ts +++ b/app/actions/api.ts @@ -1,7 +1,7 @@ import { Action } from 'redux' import { CALL_API, ApiAction, ApiActionThunk, chainSuccess } from '../store/api' -import { DatasetSummary, ComponentStatus, ComponentState, WorkingDataset } from '../models/store' +import { DatasetSummary, ComponentStatus, ComponentState, WorkingDataset, ComponentType } from '../models/store' import { Dataset, Commit } from '../models/dataset' import { openToast } from './ui' import { setWorkingDataset, setSelectedListItem } from './selections' @@ -568,3 +568,32 @@ export function linkDataset (peername: string, name: string, dir: string): ApiAc return response } } + +export function discardChanges (component: ComponentType): ApiActionThunk { + return async (dispatch, getState) => { + const { selections } = getState() + const { peername, name } = selections + let response: Action + + try { + const action = { + type: 'restore', + [CALL_API]: { + endpoint: 'restore', + method: 'POST', + segments: { + peername, + name + }, + params: { + component + } + } + } + response = await dispatch(action) + } catch (action) { + throw action + } + return response + } +} diff --git a/app/components/ComponentList.tsx b/app/components/ComponentList.tsx index d2d3b54d..9e3f2978 100644 --- a/app/components/ComponentList.tsx +++ b/app/components/ComponentList.tsx @@ -1,10 +1,14 @@ import * as React from 'react' import { Action } from 'redux' import classNames from 'classnames' -import { DatasetStatus, ComponentType } from '../models/store' +import { clipboard, shell, MenuItemConstructorOptions } from 'electron' +import ContextMenuArea from 'react-electron-contextmenu' +import { ApiActionThunk } from '../store/api' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { faTags, faArchive, faTh, IconDefinition } from '@fortawesome/free-solid-svg-icons' +import { DatasetStatus, ComponentType } from '../models/store' + interface StatusDotProps { status: string | undefined } @@ -78,8 +82,10 @@ interface ComponentListProps { status: DatasetStatus selectedComponent: string onComponentClick: (type: ComponentType, activeTab: string) => Action + discardChanges?: (component: ComponentType) => ApiActionThunk selectionType: ComponentType isLinked?: boolean + linkpath?: string } const components = [ @@ -113,7 +119,9 @@ const ComponentList: React.FunctionComponent = (props: Compo selectedComponent, onComponentClick, selectionType, - isLinked + isLinked, + discardChanges, + linkpath } = props return ( @@ -132,7 +140,7 @@ const ComponentList: React.FunctionComponent = (props: Compo filename = filepath.substring((filepath.lastIndexOf('/') + 1)) } - return ( + const fileRow = ( = (props: Compo onClick={onComponentClick} /> ) + + if (discardChanges && linkpath) { + const menuItems: MenuItemConstructorOptions[] = [ + { + label: 'Open in Finder', + click: () => { shell.showItemInFolder(`${linkpath}/${filepath}`) } + }, + { + label: 'Copy File Path', + click: () => { clipboard.writeText(`${linkpath}/${filepath}`) } + } + ] + + // add discard changes option of file is modified + if (fileStatus !== 'unmodified') { + menuItems.unshift({ + label: 'Discard Changes...', + click: () => { discardChanges(name as ComponentType) } + }, + { + type: 'separator' + }) + } + + return ( + + {fileRow} + + ) + } else { + return fileRow + } } else { return ( Action unpublishDataset: (dataset: WorkingDataset) => Action signout: () => Action + discardChanges: (component: ComponentType) => ApiActionThunk } interface DatasetState { @@ -218,7 +220,7 @@ export default class Dataset extends React.Component { // don't use isLinked from selections const isLinked = workingDataset.linkpath !== '' - const { history, status, path } = workingDataset + const { status } = workingDataset // actions const { @@ -227,8 +229,8 @@ export default class Dataset extends React.Component { setSidebarWidth, setSelectedListItem, fetchWorkingHistory, - // linkDataset, - signout + signout, + discardChanges } = this.props const linkButton = isLinked ? ( @@ -318,16 +320,15 @@ export default class Dataset extends React.Component { maximumWidth={495} >
diff --git a/app/components/DatasetSidebar.tsx b/app/components/DatasetSidebar.tsx index e4751d37..3e4b79af 100644 --- a/app/components/DatasetSidebar.tsx +++ b/app/components/DatasetSidebar.tsx @@ -41,29 +41,29 @@ const HistoryListItem: React.FunctionComponent = (props) = interface DatasetSidebarProps { activeTab: string - path: string selectedComponent: string selectedCommit: string - history: WorkingDataset['history'] - status: WorkingDataset['status'] isLinked: boolean onTabClick: (activeTab: string) => Action onListItemClick: (type: ComponentType, activeTab: string) => Action fetchWorkingHistory: (page?: number, pageSize?: number) => ApiActionThunk + discardChanges: (component: ComponentType) => ApiActionThunk + workingDataset: WorkingDataset } const DatasetSidebar: React.FunctionComponent = ({ activeTab, - path, selectedComponent, selectedCommit, - history, - status, onTabClick, onListItemClick, fetchWorkingHistory, - isLinked + isLinked, + discardChanges, + workingDataset }) => { + const { path, linkpath, history, status } = workingDataset + const historyLoaded = !!history const statusLoaded = !!status @@ -118,6 +118,8 @@ const DatasetSidebar: React.FunctionComponent = ({ onComponentClick={onListItemClick} selectionType={'component' as ComponentType} isLinked={isLinked} + linkpath={linkpath} + discardChanges={discardChanges} />
diff --git a/app/containers/DatasetContainer.tsx b/app/containers/DatasetContainer.tsx index f3f9e34e..ebe4af9c 100644 --- a/app/containers/DatasetContainer.tsx +++ b/app/containers/DatasetContainer.tsx @@ -10,7 +10,8 @@ import { fetchWorkingStatus, fetchWorkingHistory, publishDataset, - unpublishDataset + unpublishDataset, + discardChanges } from '../actions/api' import { @@ -70,7 +71,8 @@ const DatasetContainer = connect( resetOtherComponents, publishDataset, unpublishDataset, - signout + signout, + discardChanges }, mergeProps )(Dataset) diff --git a/app/containers/DatasetSidebarContainer.tsx b/app/containers/DatasetSidebarContainer.tsx new file mode 100644 index 00000000..e69de29b diff --git a/app/main.development.js b/app/main.development.js index 6bfdcdf2..e1f724c7 100644 --- a/app/main.development.js +++ b/app/main.development.js @@ -56,11 +56,6 @@ const setMenuItemEnabled = (menuItemIds, enabled) => { }) } -const setMenuItemLabel = (menuItemId, label) => { - const menu = Menu.getApplicationMenu() - menu.getMenuItemById(menuItemId).label = label -} - app.on('ready', () => installExtensions() .then(() => { diff --git a/package.json b/package.json index ddf8c5c8..b09e746c 100644 --- a/package.json +++ b/package.json @@ -192,7 +192,8 @@ "moment": "2.24.0", "react": "16.8.6", "react-dom": "16.8.6", - "react-json-view": "^1.19.1", + "react-electron-contextmenu": "1.0.0", + "react-json-view": "1.19.1", "react-redux": "7.1.0", "react-router": "5.0.1", "react-router-dom": "5.0.1", diff --git a/yarn.lock b/yarn.lock index 4d3b22fc..d9e1eec6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6291,6 +6291,11 @@ react-dom@16.8.6: prop-types "^15.6.2" scheduler "^0.13.6" +react-electron-contextmenu@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/react-electron-contextmenu/-/react-electron-contextmenu-1.0.0.tgz#035291edc6ee7e98d1ff4d7074c2cd8035e575ea" + integrity sha1-A1KR7cbufpjR/01wdMLNgDXldeo= + react-hot-loader@4.12.6: version "4.12.6" resolved "https://registry.yarnpkg.com/react-hot-loader/-/react-hot-loader-4.12.6.tgz#bd7a41501b02576638031482474a72bac453587d"