Skip to content

Commit

Permalink
Merge pull request #818 from 200ok-ch/feat/create-new-org-file
Browse files Browse the repository at this point in the history
feat: Create new file from file browser
  • Loading branch information
branch14 authored Jun 14, 2022
2 parents 7677a6b + c7f7079 commit 0cb5745
Show file tree
Hide file tree
Showing 8 changed files with 160 additions and 11 deletions.
4 changes: 4 additions & 0 deletions changelog.org
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ All user visible changes to organice will be documented in this file.

When there are updates to the changelog, you will be notified and see a 'gift' icon appear on the top right corner.

* [2022-06-14 Tue]
** Added
- Create new file from file browser
- PR: https://github.com/200ok-ch/organice/pull/818
* [2022-06-13 Mon]
** Added

Expand Down
6 changes: 6 additions & 0 deletions src/actions/org.js
Original file line number Diff line number Diff line change
Expand Up @@ -710,3 +710,9 @@ export const deleteBookmark = (context, bookmark) => ({
context,
bookmark,
});

export const addNewFile = (path, content) => ({
type: 'ADD_NEW_FILE',
path,
content,
});
34 changes: 32 additions & 2 deletions src/actions/sync_backend.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,14 @@ export const signOut = () => (dispatch, getState) => {
export const setCurrentFileBrowserDirectoryListing = (
directoryListing,
hasMore,
additionalSyncBackendState
additionalSyncBackendState,
path
) => ({
type: 'SET_CURRENT_FILE_BROWSER_DIRECTORY_LISTING',
directoryListing,
hasMore,
additionalSyncBackendState,
path,
});

export const setIsLoadingMoreDirectoryListing = (isLoadingMore) => ({
Expand All @@ -58,7 +60,9 @@ export const getDirectoryListing = (path) => (dispatch, getState) => {
client
.getDirectoryListing(path)
.then(({ listing, hasMore, additionalSyncBackendState }) => {
dispatch(setCurrentFileBrowserDirectoryListing(listing, hasMore, additionalSyncBackendState));
dispatch(
setCurrentFileBrowserDirectoryListing(listing, hasMore, additionalSyncBackendState, path)
);
dispatch(hideLoadingMessage());
})
.catch((error) => {
Expand Down Expand Up @@ -123,3 +127,29 @@ export const downloadFile = (path) => {
});
};
};

/**
* @param {String} path Returns the directory name of `path`.
*/
function dirName(path) {
return path.substring(0, path.lastIndexOf('/') + 1);
}

export const createFile = (path, content) => {
return (dispatch, getState) => {
dispatch(setLoadingMessage(`Creating file: ${path}`));
getState()
.syncBackend.get('client')
.createFile(path, content)
.then(() => {
dispatch(setLastSyncAt(addSeconds(new Date(), 5), path));
dispatch(hideLoadingMessage());
dispatch(getDirectoryListing(dirName(path)));
})
.catch(() => {
dispatch(hideLoadingMessage());
dispatch(setIsLoading(false, path));
dispatch(setOrgFileErrorMessage(`File ${path} not found`));
});
};
};
86 changes: 86 additions & 0 deletions src/components/FileBrowser/components/ActionDrawer/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// INFO: There's an <ActionDrawer> component within the <OrgFile>
// component, as well.

import React, { Fragment } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import _ from 'lodash';

import './../../../OrgFile/components/ActionDrawer/stylesheet.css';

import * as orgActions from '../../../../actions/org';
import * as syncActions from '../../../../actions/sync_backend';

import ActionButton from '../../../OrgFile/components/ActionDrawer/components/ActionButton';

const ensureCompleteFilename = (fileName) => {
return fileName.endsWith('.org') ? fileName : `${fileName}.org`;
};

const ActionDrawer = ({ org, files, syncBackend, path }) => {
const handleAddNewOrgFileClick = () => {
const content = '* First header\nExtend the file from here.';
let fileName = prompt('New filename:');

if (!fileName) return;

fileName = ensureCompleteFilename(fileName);
let newPath = `${path}/${fileName}`;

if (_.includes(files, newPath)) {
alert('File already exists. Aborting.');
} else {
syncBackend.createFile(newPath, content);
org.addNewFile(newPath, content);
}
};

const mainButtonStyle = {
opacity: 1,
position: 'relative',
zIndex: 1,
};

return (
<div className="action-drawer-container nice-scroll">
{
<Fragment>
<div
className="action-drawer__capture-buttons-container"
style={{
marginLeft: 'auto',
marginRight: 0,
}}
>
<ActionButton
iconName="plus"
isDisabled={false}
onClick={handleAddNewOrgFileClick}
style={mainButtonStyle}
tooltip="Add new Org file"
/>
</div>
</Fragment>
}
</div>
);
};

const mapStateToProps = (state) => {
const path = state.syncBackend.get('currentPath');
let files = state.syncBackend.getIn(['currentFileBrowserDirectoryListing', 'listing']);
files = files ? files.map((e) => e.get('id')).toJS() : [];
return {
path,
files,
};
};

const mapDispatchToProps = (dispatch) => {
return {
org: bindActionCreators(orgActions, dispatch),
syncBackend: bindActionCreators(syncActions, dispatch),
};
};

export default connect(mapStateToProps, mapDispatchToProps)(ActionDrawer);
4 changes: 4 additions & 0 deletions src/components/FileBrowser/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { bindActionCreators } from 'redux';

import { Link } from 'react-router-dom';

import ActionDrawer from './components/ActionDrawer';

import './stylesheet.css';

import classNames from 'classnames';
Expand Down Expand Up @@ -45,6 +47,8 @@ const FileBrowser = ({
<h3 className="file-browser__header">Directory: {isTopLevelDirectory ? '/' : path}</h3>
)}

<ActionDrawer />

<ul className="file-browser__file-list">
{!isTopLevelDirectory && (
<Link to={`/files${getParentDirectoryPath()}`}>
Expand Down
14 changes: 14 additions & 0 deletions src/reducers/org.js
Original file line number Diff line number Diff line change
Expand Up @@ -1371,6 +1371,18 @@ const deleteBookmark = (state, { context, bookmark }) => {
);
};

const addNewFile = (state, { path, content }) => {
const parsedFile = parseOrg(content);

return state
.setIn(['files', path, 'headers'], parsedFile.get('headers'))
.setIn(['files', path, 'todoKeywordSets'], parsedFile.get('todoKeywordSets'))
.setIn(['files', path, 'fileConfigLines'], parsedFile.get('fileConfigLines'))
.setIn(['files', path, 'linesBeforeHeadings'], parsedFile.get('linesBeforeHeadings'))
.setIn(['files', path, 'activeClocks'], parsedFile.get('activeClocks'))
.setIn(['files', path, 'isDirty'], false);
};

const addNewEmptyFileSetting = (state) =>
state.update('fileSettings', (settings) =>
settings.push(
Expand Down Expand Up @@ -1543,6 +1555,8 @@ const reducer = (state, action) => {
return saveBookmark(state, action);
case 'DELETE_BOOKMARK':
return deleteBookmark(state, action);
case 'ADD_NEW_FILE':
return addNewFile(state, action);
default:
return state;
}
Expand Down
18 changes: 10 additions & 8 deletions src/reducers/sync_backend.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@ import { Map } from 'immutable';
const signOut = (state) => state.set('isAuthenticated', false).set('client', null);

const setCurrentFileBrowserDirectoryListing = (state, action) =>
state.set(
'currentFileBrowserDirectoryListing',
Map({
listing: action.directoryListing,
hasMore: action.hasMore,
additionalSyncBackendState: action.additionalSyncBackendState,
})
);
state
.set(
'currentFileBrowserDirectoryListing',
Map({
listing: action.directoryListing,
hasMore: action.hasMore,
additionalSyncBackendState: action.additionalSyncBackendState,
})
)
.set('currentPath', action.path);

const setIsLoadingMoreDirectoryListing = (state, action) =>
state
Expand Down
5 changes: 4 additions & 1 deletion src/sync_backend_clients/webdav_sync_backend_client.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,10 @@ export default (url, login, password) => {

const uploadFile = (path, contents) =>
new Promise((resolve, reject) =>
webdavClient.putFileContents(path, contents, { overwrite: true }).then(resolve).catch(reject)
webdavClient
.putFileContents(path, contents, { overwrite: true })
.then(resolve())
.catch(reject)
);

const updateFile = uploadFile;
Expand Down

0 comments on commit 0cb5745

Please sign in to comment.