Skip to content

Commit

Permalink
feat(Export Modal): ExportVersion modal component
Browse files Browse the repository at this point in the history
This also adds `exportPath` to the state tree and local storage, so we remember the last place the user wanted to store and export
  • Loading branch information
ramfox committed Oct 3, 2019
1 parent 51544e1 commit f38cad7
Show file tree
Hide file tree
Showing 9 changed files with 207 additions and 12 deletions.
10 changes: 9 additions & 1 deletion app/actions/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import {
UI_SET_MODAL,
UI_SIGNOUT,
UI_HIDE_COMMIT_NUDGE,
UI_SET_DATASET_DIR_PATH
UI_SET_DATASET_DIR_PATH,
UI_SET_EXPORT_PATH
} from '../reducers/ui'

import { ToastType } from '../models/store'
Expand Down Expand Up @@ -82,3 +83,10 @@ export const setDatasetDirPath = (path: string) => {
path
}
}

export const setExportPath = (path: string) => {
return {
type: UI_SET_EXPORT_PATH,
path
}
}
19 changes: 19 additions & 0 deletions app/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Toast from './Toast'
import AppError from './AppError'
import AppLoading from './AppLoading'
import AddDataset from './modals/AddDataset'
import ExportVersion from './modals/ExportVersion'
import LinkDataset from './modals/LinkDataset'
import RemoveDataset from './modals/RemoveDataset'
import CreateDataset from './modals/CreateDataset'
Expand Down Expand Up @@ -44,6 +45,8 @@ export interface AppProps {
toast: IToast
modal: Modal
workingDataset: Dataset
exportPath: string
setExportPath: (path: string) => Action
children: JSX.Element[] | JSX.Element
bootstrap: () => Promise<ApiAction>
fetchMyDatasets: (page?: number, pageSize?: number) => Promise<ApiAction>
Expand Down Expand Up @@ -183,6 +186,22 @@ class App extends React.Component<AppProps, AppState> {
break
}

case ModalType.ExportVersion: {
modalComponent = (
<ExportVersion
peername={modal.peername}
name={modal.name}
path={modal.path}
title={modal.title}
timestamp={modal.timestamp}
exportPath={this.props.exportPath}
setExportPath={this.props.setExportPath}
onDismissed={async () => setModal(noModalObject)}
/>
)
break
}

case ModalType.LinkDataset: {
const { peername, name } = this.props.workingDataset
modalComponent = (
Expand Down
16 changes: 13 additions & 3 deletions app/components/DatasetSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import Spinner from './chrome/Spinner'

import { WorkingDataset, ComponentType, Selections } from '../models/store'
import ContextMenuArea from 'react-electron-contextmenu'
import { MenuItemConstructorOptions, ipcRenderer } from 'electron'
import { MenuItemConstructorOptions } from 'electron'
import { ModalType, Modal } from '../models/modals'

interface HistoryListItemProps {
path: string
Expand Down Expand Up @@ -48,6 +49,7 @@ export interface DatasetSidebarProps {
selections: Selections
workingDataset: WorkingDataset
hideCommitNudge: boolean
setModal: (modal: Modal) => void
setActiveTab: (activeTab: string) => Action
setSelectedListItem: (type: ComponentType, activeTab: string) => Action
fetchWorkingHistory: (page?: number, pageSize?: number) => ApiActionThunk
Expand All @@ -64,7 +66,8 @@ const DatasetSidebar: React.FunctionComponent<DatasetSidebarProps> = (props) =>
setSelectedListItem,
fetchWorkingHistory,
discardChanges,
setHideCommitNudge
setHideCommitNudge,
setModal
} = props

const { fsiPath, history, status, components } = workingDataset
Expand Down Expand Up @@ -179,7 +182,14 @@ const DatasetSidebar: React.FunctionComponent<DatasetSidebarProps> = (props) =>
{
label: 'Export this version',
click: () => {
ipcRenderer.send('export', `http://localhost:2503/export/${peername}/${name}/at/${path}?download=true&all=true`)
setModal({
type: ModalType.ExportVersion,
peername: peername || '',
name: name || '',
path: path || '',
timestamp: timestamp,
title: title
})
}
}
]
Expand Down
134 changes: 134 additions & 0 deletions app/components/modals/ExportVersion.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import * as React from 'react'
import { Action } from 'redux'
import { remote, ipcRenderer } from 'electron'

import Modal from './Modal'
import TextInput from '../form/TextInput'
import Buttons from './Buttons'
import moment from 'moment'
import ButtonInput from '../form/ButtonInput'

interface ExportVersionProps {
onDismissed: () => void
peername: string
name: string
path: string
title: string
exportPath: string
timestamp: Date
setExportPath: (path: string) => Action
}

const ExportVersion: React.FunctionComponent<ExportVersionProps> = (props) => {
const {
onDismissed,
peername,
name,
path,
title,
timestamp,
exportPath: persistedExportPath,
setExportPath: saveExportPath
} = props

const pathUrl = path === '' ? '' : `/at/${path}`
const exportUrl = `http://localhost:2503/export/${peername}/${name}${pathUrl}?download=true&all=true`
const [exportPath, setExportPath] = React.useState(persistedExportPath)
const [dismissable, setDismissable] = React.useState(true)
const [buttonDisabled, setButtonDisabled] = React.useState(true)

const handleSubmit = () => {
ipcRenderer.send('export', { url: exportUrl, directory: exportPath })
onDismissed()
}

React.useEffect(() => {
// persist the exportPath
if (exportPath !== '') {
saveExportPath(exportPath)
if (buttonDisabled) setButtonDisabled(false)
} else {
setButtonDisabled(true)
}
}, [exportPath])

const handleChanges = (name: string, value: any) => {
if (value[value.length - 1] === ' ') {

}
}

const handlePathPickerDialog = (showFunc: () => void) => {
new Promise(resolve => {
setDismissable(false)
resolve()
})
.then(() => showFunc())
.then(() => setDismissable(true))
}

const showDirectoryPicker = () => {
const window = remote.getCurrentWindow()
const directory: string[] | undefined = remote.dialog.showOpenDialog(window, {
properties: ['createDirectory', 'openDirectory']
})

if (!directory) {
return
}

const selectedPath = directory[0]

setExportPath(selectedPath)
}

return (
<Modal
id="export_modal"
title={'Export a Version of this Dataset'}
onDismissed={onDismissed}
onSubmit={() => {}}
dismissable={dismissable}
setDismissable={setDismissable}
>
<div className='content-wrap'>
<div>
<div className='content'>
<div className='margin-bottom'>
<p><strong>{peername}/{name}</strong></p>
<p>{title} - <i>{moment(timestamp).format('MMMM Do YYYY, h:mm:ss a')}</i></p>
</div>
<div className='flex-space-between'>
<TextInput
name='savePath'
label='Export Folder'
labelTooltip='Qri will export the dataset to this folder'
tooltipFor='modal-tooltip'
type=''
value={exportPath}
onChange={handleChanges}
maxLength={600}
/>
<div className='margin-left'><ButtonInput id='chooseSavePath' onClick={() => handlePathPickerDialog(showDirectoryPicker)} >Choose...</ButtonInput></div>
</div>
</div>
</div>
<p className='submit-message'>
{!buttonDisabled && (
<span>Qri will save a zip of this dataset version to {exportPath} </span>
)}
</p>
</div>
<Buttons
cancelText='cancel'
onCancel={onDismissed}
submitText='Export Version'
onSubmit={handleSubmit}
disabled={buttonDisabled}
loading={false}
/>
</Modal>
)
}

export default ExportVersion
9 changes: 6 additions & 3 deletions app/containers/AppContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import {
setQriCloudAuthenticated,
closeToast,
setModal,
setDatasetDirPath
setDatasetDirPath,
setExportPath
} from '../actions/ui'

import {
Expand All @@ -41,7 +42,7 @@ const AppContainer = connect(
const loading = connection.apiConnection === 0 || session.isLoading
const hasDatasets = myDatasets.value.length !== 0
const { id: sessionID, peername } = session
const { toast, modal, datasetDirPath } = ui
const { toast, modal, datasetDirPath, exportPath } = ui
return {
hasDatasets,
loading,
Expand All @@ -52,7 +53,8 @@ const AppContainer = connect(
modal,
workingDataset,
apiConnection,
datasetDirPath
datasetDirPath,
exportPath
}
},
{
Expand All @@ -67,6 +69,7 @@ const AppContainer = connect(
closeToast,
pingApi,
setWorkingDataset,
setExportPath,
setModal,
publishDataset,
unpublishDataset,
Expand Down
4 changes: 2 additions & 2 deletions app/main.development.js
Original file line number Diff line number Diff line change
Expand Up @@ -470,9 +470,9 @@ app.on('ready', () =>
})

// catch export events
ipcMain.on('export', async (e, exportPath) => {
ipcMain.on('export', async (e, { url, directory }) => {
const win = BrowserWindow.getFocusedWindow()
await download(win, exportPath, { saveAs: true })
await download(win, url, { directory })
})

ipcMain.on('block-menus', (e, blockMenus) => {
Expand Down
13 changes: 12 additions & 1 deletion app/models/modals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ export enum ModalType {
LinkDataset,
RemoveDataset,
PublishDataset,
UnpublishDataset
UnpublishDataset,
ExportVersion
}

interface CreateDatasetModal {
Expand Down Expand Up @@ -39,6 +40,15 @@ export interface RemoveDatasetModal {
fsiPath: string
}

export interface ExportVersionModal {
type: ModalType.ExportVersion
peername: string
name: string
path: string
timestamp: Date
title: string
}

export interface HideModal {
type: ModalType.NoModal
}
Expand All @@ -50,3 +60,4 @@ export type Modal = CreateDatasetModal
| PublishDataset
| UnpublishDataset
| HideModal
| ExportVersionModal
1 change: 1 addition & 0 deletions app/models/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export interface UI {
blockMenus: boolean
hideCommitNudge: boolean
datasetDirPath: string
exportPath: string
}

export type SelectedComponent = 'meta' | 'body' | 'schema' | ''
Expand Down
13 changes: 11 additions & 2 deletions app/reducers/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ export const UI_CLOSE_TOAST = 'UI_CLOSE_TOAST'
export const UI_SET_MODAL = 'UI_SET_MODAL'
export const UI_SIGNOUT = 'UI_SIGNOUT'
export const UI_HIDE_COMMIT_NUDGE = 'UI_HIDE_COMMIT_NUDGE'
export const UI_SET_DATASET_DIR_PATH = 'UI_SET_DATASET_PATH'
export const UI_SET_DATASET_DIR_PATH = 'UI_SET_DATASET_DIR_PATH'
export const UI_SET_EXPORT_PATH = 'UI_SET_EXPORT_PATH'

export const UNAUTHORIZED = 'UNAUTHORIZED'

Expand Down Expand Up @@ -47,7 +48,8 @@ const initialState = {
toast: defaultToast,
blockMenus: true,
hideCommitNudge: store().getItem(hideCommitNudge) === 'true',
datasetDirPath: store().getItem('datasetDirPath') || ''
datasetDirPath: store().getItem('datasetDirPath') || '',
exportPath: store().getItem('exportPath') || ''
}

// send an event to electron to block menus on first load
Expand Down Expand Up @@ -171,6 +173,13 @@ export default (state = initialState, action: AnyAction) => {
datasetDirPath: action.path
}

case UI_SET_EXPORT_PATH:
store().setItem('exportPath', action.path)
return {
...state,
exportPath: action.path
}

case ADD_SUCC:
case INIT_SUCC:
const { peername, name } = action.payload.data
Expand Down

0 comments on commit f38cad7

Please sign in to comment.