diff --git a/packages/client-react/.env.js b/packages/client-react/.env.js
index 05f448a29..fb28ff93a 100644
--- a/packages/client-react/.env.js
+++ b/packages/client-react/.env.js
@@ -3,7 +3,7 @@
module.exports = {
HOST: process.env.HOST ? process.env.HOST : 'localhost',
PORT: process.env.PORT ? process.env.PORT : 3000,
- SERVER_URL: process.env.SERVER_URL ? process.env.SERVER_URL : 'http://localhost:8080/myfilemanager',
+ FILE_SERVER_URL: process.env.FILE_SERVER_URL ? process.env.FILE_SERVER_URL : 'http://localhost:3020',// 'http://localhost:8080/myfilemanager',
CLIENT_ID: process.env.CLIENT_ID,
API_KEY: process.env.API_KEY
diff --git a/packages/client-react/config/webpack.config.js b/packages/client-react/config/webpack.config.js
index 69904b269..700a1b963 100644
--- a/packages/client-react/config/webpack.config.js
+++ b/packages/client-react/config/webpack.config.js
@@ -163,7 +163,8 @@ module.exports = {
}
}],
include: [
- path.resolve(__dirname, '../src')
+ path.resolve(__dirname, '../src'),
+ path.resolve(__dirname, '../www')
]
}
]
diff --git a/packages/client-react/package.json b/packages/client-react/package.json
index 537d5b276..0b29df2d0 100644
--- a/packages/client-react/package.json
+++ b/packages/client-react/package.json
@@ -41,7 +41,7 @@
"babel-cli": "6.26.0",
"babel-core": "6.26.0",
"babel-eslint": "8.2.3",
- "babel-loader": "6.4.1",
+ "babel-loader": "7.1.5",
"babel-plugin-lodash": "3.2.11",
"babel-plugin-transform-decorators-legacy": "1.3.4",
"babel-plugin-transform-runtime": "6.23.0",
@@ -86,10 +86,13 @@
"source-map-loader": "0.1.6",
"style-loader": "0.13.2",
"url-loader": "0.5.8",
- "webpack": "2.2.1",
+ "webpack": "2.7.0",
"webpack-bundle-analyzer": "2.8.2",
"webpack-dev-middleware": "1.10.1",
- "write-file-webpack-plugin": "3.4.2"
+ "write-file-webpack-plugin": "3.4.2",
+ "http-proxy-middleware": "2.0.3",
+ "react-ace": "10.1.0"
+
},
"dependencies": {
"@opuscapita/react-svg": "2.0.1",
diff --git a/packages/client-react/src/client/components/Dialog/Dialog.react.js b/packages/client-react/src/client/components/Dialog/Dialog.react.js
index cc13912bd..8dcda3126 100644
--- a/packages/client-react/src/client/components/Dialog/Dialog.react.js
+++ b/packages/client-react/src/client/components/Dialog/Dialog.react.js
@@ -4,11 +4,13 @@ import './Dialog.less';
const propTypes = {
autofocus: PropTypes.bool,
- onHide: PropTypes.func
+ onHide: PropTypes.func,
+ className: PropTypes.string
};
const defaultProps = {
autofocus: false,
- onHide: () => {}
+ onHide: () => {},
+ className: "oc-fm--dialog"
};
export default
@@ -26,7 +28,7 @@ class Dialog extends Component {
return (
(autofocus && ref && ref.focus())}
- className="oc-fm--dialog"
+ className={this.props.className}
onKeyDown={this.handleKeyDown}
onClick={e => e.stopPropagation()}
onMouseDown={e => e.stopPropagation()}
diff --git a/packages/client-react/src/client/components/EditDialog/EditDialog.DOCUMENTATION.md b/packages/client-react/src/client/components/EditDialog/EditDialog.DOCUMENTATION.md
new file mode 100644
index 000000000..8e550a209
--- /dev/null
+++ b/packages/client-react/src/client/components/EditDialog/EditDialog.DOCUMENTATION.md
@@ -0,0 +1,27 @@
+### Synopsis
+
+EditDialog is
+*Write here a short introduction and/or overview that explains **what** component is.*
+
+### Props Reference
+
+| Name | Type | Description |
+| ------------------------------ | :---------------------- | ----------------------------------------------------------- |
+| demoProp | string | Write a description of the property |
+
+### Code Example
+
+```
+
+
+
+```
+
+### Component Name
+
+EditDialog
+
+### License
+
+Apache License Version 2.0
+
diff --git a/packages/client-react/src/client/components/EditDialog/EditDialog.SCOPE.react.js b/packages/client-react/src/client/components/EditDialog/EditDialog.SCOPE.react.js
new file mode 100644
index 000000000..1341caf12
--- /dev/null
+++ b/packages/client-react/src/client/components/EditDialog/EditDialog.SCOPE.react.js
@@ -0,0 +1,24 @@
+/*
+ What is a SCOPE file. See documentation here:
+ https://github.com/OpusCapita/react-showroom-client/blob/master/docs/scope-component.md
+*/
+
+import React, { Component } from 'react';
+import { showroomScopeDecorator } from '@opuscapita/react-showroom-client';
+
+@showroomScopeDecorator
+export default
+class EditDialogScope extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {};
+ }
+
+ render() {
+ return (
+
+ {this._renderChildren()}
+
+ );
+ }
+}
diff --git a/packages/client-react/src/client/components/EditDialog/EditDialog.less b/packages/client-react/src/client/components/EditDialog/EditDialog.less
new file mode 100644
index 000000000..290ed4d64
--- /dev/null
+++ b/packages/client-react/src/client/components/EditDialog/EditDialog.less
@@ -0,0 +1,61 @@
+.oc-fm-edit-dialog {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ text-align: center;
+ padding: 12px;
+ width: 92%;
+ height: 92%;
+// width: calc(100% - 10px);
+// height: calc(100% - 10px);
+ border-radius: 4px;
+ background: #fff;
+ position: relative;
+ box-shadow: rgba(0, 0, 0, 0.25) 0px 2px 16px, rgba(0, 0, 0, 0.15) 0px 1px 4px;
+
+ &:focus {
+ outline:none;
+ }
+}
+
+.oc-edit--dialog__content {
+ width: 100%;
+ max-width: 100%;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: flex-start;
+
+ &:focus {
+ outline: none;
+ }
+}
+
+.oc-edit--dialog__close-icon {
+ width: 24px;
+ height: 24px;
+ position: absolute;
+ top: 2px;
+ right: 2px;
+ &:hover {
+ background-color: #e0e0e0;
+ }
+}
+
+@font-face {
+ font-family : 'Droid Sans Mono';
+ src : url(https://themes.googleusercontent.com/static/fonts/droidsansmono/v5/ns-m2xQYezAtqh7ai59hJTwtzT4qNq-faudv5qbO9-U.eot);
+ src :
+ local('Droid Sans Mono'),
+ local('DroidSansMono'),
+ url(/font/DroidSansMono.eot) format('embedded-opentype'),
+ url(https://themes.googleusercontent.com/static/fonts/droidsansmono/v5/ns-m2xQYezAtqh7ai59hJTwtzT4qNq-faudv5qbO9-U.eot?#iefix) format('embedded-opentype'),
+ url(https://themes.googleusercontent.com/static/fonts/droidsansmono/v5/ns-m2xQYezAtqh7ai59hJTwtzT4qNq-faudv5qbO9-U.eot) format('embedded-opentype'),
+ url(/font/DroidSansMono.woff2) format('woff2'),
+ url(/font/DroidSansMono.woff) format('woff'),
+ url(https://themes.googleusercontent.com/static/fonts/droidsansmono/v5/ns-m2xQYezAtqh7ai59hJUYuTAAIFFn5GTWtryCmBQ4.woff) format('woff'),
+ local('Consolas');
+ font-style : normal;
+ font-weight : 400;
+}
diff --git a/packages/client-react/src/client/components/EditDialog/EditDialog.react.js b/packages/client-react/src/client/components/EditDialog/EditDialog.react.js
new file mode 100644
index 000000000..ce4e3c0ca
--- /dev/null
+++ b/packages/client-react/src/client/components/EditDialog/EditDialog.react.js
@@ -0,0 +1,254 @@
+import PropTypes from 'prop-types';
+import React, { Component } from 'react';
+import './EditDialog.less';
+import Dialog from '../Dialog';
+import FileSaveConfirmDialog from '../FileSaveConfirmDialog';
+import AceEditor from "react-ace";
+import Svg from '@opuscapita/react-svg/lib/SVG';
+import icons from './icons-svg';
+import {getModeForPath, modes, modesByName} from "ace-builds/src-noconflict/ext-modelist";
+
+// const languages = [
+// "javascript",
+// "java",
+// "python",
+// "xml",
+// "markdown",
+// "json",
+// "html",
+// "typescript",
+// "css",
+// "text",
+// "plain_text"
+// ];
+
+// languages.map(lang => {
+// try {
+// require(`ace-builds/src-noconflict/mode-${lang}`);
+// require(`ace-builds/src-noconflict/snippets/${lang}`);
+// } catch(ignore) {}
+// });
+
+// modes.map(mode => {
+// try {
+// require(`ace-builds/src-noconflict/mode-${mode.name}`);
+// require(`ace-builds/src-noconflict/snippets/${mode.name}`);
+// } catch(ignore) {}
+// });
+
+import 'ace-builds/src-noconflict/mode-javascript';
+import 'ace-builds/src-noconflict/snippets/javascript';
+
+import 'ace-builds/src-noconflict/mode-java';
+import 'ace-builds/src-noconflict/snippets/java';
+
+import 'ace-builds/src-noconflict/mode-python';
+import 'ace-builds/src-noconflict/snippets/python';
+
+import 'ace-builds/src-noconflict/mode-xml';
+import 'ace-builds/src-noconflict/snippets/xml';
+
+import 'ace-builds/src-noconflict/mode-json';
+import "ace-builds/src-noconflict/snippets/json";
+
+import 'ace-builds/src-noconflict/mode-html';
+import 'ace-builds/src-noconflict/snippets/html';
+
+import 'ace-builds/src-noconflict/mode-typescript';
+import 'ace-builds/src-noconflict/snippets/typescript';
+
+import 'ace-builds/src-noconflict/mode-css';
+import 'ace-builds/src-noconflict/snippets/css';
+
+import 'ace-builds/src-noconflict/mode-text';
+import 'ace-builds/src-noconflict/snippets/text';
+
+import 'ace-builds/src-noconflict/mode-plain_text';
+import 'ace-builds/src-noconflict/snippets/plain_text';
+
+import 'ace-builds/src-noconflict/mode-makefile';
+import 'ace-builds/src-noconflict/snippets/makefile';
+
+import 'ace-builds/src-noconflict/mode-markdown';
+import 'ace-builds/src-noconflict/snippets/markdown';
+
+import 'ace-builds/src-noconflict/mode-lua';
+import 'ace-builds/src-noconflict/snippets/lua';
+
+import 'ace-builds/src-noconflict/mode-jsx'
+import 'ace-builds/src-noconflict/snippets/jsx';
+
+
+//import "ace-builds/src-noconflict/theme-monokai";
+import 'ace-builds/src-noconflict/theme-dracula';
+
+//import 'ace-builds/src-noconflict/ext-beautify';
+import 'ace-builds/src-noconflict/ext-code_lens';
+// import 'ace-builds/src-noconflict/ext-elastic_tabstops_lite';
+// import 'ace-builds/src-noconflict/ext-emmet';
+import 'ace-builds/src-noconflict/ext-error_marker';
+import 'ace-builds/src-noconflict/ext-hardwrap';
+import 'ace-builds/src-noconflict/ext-keybinding_menu';
+import 'ace-builds/src-noconflict/ext-language_tools';
+import 'ace-builds/src-noconflict/ext-linking';
+//import 'ace-builds/src-noconflict/ext-modelist';
+import 'ace-builds/src-noconflict/ext-options';
+import 'ace-builds/src-noconflict/ext-prompt';
+import 'ace-builds/src-noconflict/ext-rtl';
+import 'ace-builds/src-noconflict/ext-searchbox';
+import 'ace-builds/src-noconflict/ext-settings_menu';
+//import 'ace-builds/src-noconflict/ext-spellcheck';
+//import 'ace-builds/src-noconflict/ext-split';
+//import 'ace-builds/src-noconflict/ext-static_highlight';
+//import 'ace-builds/src-noconflict/ext-statusbar';
+import 'ace-builds/src-noconflict/ext-textarea';
+//import 'ace-builds/src-noconflict/ext-themelist';
+import 'ace-builds/src-noconflict/ext-whitespace';
+// import 'ace-builds/src-noconflict/keybinding-emacs';
+// import 'ace-builds/src-noconflict/keybinding-sublime';
+// import 'ace-builds/src-noconflict/keybinding-vim';
+// import 'ace-builds/src-noconflict/keybinding-vscode';
+
+
+const propTypes = {
+ readOnly: PropTypes.bool,
+ headerText: PropTypes.string,
+ fileName: PropTypes.string,
+ onChange: PropTypes.func,
+ onHide: PropTypes.func,
+ onSubmit: PropTypes.func,
+ onValidate: PropTypes.func,
+ getFileContent: PropTypes.func,
+};
+const defaultProps = {
+ readOnly: false,
+ headerText: '',
+ fileName: '',
+ onChange: () => {},
+ onHide: () => {},
+ onSubmit: () => {},
+ onValidate: () => {},
+ getFileContent: () => {},
+};
+
+export default
+class EditDialog extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ showSaveConfirmDialog: false,
+ editorText: "",
+ editorMode: "text"
+ };
+ this.newText = null;
+ this.saveConfirmDialog = React.createElement(FileSaveConfirmDialog, { ...FileSaveConfirmDialog.defaultProps,
+ onSubmit: this.handleSubmit,
+ onHide: this.handleHideSaveConfirmDialog,
+ onIgnore: this.handleSkipSaveAndClose,
+ });
+ }
+
+ componentDidMount() {
+ this._isMounted = true
+ this.initEditorText();
+ }
+
+ componentWillUnmount() {
+ this._isMounted = false
+ }
+
+ initEditorText = async (e) => {
+ let value = await this.props.getFileContent();
+
+ let mode = getModeForPath(this.props.fileName).name;
+ try { //prevent exception on client, if not imported mode is used.
+ await import (`ace-builds/src-noconflict/mode-${mode}`);
+ } catch(error) {
+ mode = 'text';
+ }
+
+ this.setState({ editorText: value, editorMode: mode });
+ }
+
+ handleChange = async (value, event) => {
+ this.newText = value;
+ if (this._isMounted) {
+
+ }
+ }
+
+ handleSubmit = async () => {
+ if (this.newText) {
+ const validationError = await this.props.onSubmit(this.newText);
+
+ // if (validationError && this._isMounted) {
+ // this.setState({ validationError });
+ // }
+ this.handleSkipSaveAndClose();
+ }
+ }
+
+ handleClose = async () => {
+ if (this._isMounted && this.newText) {
+ this.setState({ showSaveConfirmDialog: true, editorText: this.newText});
+ } else {
+ this.handleSkipSaveAndClose();
+ }
+ }
+
+ handleSkipSaveAndClose = async () => {
+ this.props.onHide();
+ this.newText = null;
+ }
+
+ handleHideSaveConfirmDialog = async () => {
+ if (this._isMounted)
+ this.setState({ showSaveConfirmDialog: false });
+ }
+
+ render() {
+ const { onHide, headerText } = this.props;
+ const { showSaveConfirmDialog } = this.state;
+
+
+ return (
+
+ );
+ }
+}
+
+EditDialog.propTypes = propTypes;
+EditDialog.defaultProps = defaultProps;
diff --git a/packages/client-react/src/client/components/EditDialog/EditDialog.spec.js b/packages/client-react/src/client/components/EditDialog/EditDialog.spec.js
new file mode 100644
index 000000000..30b01316e
--- /dev/null
+++ b/packages/client-react/src/client/components/EditDialog/EditDialog.spec.js
@@ -0,0 +1,21 @@
+import React from 'react'; // eslint-disable-line
+import { expect } from 'chai'; // eslint-disable-line
+import { shallow } from 'enzyme'; // eslint-disable-line
+import EditDialog from '.'; // eslint-disable-line
+
+describe('
', () => {
+ /* Recommended test-cases
+
+ it('should have default props', () => {
+ let component =
;
+ expect(component.props.testProp).to.equal('Give me back my label!');
+ expect(component.props.onClick).to.be.a('function');
+ });
+ it('should have the right class name', () => {
+ let wrapper = shallow(
);
+ expect(wrapper).to.have.className('set-name-dialog');
+ expect(wrapper).to.have.className('test-class-name');
+ });
+
+ */
+});
diff --git a/packages/client-react/src/client/components/EditDialog/icons-svg.js b/packages/client-react/src/client/components/EditDialog/icons-svg.js
new file mode 100644
index 000000000..1dc75b397
--- /dev/null
+++ b/packages/client-react/src/client/components/EditDialog/icons-svg.js
@@ -0,0 +1,3 @@
+export default {
+ close: `
`,
+};
diff --git a/packages/client-react/src/client/components/EditDialog/index.js b/packages/client-react/src/client/components/EditDialog/index.js
new file mode 100644
index 000000000..4b1a9b544
--- /dev/null
+++ b/packages/client-react/src/client/components/EditDialog/index.js
@@ -0,0 +1 @@
+export default require('./EditDialog.react').default;
diff --git a/packages/client-react/src/client/components/FileNavigator/FileNavigator.less b/packages/client-react/src/client/components/FileNavigator/FileNavigator.less
index d74bb32dd..ce61bc889 100644
--- a/packages/client-react/src/client/components/FileNavigator/FileNavigator.less
+++ b/packages/client-react/src/client/components/FileNavigator/FileNavigator.less
@@ -18,13 +18,14 @@
}
.oc-fm--file-navigator__location-bar {
- border-top: 1px solid rgba(0,0,0,.08);
+ //border-top: 1px solid rgba(0,0,0,.08);
+ border-bottom: 1px solid #f5f5f5;
position: relative;
z-index: 10;
}
.oc-fm--file-navigator__notifications {
- width: 280px;
+ width: 310px;
position: absolute;
right: 24px;
bottom: 12px;
diff --git a/packages/client-react/src/client/components/FileNavigator/FileNavigator.react.js b/packages/client-react/src/client/components/FileNavigator/FileNavigator.react.js
index 11aa30c85..db05616d4 100644
--- a/packages/client-react/src/client/components/FileNavigator/FileNavigator.react.js
+++ b/packages/client-react/src/client/components/FileNavigator/FileNavigator.react.js
@@ -104,6 +104,11 @@ class FileNavigator extends Component {
const initializedCapabilities = capabilities(apiOptions, capabilitiesProps);
this.setState({ initializedCapabilities });
}
+
+ if (this.props.signInRenderer !== nextProps.signInRenderer) {
+ this.setState( () => ({ apiSignedIn: false }));
+ this.monitorApiAvailability();
+ }
}
componentWillUnmount() {
@@ -165,14 +170,16 @@ class FileNavigator extends Component {
};
monitorApiAvailability = () => {
- const { api } = this.props;
+ const { api, apiOptions, signInRenderer } = this.props;
- this.apiAvailabilityTimeout = setTimeout(() => {
- if (api.hasSignedIn()) {
+ this.apiAvailabilityTimeout = setTimeout( async () => {
+ let response = await api.hasSignedIn(apiOptions);
+ if (response) {
this.setStateAsync({ apiInitialized: true, apiSignedIn: true });
this.handleApiReady();
} else {
- this.monitorApiAvailability();
+ if (signInRenderer === null)
+ this.monitorApiAvailability();
}
}, MONITOR_API_AVAILABILITY_TIMEOUT);
};
@@ -300,7 +307,7 @@ class FileNavigator extends Component {
};
handleResourceItemDoubleClick = async ({ event, number, rowData }) => {
- const { loadingView } = this.state;
+ const { loadingView, initializedCapabilities } = this.state;
const { id } = rowData;
if (loadingView) {
@@ -312,6 +319,14 @@ class FileNavigator extends Component {
this.navigateToDir(id);
}
+ const isFile = rowData.type === 'file';
+ if (isFile) {
+ const { apiOptions } = this.props;
+ const fileOpenCapability = find(initializedCapabilities, (o) => (o.id === 'edit' || o.id === 'view') && o.shouldBeAvailable(apiOptions));
+ if (fileOpenCapability)
+ fileOpenCapability.handler();
+ }
+
this.focusView();
this.props.onResourceItemDoubleClick({ event, number, rowData });
@@ -485,6 +500,12 @@ class FileNavigator extends Component {
locale={apiOptions.locale}
/>
+