From d4ea4b155d8b8e8d8b50ade4f7f19a6f1ed5996b Mon Sep 17 00:00:00 2001 From: Alexander Pustovalov Date: Mon, 27 Mar 2017 01:19:51 +0300 Subject: [PATCH] Installer and Extractor were added --- package.json | 1 + src-client/api/app/serverApi.js | 8 +- src-client/assets/app/css/img/screenshot.png | Bin 0 -> 9641 bytes .../assets/app/css/umyproto.deskpage.css | 6 + src-client/components/NamespaceCard.js | 102 +++++++ src-client/components/OptionInput.js | 74 +++--- src-client/components/index.js | 1 + .../app/containers/AppContainer/actions.js | 17 +- .../app/containers/AppContainer/index.js | 20 +- .../app/containers/AppContainer/reducer.js | 24 +- .../app/containers/AppMessage/index.js | 14 +- .../app/containers/ConfirmationModal/index.js | 4 +- .../containers/ExtractList/actions.js | 22 ++ .../extractor/containers/ExtractList/index.js | 109 ++++++++ .../containers/ExtractList/reducer.js | 28 ++ .../extractor/containers/ExtractList/sagas.js | 19 ++ .../containers/ExtractList/selectors.js | 31 +++ .../extractor/containers/Extractor/actions.js | 57 ++++ .../extractor/containers/Extractor/index.js | 155 +++++++++++ .../extractor/containers/Extractor/reducer.js | 51 ++++ .../extractor/containers/Extractor/sagas.js | 78 ++++++ .../containers/Extractor/selectors.js | 26 ++ .../containers/NamespaceList/actions.js | 22 ++ .../containers/NamespaceList/index.js | 130 +++++++++ .../containers/NamespaceList/reducer.js | 28 ++ .../containers/NamespaceList/sagas.js | 19 ++ .../containers/NamespaceList/selectors.js | 24 ++ src-client/modules/extractor/index.js | 19 ++ .../generator/containers/Generator/index.js | 2 +- .../installer/containers/Installer/actions.js | 29 ++ .../installer/containers/Installer/index.js | 249 ++++++++++++++++++ .../installer/containers/Installer/reducer.js | 39 +++ .../installer/containers/Installer/sagas.js | 128 +++++++++ .../containers/Installer/selectors.js | 27 ++ .../SelectDirectoryModal/actions.js | 27 ++ .../containers/SelectDirectoryModal/index.js | 95 +++++++ .../SelectDirectoryModal/reducer.js | 50 ++++ .../containers/SelectDirectoryModal/sagas.js | 19 ++ .../SelectDirectoryModal/selectors.js | 22 ++ src-client/modules/installer/index.js | 17 ++ .../containers/ComponentOptionsPanel/index.js | 6 +- .../containers/LibraryControls/actions.js | 16 +- .../containers/LibraryControls/index.js | 7 +- .../containers/LibraryControls/sagas.js | 23 -- .../containers/LibraryPanel/actions.js | 33 ++- .../containers/LibraryPanel/index.js | 104 ++++---- .../containers/PageExportControls/actions.js | 69 +++-- .../containers/PageListControls/actions.js | 12 +- .../containers/PageListControls/index.js | 4 +- .../containers/PageListPanel/index.js | 2 +- .../SaveDefaultModelModal/actions.js | 1 + .../containers/SaveDefaultModelModal/index.js | 13 +- .../containers/SelectionBreadcrumbs/index.js | 15 +- src-client/redux/reducer.js | 8 + src-client/sagas/saga.js | 4 +- src-server/commons/extractManager.js | 201 ++++++++++++++ src-server/structor/controller.js | 66 +---- src-server/structor/sandboxCompilerManager.js | 8 +- .../structor/webpackBuilderMiddleware.js | 43 ++- 59 files changed, 2152 insertions(+), 276 deletions(-) create mode 100644 src-client/assets/app/css/img/screenshot.png create mode 100644 src-client/components/NamespaceCard.js create mode 100644 src-client/modules/extractor/containers/ExtractList/actions.js create mode 100644 src-client/modules/extractor/containers/ExtractList/index.js create mode 100644 src-client/modules/extractor/containers/ExtractList/reducer.js create mode 100644 src-client/modules/extractor/containers/ExtractList/sagas.js create mode 100644 src-client/modules/extractor/containers/ExtractList/selectors.js create mode 100644 src-client/modules/extractor/containers/Extractor/actions.js create mode 100644 src-client/modules/extractor/containers/Extractor/index.js create mode 100644 src-client/modules/extractor/containers/Extractor/reducer.js create mode 100644 src-client/modules/extractor/containers/Extractor/sagas.js create mode 100644 src-client/modules/extractor/containers/Extractor/selectors.js create mode 100644 src-client/modules/extractor/containers/NamespaceList/actions.js create mode 100644 src-client/modules/extractor/containers/NamespaceList/index.js create mode 100644 src-client/modules/extractor/containers/NamespaceList/reducer.js create mode 100644 src-client/modules/extractor/containers/NamespaceList/sagas.js create mode 100644 src-client/modules/extractor/containers/NamespaceList/selectors.js create mode 100644 src-client/modules/extractor/index.js create mode 100644 src-client/modules/installer/containers/Installer/actions.js create mode 100644 src-client/modules/installer/containers/Installer/index.js create mode 100644 src-client/modules/installer/containers/Installer/reducer.js create mode 100644 src-client/modules/installer/containers/Installer/sagas.js create mode 100644 src-client/modules/installer/containers/Installer/selectors.js create mode 100644 src-client/modules/installer/containers/SelectDirectoryModal/actions.js create mode 100644 src-client/modules/installer/containers/SelectDirectoryModal/index.js create mode 100644 src-client/modules/installer/containers/SelectDirectoryModal/reducer.js create mode 100644 src-client/modules/installer/containers/SelectDirectoryModal/sagas.js create mode 100644 src-client/modules/installer/containers/SelectDirectoryModal/selectors.js create mode 100644 src-client/modules/installer/index.js create mode 100644 src-server/commons/extractManager.js diff --git a/package.json b/package.json index 351b5903..aa9a6ad2 100644 --- a/package.json +++ b/package.json @@ -84,6 +84,7 @@ "gulp-watch": "4.3.9", "marked": "0.3.5", "react-bootstrap": "0.30.6", + "strip-ansi": "3.0.1", "validator": "5.2.0" }, "keywords": [ diff --git a/src-client/api/app/serverApi.js b/src-client/api/app/serverApi.js index ad38a43e..1a0ac873 100644 --- a/src-client/api/app/serverApi.js +++ b/src-client/api/app/serverApi.js @@ -136,6 +136,10 @@ export function generateApplication(pagesModel, hasApplicationFiles) { return invokeStructor('generateApplication', {pagesModel, hasApplicationFiles}); } -export function extractNamespace(namespace) { - return invokeStructor('extractNamespace', {namespace}); +export function preExtractNamespaces(namespaces) { + return invokeStructor('preExtractNamespaces', {namespaces}); +} + +export function extractNamespaces(namespaces, dependencies, dirPath) { + return invokeStructor('extractNamespaces', {namespaces, dependencies, dirPath}); } \ No newline at end of file diff --git a/src-client/assets/app/css/img/screenshot.png b/src-client/assets/app/css/img/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..108e90f72b44c79989ac04743fd3e1c7cb53ea4b GIT binary patch literal 9641 zcmdscXH-A3J-7(&H=bd-%x$oy)W7OzgwQ9|(nl-~WzZIdQrNMOk)Nud+ z)6E;#bpb%)j~YEK>|yL`KMQ}jz0{1o^jz>bX)?;aciu^4d1>xly^@=^0;=(ekD|E)ogX{6FNvFC`^d zB^HnN=wnR*sQr-*=mGv;Gy#AF|F71|8hvjsEfvbs3UAj>+>W(uPou){n&#D~bvO!( ztZqj~hMVQnAl%%VC-j;9PW;SXYfF+2crlh|-bG*pT+B&K2s%BPlRaVU^&*_mUexoOez48e#cCqWueoxtZP=D5JC591yGF3@$d;9GdVIL_4+{-~mq_uAo z+NG8zo&zZO@TnC{wrBJ+uwPqw!O_&HnARm8wCj||`{VPb<#_iaqxrY2tWB<(D^#z8 zuVGT}GRV;X`0GcBC)by6x|~*LE`9Rgq?#;y%z)o+l}&Liew&w!wMFRkq1?rl7T%

Oo~N*z(#D;tp))`ReEz2l6w?f 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 literal 0 HcmV?d00001 diff --git a/src-client/assets/app/css/umyproto.deskpage.css b/src-client/assets/app/css/umyproto.deskpage.css index f52d6b4d..3c596073 100644 --- a/src-client/assets/app/css/umyproto.deskpage.css +++ b/src-client/assets/app/css/umyproto.deskpage.css @@ -45,6 +45,12 @@ body { background-size: 25em 25em; } +.umy-logo-flexible { + width: 100%; + background: url(img/umylogo-white.svg); + background-size: 100%; +} + .umy-grid-basic-element { position: relative; } diff --git a/src-client/components/NamespaceCard.js b/src-client/components/NamespaceCard.js new file mode 100644 index 00000000..3f42c7be --- /dev/null +++ b/src-client/components/NamespaceCard.js @@ -0,0 +1,102 @@ +/* + * Copyright 2015 Alexander Pustovalov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, { Component, PropTypes } from 'react'; +import defaultScreenshotSrc from 'assets/app/css/img/screenshot.png'; + +const containerStyle = { + display: 'flex', + flexDirection: 'row', + flexFlow: 'nowrap', + alignItems: 'center', + width: '600px', +}; +const screenshotSectionStyle = { + flexGrow: 0, + minWidth: '200px', + width: '200px', + padding: '0.5em', +}; +const mainSectionStyle = { + marginLeft: '0.5em', + flexGrow: 2, + padding: '0.5em 0.5em 0.5em 0', + height: '200px', + overflow: 'auto', +}; +const installBtnSectionStyle = { + flexGrow: 0, + minWidth: '200px', + width: '200px', + padding: '0.5em', + alignItems: 'center', +}; +const bottomToolbarStyle = { + flexGrow: 2, + display: 'flex', + flexDirection: 'row', + padding: '0.5em 0.5em 0.5em 0', + alignItems: 'center', +}; + +class NamespaceCard extends Component { + + render() { + const {style, namespace, repoName, repoLink, namespaceDescription, stars} = this.props; + return ( +

+
+
+
+ +
+
+

{repoName && repoName.substr(0, 100)}

+

{namespace}

+

+ {namespaceDescription} +

+
+
+
+
+ +
+
+
+ GH Stars: {stars} +
+ +
+
+
+
+ ); + } +} + +export default NamespaceCard; diff --git a/src-client/components/OptionInput.js b/src-client/components/OptionInput.js index f2ae4108..6b136f6c 100644 --- a/src-client/components/OptionInput.js +++ b/src-client/components/OptionInput.js @@ -76,14 +76,13 @@ class OptionInput extends Component { handleChangeInputValue(e) { let value = null; const {propertyType} = this.state; - const {inputElement} = this.refs; if(propertyType){ if(propertyType === 'text'){ - value = inputElement.value; + value = this.inputElement.value; } else if(propertyType === 'checkbox'){ - value = inputElement.checked; + value = this.inputElement.checked; } else if(propertyType === 'number'){ - value = parseFloat(inputElement.value); + value = parseFloat(this.inputElement.value); } } let valueObject = set({}, this.props.path, value); @@ -100,7 +99,7 @@ class OptionInput extends Component { const {path, onChangeValue} = this.props; if(propertyType){ if(propertyType === 'checkbox'){ - value = this.refs.inputElement.checked; + value = this.inputElement.checked; } } let valueObject = set({}, path, value); @@ -141,43 +140,56 @@ class OptionInput extends Component { height: '1.55em', paddingTop: '2px', paddingBottom: '2px' }; if(propertyType === 'checkbox') { - style.width = '1em'; + style.width = '2em'; element = ( -
- - +
+
+ +
+
+ this.inputElement = me} + type={propertyType} + checked={this.getValueFromObject()} + onFocus={this.handleFocus} + style={style} + onChange={this.handleChangeCheckboxValue} + /> +
); } else if(propertyType === 'text' || propertyType === 'number') { element = ( -
- - +
+
+ +
+
+ this.inputElement = me} + type={propertyType} + className="form-control" + value={this.getValueFromObject()} + style={style} + onFocus={this.handleFocus} + onChange={this.handleChangeInputValue} + /> +
); } return (
-

+

{label}

{element} diff --git a/src-client/components/index.js b/src-client/components/index.js index a4a2c80b..d1f3cb61 100644 --- a/src-client/components/index.js +++ b/src-client/components/index.js @@ -37,3 +37,4 @@ export StyleNumberInput from './StyleNumberInput'; export StyleOptionSelect from './StyleOptionSelect'; export StyleSizeInput from './StyleSizeInput'; export StyleSwatchesPicker from './StyleSwatchesPicker'; +export NamespaceCard from './NamespaceCard'; diff --git a/src-client/modules/app/containers/AppContainer/actions.js b/src-client/modules/app/containers/AppContainer/actions.js index 52d38310..eb3e8a33 100644 --- a/src-client/modules/app/containers/AppContainer/actions.js +++ b/src-client/modules/app/containers/AppContainer/actions.js @@ -13,6 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + +import stripAnsi from 'strip-ansi'; import { bindActionCreators } from 'redux'; import { success, failed, timeout, close} from 'modules/app/containers/AppMessage/actions'; import { setReloadPageRequest, executeReloadPageRequest } from 'modules/workspace/containers/DeskPage/actions'; @@ -32,11 +34,12 @@ export const COMPILER_DONE = "AppContainer/COMPILER_DONE"; export const COMPILER_TIMEOUT = "AppContainer/COMPILER_TIMEOUT"; export const SHOW_DESK = "AppContainer/SHOW_DESK"; -export const SHOW_PROJECTS = "AppContainer/SHOW_PROJECTS"; export const SHOW_GENERATOR = "AppContainer/SHOW_GENERATOR"; export const HIDE_GENERATOR = "AppContainer/HIDE_GENERATOR"; -export const SHOW_SANDBOX = "AppContainer/SHOW_SANDBOX"; -export const HIDE_SANDBOX = "AppContainer/HIDE_SANDBOX"; +export const SHOW_INSTALLER = "AppContainer/SHOW_INSTALLER"; +export const HIDE_INSTALLER = "AppContainer/HIDE_INSTALLER"; +export const SHOW_EXTRACTOR = "AppContainer/SHOW_EXTRACTOR"; +export const HIDE_EXTRACTOR = "AppContainer/HIDE_EXTRACTOR"; export const getProjectStatus = () => ({ type: GET_PROJECT_STATUS }); export const setProjectInfo = (info) => ({ type: SET_PROJECT_INFO, payload: info }); @@ -54,8 +57,10 @@ export const compilerTimeout = () => ({ type: COMPILER_TIMEOUT }); export const showDesk = () => ({type: SHOW_DESK}); export const showGenerator = () => ({type: SHOW_GENERATOR}); export const hideGenerator = () => ({type: HIDE_GENERATOR}); -export const showSandbox = () => ({type: SHOW_SANDBOX}); -export const hideSandbox = () => ({type: HIDE_SANDBOX}); +export const showInstaller = () => ({type: SHOW_INSTALLER}); +export const hideInstaller = () => ({type: HIDE_INSTALLER}); +export const showExtractor = () => ({type: SHOW_EXTRACTOR}); +export const hideExtractor = () => ({type: HIDE_EXTRACTOR}); export const handleCompilerMessage = (message) => (dispatch, getState) => { if(message.status === 'start'){ @@ -63,7 +68,7 @@ export const handleCompilerMessage = (message) => (dispatch, getState) => { } else if(message.status === 'done') { if(message.errors && message.errors.length > 0){ message.errors.forEach( error => { - dispatch(failed(error.message ? error.message : error)); + dispatch(failed(stripAnsi(error.message ? error.message : error))); }); dispatch(setReloadPageRequest()); } else { diff --git a/src-client/modules/app/containers/AppContainer/index.js b/src-client/modules/app/containers/AppContainer/index.js index 669c5f4d..db8fa79b 100644 --- a/src-client/modules/app/containers/AppContainer/index.js +++ b/src-client/modules/app/containers/AppContainer/index.js @@ -27,6 +27,8 @@ import { SaveDefaultModelModal } from 'modules/workspace'; import {Generator} from 'modules/generator'; +import {Installer} from 'modules/installer'; +import {Extractor} from 'modules/extractor'; import SignInModal from 'modules/app/containers/SignInModal'; import ProxySetupModal from 'modules/app/containers/ProxySetupModal'; import ConfirmationModal from 'modules/app/containers/ConfirmationModal'; @@ -72,13 +74,29 @@ class Container extends Component {
); + } else if(workspaceMode === 'installer'){ + content = ( +
+ + + +
+ ); + } else if(workspaceMode === 'extractor'){ + content = ( +
+ + + +
+ ); } else { content = (
-
+
diff --git a/src-client/modules/app/containers/AppContainer/reducer.js b/src-client/modules/app/containers/AppContainer/reducer.js index 7e7fb417..182a2c9c 100644 --- a/src-client/modules/app/containers/AppContainer/reducer.js +++ b/src-client/modules/app/containers/AppContainer/reducer.js @@ -86,31 +86,33 @@ export default (state = initialState, action = {}) => { }); } - if(type === actions.SHOW_PROJECTS){ - return Object.assign({}, state, { - workspaceMode: 'projects' - }); - } - if(type === actions.SHOW_GENERATOR){ return Object.assign({}, state, { workspaceMode: 'generator' }); } - if(type === actions.HIDE_GENERATOR || type === actions.HIDE_SANDBOX){ + if(type === actions.SHOW_INSTALLER){ return Object.assign({}, state, { - workspaceMode: 'desk' + workspaceMode: 'installer' }); } - if(type === actions.SHOW_SANDBOX){ + if(type === actions.SHOW_EXTRACTOR){ return Object.assign({}, state, { - workspaceMode: 'sandbox' + workspaceMode: 'extractor' }); } - return state; + if(type === actions.HIDE_GENERATOR + || type === actions.HIDE_INSTALLER + || type === actions.HIDE_EXTRACTOR){ + return Object.assign({}, state, { + workspaceMode: 'desk' + }); + } + + return state; } diff --git a/src-client/modules/app/containers/AppMessage/index.js b/src-client/modules/app/containers/AppMessage/index.js index 8b74bde3..0fb40ed9 100644 --- a/src-client/modules/app/containers/AppMessage/index.js +++ b/src-client/modules/app/containers/AppMessage/index.js @@ -14,6 +14,7 @@ * limitations under the License. */ +import marked from 'marked'; import React, { Component, PropTypes } from 'react'; import ReactDOM from 'react-dom'; import { connect } from 'react-redux'; @@ -101,10 +102,15 @@ class Container extends Component { messageText = messageText.substr(0, 300) + '...'; } messagesItems.push( -
-

- {messageText} -

+
+ {messageText && +
+ } { textNeedCut ?

Confirm -

+
{message && -
+
}
diff --git a/src-client/modules/extractor/containers/ExtractList/actions.js b/src-client/modules/extractor/containers/ExtractList/actions.js new file mode 100644 index 00000000..7d112d23 --- /dev/null +++ b/src-client/modules/extractor/containers/ExtractList/actions.js @@ -0,0 +1,22 @@ +/* + * Copyright 2015 Alexander Pustovalov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { bindActionCreators } from 'redux'; +import { extract } from 'modules/extractor/containers/Extractor/actions'; + +export const containerActions = (dispatch) => bindActionCreators({ + extract +}, dispatch); diff --git a/src-client/modules/extractor/containers/ExtractList/index.js b/src-client/modules/extractor/containers/ExtractList/index.js new file mode 100644 index 00000000..3d3a8ca2 --- /dev/null +++ b/src-client/modules/extractor/containers/ExtractList/index.js @@ -0,0 +1,109 @@ +/* + * Copyright 2015 Alexander Pustovalov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {includes, findIndex, difference} from 'lodash'; +import React, {Component, PropTypes} from 'react'; +import {connect} from 'react-redux'; +import {modelSelector} from './selectors.js'; +import {containerActions} from './actions.js'; + +import {Grid, Row, Col} from 'react-bootstrap'; +import {ListGroup, ListGroupItem} from 'react-bootstrap'; + +const labelContainerStyle = { + display: 'flex', + flexDirection: 'row', + alignItems: 'center', +}; + +const labelStyle = { + margin: 0, + whiteSpace: 'wrap', + wordBreak: 'break-all' +}; + +const checkBoxLabelStyle = { + width: '1.5em', + minWidth: '1.5em', + flexGrow: 0, +}; + +let checkBoxStyle = { + margin: 0, +}; + +class Container extends Component { + + constructor(props) { + super(props); + this.handleExtract = this.handleExtract.bind(this); + } + + handleExtract(e) { + e.stopPropagation(); + e.preventDefault(); + const {dependentNamespaces, dependencies, projectPaths, extract} = this.props; + const {dir} = projectPaths; + extract(dependentNamespaces, dependencies, dir + '_namespaces'); + } + + render() { + const {dependentNamespaces, dependencies, selectedNamespaces, projectPaths} = this.props; + let addedNamespaces = difference(dependentNamespaces, selectedNamespaces); + const {dir} = projectPaths; + return ( + + + +

The source code of the listed namespaces will be saved into directory:

+
{dir + '_namespaces'}
+ +
+ + +
+

Selected namespaces:

+
+								{JSON.stringify(selectedNamespaces, null, 4)}
+							
+

Namespace dependencies:

+
+								{JSON.stringify(addedNamespaces, null, 4)}
+							
+
+
+ +
+ + +

Node modules dependencies:

+
+							{JSON.stringify(dependencies, null, 4)}
+						
+ +
+
+ ); + } +} + +export default connect(modelSelector, containerActions)(Container); + diff --git a/src-client/modules/extractor/containers/ExtractList/reducer.js b/src-client/modules/extractor/containers/ExtractList/reducer.js new file mode 100644 index 00000000..1a291fed --- /dev/null +++ b/src-client/modules/extractor/containers/ExtractList/reducer.js @@ -0,0 +1,28 @@ +/* + * Copyright 2015 Alexander Pustovalov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as actions from './actions.js'; + +const initialState = { +}; + +export default (state = initialState, action = {}) => { + + const {type, payload} = action; + + return state; +} + diff --git a/src-client/modules/extractor/containers/ExtractList/sagas.js b/src-client/modules/extractor/containers/ExtractList/sagas.js new file mode 100644 index 00000000..4a3fb834 --- /dev/null +++ b/src-client/modules/extractor/containers/ExtractList/sagas.js @@ -0,0 +1,19 @@ +/* + * Copyright 2015 Alexander Pustovalov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// main saga +export default function* mainSaga() { +}; diff --git a/src-client/modules/extractor/containers/ExtractList/selectors.js b/src-client/modules/extractor/containers/ExtractList/selectors.js new file mode 100644 index 00000000..6e283653 --- /dev/null +++ b/src-client/modules/extractor/containers/ExtractList/selectors.js @@ -0,0 +1,31 @@ +/* + * Copyright 2015 Alexander Pustovalov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createStructuredSelector } from 'reselect'; +import {availableNamespacesSelector} from 'modules/workspace/containers/LibraryPanel/selectors'; +import {projectPathsSelector} from 'modules/app/containers/AppContainer/selectors'; +import { + selectedNamespacesSelector, + dependentNamespacesSelector, + dependenciesSelector +} from 'modules/extractor/containers/Extractor/selectors'; + +export const modelSelector = createStructuredSelector({ + selectedNamespaces: selectedNamespacesSelector, + dependentNamespaces: dependentNamespacesSelector, + dependencies: dependenciesSelector, + projectPaths: projectPathsSelector, +}); diff --git a/src-client/modules/extractor/containers/Extractor/actions.js b/src-client/modules/extractor/containers/Extractor/actions.js new file mode 100644 index 00000000..112c94b7 --- /dev/null +++ b/src-client/modules/extractor/containers/Extractor/actions.js @@ -0,0 +1,57 @@ +/* + * Copyright 2015 Alexander Pustovalov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {bindActionCreators} from 'redux'; +import {graphApi, serverApi} from 'api'; +import {hideExtractor} from 'modules/app/containers/AppContainer/actions'; +import {failed} from 'modules/app/containers/AppMessage/actions'; + +export const STAGE1 = 'STAGE1'; +export const STAGE2 = 'STAGE2'; + +export const STEP_TO_STAGE = "Extractor/STEP_TO_STAGE"; +export const PREEXTRACT = "Extractor/PREEXTRACT"; +export const EXTRACT = "Extractor/EXTRACT"; + +export const SET_SELECTED_NAMESPACES = "Extractor/SET_SELECTED_NAMESPACES"; +export const SET_PREEXTRACTED_DATA = "Extractor/SET_PREEXTRACTED_DATA"; + +export const stepToStage = (stage) => ({type: STEP_TO_STAGE, payload: stage}); + +export const setSelectedNamespaces = (namespaces) => (dispatch, getState) => { + dispatch({type: SET_SELECTED_NAMESPACES, payload: namespaces}); +}; + +export const preExtract = (namespaces) => (dispatch, getState) => { + dispatch({type: PREEXTRACT, payload: namespaces}); +}; + +export const setPreExtractedData = (preExtractedData) => (dispatch, getState) => { + dispatch({type: SET_PREEXTRACTED_DATA, payload: preExtractedData}); +}; + +export const extract = (namespaces, dependencies, dirPath) => (dispatch, getState) => { + dispatch({type: EXTRACT, payload: {namespaces, dependencies, dirPath}}); +}; + +export const hide = () => (dispatch, getState) => { + dispatch(hideExtractor()); + dispatch(stepToStage(STAGE1)); +}; + +export const containerActions = (dispatch) => bindActionCreators({ + hide, stepToStage +}, dispatch); diff --git a/src-client/modules/extractor/containers/Extractor/index.js b/src-client/modules/extractor/containers/Extractor/index.js new file mode 100644 index 00000000..8f180676 --- /dev/null +++ b/src-client/modules/extractor/containers/Extractor/index.js @@ -0,0 +1,155 @@ +/* + * Copyright 2015 Alexander Pustovalov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, { Component, PropTypes } from 'react'; +import { connect } from 'react-redux'; +import { modelSelector } from './selectors.js'; +import { containerActions, STAGE1, STAGE2 } from './actions.js'; + +import { ButtonGroup, Button } from 'react-bootstrap'; + +import NamespaceList from 'modules/extractor/containers/NamespaceList'; +import ExtractList from 'modules/extractor/containers/ExtractList'; + +const toolbarLabelStyle = { + margin: '0 1em' +}; +const labelSectionStyle = { + width: '35%', + margin: '0 2em' +}; +const centerSectionStyle = { + width: '30%', + display: 'flex', + justifyContent: 'center' +}; +const toolbarSectionStyle = { + width: '100%', + display: 'flex', + justifyContent: 'center', + marginBottom: '1em' +}; + +const TITLE_STEP_1 = 'Select namespaces to extract'; +const TITLE_STEP_2 = 'Review dependencies'; +const TITLE_STEP_3 = 'Extract namespaces'; + +class Container extends Component { + + constructor(props) { + super(props); + this.handleOnStep = this.handleOnStep.bind(this); + this.handleClose = this.handleClose.bind(this); + } + + componentDidMount() { + this.containerElement.scrollTop = 0; + } + + componentDidUpdate() { + this.containerElement.scrollTop = 0; + } + + handleOnStep(e) { + e.stopPropagation(); + e.preventDefault(); + const stage = e.currentTarget.dataset.stage; + if(stage){ + const {stepToStage} = this.props; + stepToStage(e.currentTarget.dataset.stage); + } + } + + handleClose(e) { + e.stopPropagation(); + e.preventDefault(); + this.props.hide(); + } + + render(){ + + const { stage } = this.props; + + const closeButton = ( + + ); + + let backStepLabel = null; + let nextStepLabel = null; + let toolbar = null; + let header = null; + let content = null; + if(stage === STAGE1){ + nextStepLabel = ( +
{TITLE_STEP_2}
+ ); + toolbar = ( + + {closeButton} + + ); + header = (

{TITLE_STEP_1}

); + content = (); + } else if(stage === STAGE2){ + backStepLabel = ( +
{TITLE_STEP_1}
+ ); + nextStepLabel = ( +
{TITLE_STEP_3}
+ ); + toolbar = ( + + + {closeButton} + + ); + header = (

{TITLE_STEP_2}

); + content = (); + } + return ( +
this.containerElement = me} + id="containerElement" + style={{position: 'absolute', top: '0px', left: '0px', right: '0px', bottom: '0px', overflow: 'auto'}} + > +
+
+
+
{backStepLabel}
+
{header}
+
{nextStepLabel}
+
+
{toolbar}
+
+
+
+ {content} +
+
+ ); + } + +} + +export default connect(modelSelector, containerActions)(Container); + diff --git a/src-client/modules/extractor/containers/Extractor/reducer.js b/src-client/modules/extractor/containers/Extractor/reducer.js new file mode 100644 index 00000000..c8bd95d2 --- /dev/null +++ b/src-client/modules/extractor/containers/Extractor/reducer.js @@ -0,0 +1,51 @@ +/* + * Copyright 2015 Alexander Pustovalov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as actions from './actions.js'; + +const initialState = { + stage: actions.STAGE1, + selectedNamespaces: [], + dependentNamespaces: [], + dependencies: {} +}; + +export default (state = initialState, action = {}) => { + + const {type, payload} = action; + + if(type === actions.STEP_TO_STAGE){ + return Object.assign({}, state, { + stage: payload + }); + } + + if(type === actions.SET_SELECTED_NAMESPACES){ + return Object.assign({}, state, { + selectedNamespaces: [].concat(payload), + }); + } + + if(type === actions.SET_PREEXTRACTED_DATA){ + return Object.assign({}, state, { + dependentNamespaces: [].concat(payload.namespaces), + dependencies: Object.assign({}, payload.dependencies), + }); + } + + return state; +} + diff --git a/src-client/modules/extractor/containers/Extractor/sagas.js b/src-client/modules/extractor/containers/Extractor/sagas.js new file mode 100644 index 00000000..624144fb --- /dev/null +++ b/src-client/modules/extractor/containers/Extractor/sagas.js @@ -0,0 +1,78 @@ +/* + * Copyright 2015 Alexander Pustovalov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { fork, take, call, put, cancel } from 'redux-saga/effects'; +import { SagaCancellationException } from 'redux-saga'; +import * as actions from './actions.js'; +import * as spinnerActions from 'modules/app/containers/AppSpinner/actions'; +import * as messageActions from 'modules/app/containers/AppMessage/actions'; +import * as generatorListActions from 'modules/generator/containers/GeneratorList/actions'; +import * as appContainerActions from 'modules/app/containers/AppContainer/actions'; +import * as deskPageActions from 'modules/workspace/containers/DeskPage/actions'; +import * as clipboardIndicatorActions from 'modules/workspace/containers/ClipboardIndicator/actions'; +import * as libraryPanelActions from 'modules/workspace/containers/LibraryPanel/actions'; +import * as selectionBreadcrumbsActions from 'modules/workspace/containers/SelectionBreadcrumbs/actions'; +import { serverApi, graphApi, coockiesApi } from 'api'; +import * as historyActions from 'modules/workspace/containers/HistoryControls/actions'; + +function* preExtract(){ + while(true){ + const {payload} = yield take(actions.PREEXTRACT); + yield put(spinnerActions.started('Searching dependencies')); + try { + const preExtractedData = yield call(serverApi.preExtractNamespaces, payload); + yield put(actions.setPreExtractedData(preExtractedData)); + yield put(actions.stepToStage(actions.STAGE2)); + } catch(error) { + yield put(messageActions.failed((error.message ? error.message : error))); + } + yield put(spinnerActions.done('Searching dependencies')); + } +} + +function* extract(){ + while(true){ + const {payload: {namespaces, dependencies, dirPath}} = yield take(actions.EXTRACT); + yield put(spinnerActions.started('Extracting the source code')); + try { + yield call( + serverApi.extractNamespaces, + namespaces, + dependencies, + dirPath + ); + yield put(actions.hide()); + yield put( + messageActions.success( + 'The source code has been extracted successfully. Find extracted namespaces in ' + dirPath + ) + ); + } catch(error) { + yield put( + messageActions.failed( + 'Extracting the source code. ' + (error.message ? error.message : error) + ) + ); + } + yield put(spinnerActions.done('Extracting the source code')); + } +} + +// main saga +export default function* mainSaga() { + yield fork(preExtract); + yield fork(extract); +}; diff --git a/src-client/modules/extractor/containers/Extractor/selectors.js b/src-client/modules/extractor/containers/Extractor/selectors.js new file mode 100644 index 00000000..b479cddb --- /dev/null +++ b/src-client/modules/extractor/containers/Extractor/selectors.js @@ -0,0 +1,26 @@ +/* + * Copyright 2015 Alexander Pustovalov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createStructuredSelector } from 'reselect'; +import { userAccountSelector } from 'modules/app/containers/AppContainer/selectors'; + +export const selectedNamespacesSelector = state => state.extractor.selectedNamespaces; +export const dependentNamespacesSelector = state => state.extractor.dependentNamespaces; +export const dependenciesSelector = state => state.extractor.dependencies; + +export const modelSelector = createStructuredSelector({ + stage: state => state.extractor.stage +}); diff --git a/src-client/modules/extractor/containers/NamespaceList/actions.js b/src-client/modules/extractor/containers/NamespaceList/actions.js new file mode 100644 index 00000000..5b1593c8 --- /dev/null +++ b/src-client/modules/extractor/containers/NamespaceList/actions.js @@ -0,0 +1,22 @@ +/* + * Copyright 2015 Alexander Pustovalov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { bindActionCreators } from 'redux'; +import { setSelectedNamespaces, preExtract } from 'modules/extractor/containers/Extractor/actions'; + +export const containerActions = (dispatch) => bindActionCreators({ + setSelectedNamespaces, preExtract +}, dispatch); diff --git a/src-client/modules/extractor/containers/NamespaceList/index.js b/src-client/modules/extractor/containers/NamespaceList/index.js new file mode 100644 index 00000000..ffaf8aa6 --- /dev/null +++ b/src-client/modules/extractor/containers/NamespaceList/index.js @@ -0,0 +1,130 @@ +/* + * Copyright 2015 Alexander Pustovalov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import {includes, findIndex} from 'lodash'; +import React, { Component, PropTypes } from 'react'; +import { connect } from 'react-redux'; +import { modelSelector } from './selectors.js'; +import { containerActions } from './actions.js'; + +import { Grid, Row, Col } from 'react-bootstrap'; +import { ListGroup, ListGroupItem } from 'react-bootstrap'; + +const labelContainerStyle = { + display: 'flex', + flexDirection: 'row', + alignItems: 'center', +}; + +const labelStyle = { + margin: 0, + whiteSpace: 'wrap', + wordBreak: 'break-all' +}; + +const checkBoxLabelStyle = { + width: '1.5em', + minWidth: '1.5em', + flexGrow: 0, +}; + +let checkBoxStyle = { + margin: 0, +}; + +class Container extends Component { + + constructor(props) { + super(props); + this.handleSelectNamespace = this.handleSelectNamespace.bind(this); + this.handlePreExtract = this.handlePreExtract.bind(this); + } + + handleSelectNamespace(e){ + const namespace = e.currentTarget.dataset.namespace; + const selectedNamespaces = [].concat(this.props.selectedNamespaces); + const foundIndex = findIndex(selectedNamespaces, i => i === namespace); + if (foundIndex >= 0) { + selectedNamespaces.splice(foundIndex, 1); + } else { + selectedNamespaces.push(namespace); + } + this.props.setSelectedNamespaces(selectedNamespaces); + } + + handlePreExtract(e) { + e.stopPropagation(); + e.preventDefault(); + this.props.preExtract(this.props.selectedNamespaces); + } + + render(){ + const {availableNamespaces, selectedNamespaces} = this.props; + let namespacesItems = []; + if (availableNamespaces && availableNamespaces.length > 0) { + availableNamespaces.forEach((item, index) => { + namespacesItems.push( + +
+
+ +
+
+ {item} +
+
+
+ ) + }); + } + + return ( + + + + + {namespacesItems} + +
+ +
+ +
+
+ ); + } +} + +export default connect(modelSelector, containerActions)(Container); + diff --git a/src-client/modules/extractor/containers/NamespaceList/reducer.js b/src-client/modules/extractor/containers/NamespaceList/reducer.js new file mode 100644 index 00000000..1a291fed --- /dev/null +++ b/src-client/modules/extractor/containers/NamespaceList/reducer.js @@ -0,0 +1,28 @@ +/* + * Copyright 2015 Alexander Pustovalov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as actions from './actions.js'; + +const initialState = { +}; + +export default (state = initialState, action = {}) => { + + const {type, payload} = action; + + return state; +} + diff --git a/src-client/modules/extractor/containers/NamespaceList/sagas.js b/src-client/modules/extractor/containers/NamespaceList/sagas.js new file mode 100644 index 00000000..4a3fb834 --- /dev/null +++ b/src-client/modules/extractor/containers/NamespaceList/sagas.js @@ -0,0 +1,19 @@ +/* + * Copyright 2015 Alexander Pustovalov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// main saga +export default function* mainSaga() { +}; diff --git a/src-client/modules/extractor/containers/NamespaceList/selectors.js b/src-client/modules/extractor/containers/NamespaceList/selectors.js new file mode 100644 index 00000000..b22b6ba5 --- /dev/null +++ b/src-client/modules/extractor/containers/NamespaceList/selectors.js @@ -0,0 +1,24 @@ +/* + * Copyright 2015 Alexander Pustovalov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createStructuredSelector } from 'reselect'; +import {availableNamespacesSelector} from 'modules/workspace/containers/LibraryPanel/selectors'; +import {selectedNamespacesSelector} from 'modules/extractor/containers/Extractor/selectors'; + +export const modelSelector = createStructuredSelector({ + availableNamespaces: availableNamespacesSelector, + selectedNamespaces: selectedNamespacesSelector, +}); diff --git a/src-client/modules/extractor/index.js b/src-client/modules/extractor/index.js new file mode 100644 index 00000000..793bfe38 --- /dev/null +++ b/src-client/modules/extractor/index.js @@ -0,0 +1,19 @@ +/* + * Copyright 2015 Alexander Pustovalov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export Extractor from 'modules/extractor/containers/Extractor'; +export NamespaceList from 'modules/extractor/containers/NamespaceList'; +export ExtractList from 'modules/extractor/containers/ExtractList'; diff --git a/src-client/modules/generator/containers/Generator/index.js b/src-client/modules/generator/containers/Generator/index.js index 5ae16d4d..d21ab1ab 100644 --- a/src-client/modules/generator/containers/Generator/index.js +++ b/src-client/modules/generator/containers/Generator/index.js @@ -31,7 +31,7 @@ const toolbarLabelStyle = { }; const labelSectionStyle = { width: '35%', - margin: '0, 2em' + margin: '0 2em' }; const centerSectionStyle = { width: '30%', diff --git a/src-client/modules/installer/containers/Installer/actions.js b/src-client/modules/installer/containers/Installer/actions.js new file mode 100644 index 00000000..e6ba83df --- /dev/null +++ b/src-client/modules/installer/containers/Installer/actions.js @@ -0,0 +1,29 @@ +/* + * Copyright 2015 Alexander Pustovalov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// import validator from 'validator'; +import {bindActionCreators} from 'redux'; +import {hideInstaller} from 'modules/app/containers/AppContainer/actions'; + +// export const STEP_TO_STAGE = "Generator/STEP_TO_STAGE"; + +// export const stepToStage = (stage) => ({type: STEP_TO_STAGE, payload: stage}); +// export const setComponentMetadata = (metaData, metaHelp) => (dispatch, getState) => { +// dispatch({type: SET_COMPONENT_METADATA, payload: {metaData, metaHelp}}); +// }; +export const containerActions = (dispatch) => bindActionCreators({ + hideInstaller +}, dispatch); diff --git a/src-client/modules/installer/containers/Installer/index.js b/src-client/modules/installer/containers/Installer/index.js new file mode 100644 index 00000000..e7855b36 --- /dev/null +++ b/src-client/modules/installer/containers/Installer/index.js @@ -0,0 +1,249 @@ +/* + * Copyright 2015 Alexander Pustovalov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, { Component, PropTypes } from 'react'; +import { connect } from 'react-redux'; +import { modelSelector } from './selectors.js'; +import { containerActions } from './actions.js'; +import imgSrc from 'assets/app/css/img/umylogo-white.svg'; + +import { ButtonGroup, Button } from 'react-bootstrap'; +import { NamespaceCard } from 'components'; + +const containerStyle = { + position: 'absolute', + top: '0px', + left: '0px', + right: '0px', + bottom: '0px', + overflow: 'auto', + display: 'flex', +}; +const toolbarContainerStyle = { + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + width: '100%', +}; +const toolbarLabelStyle = { + margin: '0 1em' +}; +const logoSectionStyle = { + width: '10em', + padding: '0 2em', +}; +const closeSectionStyle = { + width: '10em', + padding: '0 2em', +}; +const centerSectionStyle = { + display: 'flex', + flexGrow: 2, + justifyContent: 'center' +}; +const toolbarSectionStyle = { + width: '100%', + display: 'flex', + justifyContent: 'center', + margin: '2em 0 2em 0', +}; +const galleryStyle = { + display: 'flex', + flexDirection: 'row', + flexFlow: 'wrap', + justifyContent: 'center', + alignContent: 'stretch', +}; +const namespaceCardStyle = { + margin: '1em 1em 0 1em', + // width: '45%', + flexGrow: 0, +}; +const toolbarStyle = { + display: 'flex', + alignItems: 'center', + flexDirection: 'row', +}; + +class Container extends Component { + + constructor(props) { + super(props); + this.handleClose = this.handleClose.bind(this); + this.handleSelectFile = this.handleSelectFile.bind(this); + this.handleBrowseFiles = this.handleBrowseFiles.bind(this); + this.state = { + selectedFile: null, + }; + } + + componentDidMount() { + this.containerElement.scrollTop = 0; + } + + componentDidUpdate() { + this.containerElement.scrollTop = 0; + } + + handleClose(e) { + e.stopPropagation(); + e.preventDefault(); + this.props.hideInstaller(); + } + + handleSelectFile(e) { + console.log(this.fileUpload.files[0]); + // this.setState({selectedFile: this.fileUpload.files[0]}); + } + + handleBrowseFiles(e) { + this.fileUpload.click(); + } + + render(){ + const { filteredNamespaces, searchText, limit } = this.props; + console.log(JSON.stringify(filteredNamespaces, null, 4)); + let namespacesCards = []; + for (let i = 0; i < filteredNamespaces.length; i++) { + if (i >= limit) { + break; + } + const {namespace, repoName, stars, repoLink, namespaceDescription} = filteredNamespaces[i]; + namespacesCards.push( + + ); + } + return ( +
this.containerElement = me} + id="containerElement" + style={containerStyle} + > +
+
+
+
+
+
+
+
+

Structor

+
+
+ +
+
+

Market

+
+
+
+
+
+

+ +

+

+ Close +

+
+
+
+
+
+
+ {filteredNamespaces.length} items found +
+
+
+ this.inputElement = me} + type="text" + className="form-control" + placeholder="Filter..." + value={searchText} + /> + + + +
+
+
+ + this.fileUpload = ref} + onChange={this.handleSelectFile} + /> +
+
+
+
+
+
+
+ {namespacesCards} +
+ {filteredNamespaces && filteredNamespaces.length > limit && +
+
+ Listed {namespacesCards.length} items. Show More... +
+
+ } +
+
+ ); + } + +} + +export default connect(modelSelector, containerActions)(Container); + diff --git a/src-client/modules/installer/containers/Installer/reducer.js b/src-client/modules/installer/containers/Installer/reducer.js new file mode 100644 index 00000000..b15a4084 --- /dev/null +++ b/src-client/modules/installer/containers/Installer/reducer.js @@ -0,0 +1,39 @@ +/* + * Copyright 2015 Alexander Pustovalov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as actions from './actions.js'; +import testData from './testData.js'; + +const initialState = { + allNamespaces: testData, + filteredNamespaces: testData, + searchText: null, + limit: 12, +}; + +export default (state = initialState, action = {}) => { + + const {type, payload} = action; + + // if(type === actions.STEP_TO_STAGE){ + // return Object.assign({}, state, { + // stage: payload + // }); + // } + + return state; +} + diff --git a/src-client/modules/installer/containers/Installer/sagas.js b/src-client/modules/installer/containers/Installer/sagas.js new file mode 100644 index 00000000..21a03aac --- /dev/null +++ b/src-client/modules/installer/containers/Installer/sagas.js @@ -0,0 +1,128 @@ +/* + * Copyright 2015 Alexander Pustovalov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// import { fork, take, call, put, cancel } from 'redux-saga/effects'; +// import { SagaCancellationException } from 'redux-saga'; +// import * as actions from './actions.js'; +// import * as spinnerActions from 'modules/app/containers/AppSpinner/actions'; +// import * as messageActions from 'modules/app/containers/AppMessage/actions'; +// import * as generatorListActions from 'modules/generator/containers/GeneratorList/actions'; +// import * as appContainerActions from 'modules/app/containers/AppContainer/actions'; +// import * as deskPageActions from 'modules/workspace/containers/DeskPage/actions'; +// import * as clipboardIndicatorActions from 'modules/workspace/containers/ClipboardIndicator/actions'; +// import * as libraryPanelActions from 'modules/workspace/containers/LibraryPanel/actions'; +// import * as selectionBreadcrumbsActions from 'modules/workspace/containers/SelectionBreadcrumbs/actions'; +// import { serverApi, graphApi, coockiesApi } from 'api'; +// import * as historyActions from 'modules/workspace/containers/HistoryControls/actions'; + +// function* pregenerate(){ +// while(true){ +// const {payload: { +// generatorName, generatorDirPath, namespace, componentName, modelNode +// }} = yield take(actions.PREGENERATE); +// yield put(spinnerActions.started('Retrieving metadata')); +// try { +// const pregeneratedData = +// yield call( +// serverApi.pregenerate, +// generatorName, +// generatorDirPath, +// namespace, +// componentName, +// modelNode +// ); +// yield put(actions.setComponentMetadata(pregeneratedData.metaData, pregeneratedData.metaHelp)); +// yield put(actions.stepToStage(actions.STAGE3)); +// let recentGenerators = coockiesApi.addToRecentGenerators(generatorName); +// yield put(generatorListActions.setRecentGenerators(recentGenerators)); +// } catch(error) { +// yield put(messageActions.failed('Metadata retrieving has an error. ' + (error.message ? error.message : error))); +// } +// yield put(spinnerActions.done('Retrieving metadata')); +// } +// } +// +// function* generate(){ +// while(true){ +// const {payload: { +// generatorName, generatorDirPath, namespace, componentName, modelNode, metaData +// }} = yield take(actions.GENERATE); +// yield put(spinnerActions.started('Generating the source code')); +// try { +// const generatedData = yield call( +// serverApi.generate, +// generatorName, +// generatorDirPath, +// namespace, +// componentName, +// modelNode, +// metaData +// ); +// yield put(actions.setGeneratedData(generatedData)); +// yield put(actions.stepToStage(actions.STAGE4)); +// } catch(error) { +// yield put(messageActions.failed('The source code generation has an error. ' + (error.message ? error.message : error))); +// } +// yield put(spinnerActions.done('Generating the source code')); +// } +// } +// +// function* saveGenerated(){ +// while(true){ +// const {payload: {selectedKey, newModelNode, files, dependencies}} = yield take(actions.SAVE_GENERATED); +// yield put(spinnerActions.started('Installing & saving the source code')); +// try { +// yield call(serverApi.saveGenerated, files, dependencies); +// graphApi.changeModelNodeType(selectedKey, newModelNode); +// yield put(clipboardIndicatorActions.removeClipboardKeys()); +// yield put(selectionBreadcrumbsActions.setSelectedKey(selectedKey)); +// yield put(libraryPanelActions.loadComponents()); +// yield put(deskPageActions.setReloadPageRequest()); +// yield put(actions.hide()); +// yield put(historyActions.pushHistory()); +// } catch(error) { +// yield put(messageActions.failed('Source code installation has an error. ' + (error.message ? error.message : error))); +// } +// yield put(spinnerActions.done('Installing & saving the source code')); +// } +// } +// +// function* loadGenerators(){ +// while(true){ +// yield take(actions.LOAD_GENERATORS); +// yield put(spinnerActions.started('Loading generators')); +// try { +// let generatorsList = yield call(serverApi.getAvailableGeneratorsList); +// const recentGenerators = coockiesApi.getRecentGenerators(); +// yield put(generatorListActions.setGenerators(generatorsList)); +// yield put(generatorListActions.setRecentGenerators(recentGenerators)); +// yield put(appContainerActions.showGenerator()); +// } catch(error) { +// yield put(messageActions.failed('Generators loading has an error. ' + (error.message ? error.message : error))); +// } +// yield put(spinnerActions.done('Loading generators')); +// } +// } + +// main saga +export default function* mainSaga() { + // yield fork(loadGenerators); + // // yield fork(loadAllGenerators); + // yield fork(pregenerate); + // yield fork(generate); + // // yield fork(remove); + // yield fork(saveGenerated); +}; diff --git a/src-client/modules/installer/containers/Installer/selectors.js b/src-client/modules/installer/containers/Installer/selectors.js new file mode 100644 index 00000000..ae8de484 --- /dev/null +++ b/src-client/modules/installer/containers/Installer/selectors.js @@ -0,0 +1,27 @@ +/* + * Copyright 2015 Alexander Pustovalov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createStructuredSelector } from 'reselect'; +// import { userAccountSelector } from 'modules/app/containers/AppContainer/selectors'; + +// export const filteredNamespacesSelector = state => state.installer.filteredNamespaces; + +export const modelSelector = createStructuredSelector({ + allNamespaces: state => state.installer.allNamespaces, + filteredNamespaces: state => state.installer.filteredNamespaces, + searchText: state => state.installer.searchText, + limit: state => state.installer.limit, +}); diff --git a/src-client/modules/installer/containers/SelectDirectoryModal/actions.js b/src-client/modules/installer/containers/SelectDirectoryModal/actions.js new file mode 100644 index 00000000..0165b5b5 --- /dev/null +++ b/src-client/modules/installer/containers/SelectDirectoryModal/actions.js @@ -0,0 +1,27 @@ +/* + * Copyright 2015 Alexander Pustovalov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { bindActionCreators } from 'redux'; + +export const HIDE_MODAL = "ConfirmationModal/HIDE_MODAL"; +export const SHOW_MODAL = "ConfirmationModal/SHOW_MODAL"; + +export const hideModal = () => ({type: HIDE_MODAL}); +export const showModal = (message, accept, cancel) => ({type: SHOW_MODAL, payload: {message, accept, cancel}}); + +export const containerActions = (dispatch) => bindActionCreators({ + hideModal +}, dispatch); diff --git a/src-client/modules/installer/containers/SelectDirectoryModal/index.js b/src-client/modules/installer/containers/SelectDirectoryModal/index.js new file mode 100644 index 00000000..23205997 --- /dev/null +++ b/src-client/modules/installer/containers/SelectDirectoryModal/index.js @@ -0,0 +1,95 @@ +/* + * Copyright 2015 Alexander Pustovalov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import marked from 'marked'; +import React, { Component, PropTypes } from 'react'; +import { connect } from 'react-redux'; +import { modelSelector } from './selectors.js'; +import { containerActions } from './actions.js'; + +import { Modal, Button } from 'react-bootstrap'; +import { ProxyInput } from 'components'; + +class Container extends Component { + + constructor(props) { + super(props); + this.handleCancel = this.handleCancel.bind(this); + this.handleAccept = this.handleAccept.bind(this); + } + + handleCancel(e){ + if (e) { + e.stopPropagation(); + e.preventDefault(); + } + const { componentModel: {cancel}, hideModal } = this.props; + if (cancel) { + cancel(); + } + hideModal(); + } + + handleAccept(e){ + if (e) { + e.stopPropagation(); + e.preventDefault(); + } + const { componentModel: {accept}, hideModal } = this.props; + if (accept) { + accept(); + } + hideModal(); + } + + render() { + const { componentModel: {show, message} } = this.props; + return ( + + + Confirm + + +
+ {message && +
+ } +
+ + + + + + + ); + } + +} + +export default connect(modelSelector, containerActions)(Container); + diff --git a/src-client/modules/installer/containers/SelectDirectoryModal/reducer.js b/src-client/modules/installer/containers/SelectDirectoryModal/reducer.js new file mode 100644 index 00000000..c8546561 --- /dev/null +++ b/src-client/modules/installer/containers/SelectDirectoryModal/reducer.js @@ -0,0 +1,50 @@ +/* + * Copyright 2015 Alexander Pustovalov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as actions from './actions.js'; + +const initialState = { + show: false, + message: null, + accept: null, + cancel: null, +}; + +export default (state = initialState, action = {}) => { + + const {type, payload} = action; + + if(type === actions.HIDE_MODAL){ + return Object.assign({}, state, { + show: false, + message: null, + accept: null, + cancel: null + }); + } + + if(type === actions.SHOW_MODAL){ + return Object.assign({}, state, { + show: true, + message: payload.message, + accept: payload.accept, + cancel: payload.cancel, + }); + } + + return state; +} + diff --git a/src-client/modules/installer/containers/SelectDirectoryModal/sagas.js b/src-client/modules/installer/containers/SelectDirectoryModal/sagas.js new file mode 100644 index 00000000..4a3fb834 --- /dev/null +++ b/src-client/modules/installer/containers/SelectDirectoryModal/sagas.js @@ -0,0 +1,19 @@ +/* + * Copyright 2015 Alexander Pustovalov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// main saga +export default function* mainSaga() { +}; diff --git a/src-client/modules/installer/containers/SelectDirectoryModal/selectors.js b/src-client/modules/installer/containers/SelectDirectoryModal/selectors.js new file mode 100644 index 00000000..2e686a40 --- /dev/null +++ b/src-client/modules/installer/containers/SelectDirectoryModal/selectors.js @@ -0,0 +1,22 @@ +/* + * Copyright 2015 Alexander Pustovalov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createStructuredSelector } from 'reselect'; + +export const modelSelector = createStructuredSelector({ + componentModel: state => state.confirmationModal, +}); + diff --git a/src-client/modules/installer/index.js b/src-client/modules/installer/index.js new file mode 100644 index 00000000..41a236f9 --- /dev/null +++ b/src-client/modules/installer/index.js @@ -0,0 +1,17 @@ +/* + * Copyright 2015 Alexander Pustovalov + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export Installer from './containers/Installer'; diff --git a/src-client/modules/workspace/containers/ComponentOptionsPanel/index.js b/src-client/modules/workspace/containers/ComponentOptionsPanel/index.js index 7b1e2385..c8bb1764 100644 --- a/src-client/modules/workspace/containers/ComponentOptionsPanel/index.js +++ b/src-client/modules/workspace/containers/ComponentOptionsPanel/index.js @@ -227,7 +227,7 @@ class Container extends Component {
{styleOptionInputs}
-
+
); @@ -246,7 +246,7 @@ class Container extends Component { optionInputs.push( (dispatch, getState) => { - const {dir} = projectPaths; - const extractDirPath = dir + '_' + namespace; - dispatch(confirmModal( - `The source code of ${namespace} namespace will be extracted into directory\n\n` + - '```' + extractDirPath + '```', - () => dispatch({type: EXTRACT_NAMESPACE, payload: {namespace}}) - )); -}; +import {showInstaller, showExtractor} from 'modules/app/containers/AppContainer/actions'; export const containerActions = (dispatch) => bindActionCreators({ - extractNamespace + showInstaller, showExtractor }, dispatch); diff --git a/src-client/modules/workspace/containers/LibraryControls/index.js b/src-client/modules/workspace/containers/LibraryControls/index.js index 17e4af1c..56e35425 100644 --- a/src-client/modules/workspace/containers/LibraryControls/index.js +++ b/src-client/modules/workspace/containers/LibraryControls/index.js @@ -34,17 +34,17 @@ class Container extends Component { onInstall(e) { e.stopPropagation(); e.preventDefault(); + this.props.showInstaller(); } onExtract(e) { e.stopPropagation(); e.preventDefault(); - const {namespace, projectPaths, extractNamespace} = this.props; - extractNamespace(namespace, projectPaths); + const {showExtractor} = this.props; + showExtractor(); } render(){ - const {namespace} = this.props; return (
); @@ -243,17 +225,18 @@ class Container extends Component { data-componentkey={componentKey} onClick={this.handleToggleItem} > - {makeTitle(componentId)} - - {isExpandedComponent ? - - : - - } - +
+
+ {makeTitle(componentId)} +
+
+ {isExpandedComponent ? + + : + + } +
+
); if (isExpandedComponent) { @@ -270,7 +253,18 @@ class Container extends Component { onClick={this.handleQuickCopyToClipboard} >
-
+
+ +
+
+ + {makeTitle(componentModel.variant)} + +
+
{modelIndex > 0 && }
-
- {makeTitle(componentModel.variant)} -
); @@ -303,7 +294,7 @@ class Container extends Component { data-index={0} onClick={this.handleQuickCopyToClipboard} > - {makeTitle(componentId)} + {makeTitle(componentId)} ); } @@ -320,7 +311,7 @@ class Container extends Component { } } = this.props; - const {filter, selectedNamespace} = this.state; + const {filter} = this.state; let libGroups = []; @@ -348,7 +339,7 @@ class Container extends Component { } }); libGroups.push( - this.createGroupingPanel(recentGroupKey, 'Recently Used', components, collapsed, false, false) + this.createGroupingPanel(recentGroupKey, 'Recently Used', components, collapsed, false) ); } @@ -372,7 +363,7 @@ class Container extends Component { } }); if (noGroupItems.length > 0) { - libGroups.push(this.createGroupingPanel(noGroupGroupKey, 'Components', noGroupItems, collapsed, false)); + libGroups.push(this.createGroupingPanel(noGroupGroupKey, 'Components', noGroupItems, collapsed)); } } @@ -398,7 +389,7 @@ class Container extends Component { } }); if (groupItems.length > 0) { - libGroups.push(this.createGroupingPanel(groupKey, moduleId, groupItems, collapsed, true)); + libGroups.push(this.createGroupingPanel(groupKey, moduleId, groupItems, collapsed)); } } }); @@ -422,7 +413,7 @@ class Container extends Component { } }); if (htmlItems.length > 0) { - libGroups.push(this.createGroupingPanel(htmlGroupKey, 'HTML', htmlItems, collapsed, false)); + libGroups.push(this.createGroupingPanel(htmlGroupKey, 'HTML', htmlItems, collapsed)); } } @@ -432,7 +423,6 @@ class Container extends Component {
diff --git a/src-client/modules/workspace/containers/PageExportControls/actions.js b/src-client/modules/workspace/containers/PageExportControls/actions.js index 4a7ce5cb..d83e3f08 100644 --- a/src-client/modules/workspace/containers/PageExportControls/actions.js +++ b/src-client/modules/workspace/containers/PageExportControls/actions.js @@ -16,39 +16,60 @@ import { bindActionCreators } from 'redux'; import { graphApi } from 'api'; +import {showModal as confirmModal} from 'modules/app/containers/ConfirmationModal/actions'; export const GENERATE_APPLICATION = "PageListPanel/GENERATE_APPLICATION"; export const exportPages = (pages) => (dispatch, getState) => { - let pagesModel = []; - let pageModel; - if (pages && pages.length > 0) { - pages.forEach(page => { - pageModel = graphApi.getPageModelByPagePath(page.pagePath); - if (pageModel) { - pagesModel.push(pageModel); + dispatch(confirmModal( + 'The source code of the selected pages will be saved into the directory:\n\n' + + '`/routes`\n\n' + + '**Warning:** The content of this directory will be rewritten', + () => { + let pagesModel = []; + let pageModel; + if (pages && pages.length > 0) { + pages.forEach(page => { + pageModel = graphApi.getPageModelByPagePath(page.pagePath); + if (pageModel) { + pagesModel.push(pageModel); + } + }); } - }); - } - if (pagesModel.length > 0) { - dispatch({type: GENERATE_APPLICATION, payload: {pagesModel, hasApplicationFiles: false}}); - } + if (pagesModel.length > 0) { + dispatch({type: GENERATE_APPLICATION, payload: {pagesModel, hasApplicationFiles: false}}); + } + } + )); }; export const exportApplication = (pages) => (dispatch, getState) => { - let pagesModel = []; - let pageModel; - if (pages && pages.length > 0) { - pages.forEach(page => { - pageModel = graphApi.getPageModelByPagePath(page.pagePath); - if (pageModel) { - pagesModel.push(pageModel); + dispatch(confirmModal( + 'The source code of the selected pages will be saved into the directory:\n\n' + + '`/routes`\n\n' + + 'The following files will be created in ``\n\n' + + '* **store.js** - Redux store\n' + + '* **reducers.js** - Redux global reducer combination\n' + + '* **sagas.js** - Sagas combination\n' + + '* **index.js** - Application main entry file\n\n' + + '**Note:** The content of the directory and files will be rewritten\n' + + '', + () => { + let pagesModel = []; + let pageModel; + if (pages && pages.length > 0) { + pages.forEach(page => { + pageModel = graphApi.getPageModelByPagePath(page.pagePath); + if (pageModel) { + pagesModel.push(pageModel); + } + }); + } + if (pagesModel.length > 0) { + dispatch({type: GENERATE_APPLICATION, payload: {pagesModel, hasApplicationFiles: true}}); } - }); - } - if (pagesModel.length > 0) { - dispatch({type: GENERATE_APPLICATION, payload: {pagesModel, hasApplicationFiles: true}}); - } + } + )); }; export const containerActions = (dispatch) => bindActionCreators({ diff --git a/src-client/modules/workspace/containers/PageListControls/actions.js b/src-client/modules/workspace/containers/PageListControls/actions.js index 12020ea4..4d287701 100644 --- a/src-client/modules/workspace/containers/PageListControls/actions.js +++ b/src-client/modules/workspace/containers/PageListControls/actions.js @@ -14,8 +14,18 @@ * limitations under the License. */ import { bindActionCreators } from 'redux'; -import { changePageRoute, deletePage } from 'modules/workspace/containers/DeskPage/actions'; +import { changePageRoute, deletePage as deleteDeskPage } from 'modules/workspace/containers/DeskPage/actions'; import { showModal } from 'modules/workspace/containers/PageOptionsModal/actions'; +import { showModal as confirmModal } from 'modules/app/containers/ConfirmationModal/actions'; + +export const deletePage = () => (dispatch, getState) => { + dispatch(confirmModal( + '#### Are you sure you want to delete the current page?', + () => { + dispatch(deleteDeskPage()); + } + )); +}; export const containerActions = (dispatch) => bindActionCreators({ changePageRoute, showModal, deletePage diff --git a/src-client/modules/workspace/containers/PageListControls/index.js b/src-client/modules/workspace/containers/PageListControls/index.js index 2bd28162..f2b57b5e 100644 --- a/src-client/modules/workspace/containers/PageListControls/index.js +++ b/src-client/modules/workspace/containers/PageListControls/index.js @@ -50,9 +50,7 @@ class Container extends Component { handleDeletePage(e) { e.stopPropagation(); e.preventDefault(); - if(confirm('Are you sure you want to delete current page?')){ - this.props.deletePage(); - } + this.props.deletePage(); } handleShowModal(e) { diff --git a/src-client/modules/workspace/containers/PageListPanel/index.js b/src-client/modules/workspace/containers/PageListPanel/index.js index 64714171..5172e901 100644 --- a/src-client/modules/workspace/containers/PageListPanel/index.js +++ b/src-client/modules/workspace/containers/PageListPanel/index.js @@ -21,7 +21,7 @@ import {utilsStore} from 'api'; import {modelSelector} from './selectors.js'; import {containerActions} from './actions.js'; import PageExportControls from 'modules/workspace/containers/PageExportControls'; -import { Modal, Button, ListGroup, ListGroupItem } from 'react-bootstrap'; +import { ListGroup, ListGroupItem } from 'react-bootstrap'; const topToolbarStyle = { paddingTop: '10px', diff --git a/src-client/modules/workspace/containers/SaveDefaultModelModal/actions.js b/src-client/modules/workspace/containers/SaveDefaultModelModal/actions.js index 281a731b..1245f017 100644 --- a/src-client/modules/workspace/containers/SaveDefaultModelModal/actions.js +++ b/src-client/modules/workspace/containers/SaveDefaultModelModal/actions.js @@ -32,6 +32,7 @@ export const submit = (currentComponent, variantName) => (dispatch, getState) => let newDefaults = defaults && defaults.length > 0 ? cloneDeep(defaults) : []; let foundExisting = newDefaults.find(i => i.variant === variantName); if (foundExisting) { + foundExisting.variant = variantName; foundExisting.props = props || {}; foundExisting.text = text; foundExisting.children = children || []; diff --git a/src-client/modules/workspace/containers/SaveDefaultModelModal/index.js b/src-client/modules/workspace/containers/SaveDefaultModelModal/index.js index 6662c1ee..a842eb7e 100644 --- a/src-client/modules/workspace/containers/SaveDefaultModelModal/index.js +++ b/src-client/modules/workspace/containers/SaveDefaultModelModal/index.js @@ -68,7 +68,7 @@ class Container extends Component { render() { const { componentModel: {show}, currentComponent } = this.props; const {errors} = this.state; - + let title = ''; let items = []; if (currentComponent) { const {defaults} = currentComponent; @@ -79,16 +79,19 @@ class Container extends Component { href="#" key={'' + item.variant + index} style={{position: 'relative'}} - data-variant={item.variant} + data-variant={item.variant || 'default'} onClick={this.handleSubmitExisting} > - {item.variant} + {item.variant || 'default'} ); }); } + title = `Save Model for ${currentComponent.componentName}`; + if (currentComponent.namespace) { + title += ` [${currentComponent.namespace}]`; + } } - return ( - Save Model + {title} {errors && errors.length > 0 && diff --git a/src-client/modules/workspace/containers/SelectionBreadcrumbs/index.js b/src-client/modules/workspace/containers/SelectionBreadcrumbs/index.js index d0c86c73..7acb59f2 100644 --- a/src-client/modules/workspace/containers/SelectionBreadcrumbs/index.js +++ b/src-client/modules/workspace/containers/SelectionBreadcrumbs/index.js @@ -104,9 +104,9 @@ class Container extends Component { Selected:  - - {(rootItem.modelNode.pageName ? rootItem.modelNode.pagePath : 'Unknown')} - + {/**/} + {/*{(rootItem.modelNode.pageName ? rootItem.modelNode.pagePath : 'Unknown')}*/} + {/**/} ); @@ -171,7 +171,10 @@ class Container extends Component { ); } else { - if(childrenMenuItems.length > 0){ + if (item.modelNode.namespace) { + componentTitle += ' [' + item.modelNode.namespace + ']'; + } + if(childrenMenuItems.length > 0){ content.push(
  • - {item.modelNode.type}  + {componentTitle} 
      ); } else { - content.push( + content.push(
    • 0) { + // find all components out of any namespace + const filtered = modelComponentList.filter(item => { + return !item.namespace + }); + if (filtered && filtered.length > 0) { + throw Error('Component models are including components out of any namespace.'); + } + modelComponentList.forEach(item => { + if (!includes(resultNamespaces, item.namespace) + && !includes(newNamespaces, item.namespace)) { + newNamespaces.push(item.namespace); + } + }); + } + return gengine.getModulesImports(componentTree, checkingNamespaces) + .then(imports => { + // console.log('Imports :', JSON.stringify(imports, null, 4)); + if (imports && imports.length > 0) { + imports.forEach(importItem => { + if (importItem && !isEmpty(importItem)) { + forOwn(importItem, (value, prop) => { + const {source} = value; + if (source && source.length > 0) { + let importPath = source.replace(/\\/g, '/'); + if (source.indexOf('.') !== 0) { + let importPathParts = importPath.split('/'); + if (importPathParts && importPathParts.length > 0) { + if (importPathParts[0] === 'modules') { + if (!includes(resultNamespaces, importPathParts[1]) + && !includes(newNamespaces, importPathParts[1])) { + newNamespaces.push(importPathParts[1]); + } + } else { + if (!includes(resultModules, importPathParts[0])) { + resultModules.push(importPathParts[0]); + } + } + } + } + } + }); + } + }); + } + if (newNamespaces.length > 0) { + return getDependentNamespaces(componentTree, newNamespaces, resultNamespaces, resultModules); + } + return {depNamespaces: resultNamespaces, modules: resultModules}; + }) +} + +export function getAllDependencies(namespaces) { + let result = { + dependencies: { + packages: [], + }, + }; + let componentTree; + return storage.getComponentTree() + .then(tree => { + componentTree = tree; + }) + .then(() => { + return getDependentNamespaces(componentTree, namespaces); + }) + .then(deps => { + const {depNamespaces, modules} = deps; + result.namespaces = depNamespaces; + let tasks = []; + if (modules && modules.length > 0) { + modules.forEach(dep => { + tasks.push( + commons.getPackageVersion(dep, config.getProjectDir()) + .then(version => { + if (version) { + result.dependencies.packages.push({ + name: dep, + version: version, + }); + } + }) + ); + }); + } + return Promise.all(tasks).then(() => { return result; }); + }); +} + +export function extractNamespaces(namespaces, dependencies, dirPath) { + const sandboxGeneratorPath = config.sandboxGeneratorDirPath(); + const sandboxModulesDirPath = path.join(config.sandboxDirPath(), 'modules'); + + const extractDirPath = dirPath; + const extractSrcDirPath = path.join(extractDirPath, 'modules'); + const extractDefaultsDirPath = path.join(extractDirPath, 'defaults'); + const extractDocsDirPath = path.join(extractDirPath, 'docs'); + + let generatorData = { + namespaces, + project: config.getProjectConfig(), + }; + let namespaceModule = undefined; + let structorNamespaces = { + namespaces: {}, + dependencies + }; + let componentTree; + return storage.getComponentTree() + .then(tree => { + generatorData.index = tree; + componentTree = tree; + return gengineManager.process(sandboxGeneratorPath, generatorData); + }) + .then(generatedObject => { + const {files} = generatedObject; + return storage.saveGenerated({}, files); + }) + .then(() => { + let copyTasks = []; + namespaces.forEach(namespace => { + namespaceModule = componentTree.modules[namespace]; + if (namespaceModule && namespaceModule.absolutePath) { + copyTasks.push( + commons.copyFile( + namespaceModule.absolutePath, + path.join(sandboxModulesDirPath, namespace) + ) + ); + } + }); + return Promise.all(copyTasks); + }) + .then(() => { + return sandboxCompilerManager.compileSandbox() + .catch(error => { + throw Error( + `It seems that some components include external components out of any namespace.\n\n\n ${error}` + ); + }); + }) + .then(() => { + let copyTasks = []; + const globalReducerSource = componentTree.reducersSourceCode; + namespaces.forEach(namespace => { + namespaceModule = componentTree.modules[namespace]; + if (namespaceModule && namespaceModule.absolutePath) { + const reducerFilePath = namespaceModule.reducerFilePath; + if (reducerFilePath) { + const reducerPropertyName = + gengine.getReducerPropertyName(globalReducerSource, namespaceModule.reducerImportPath); + structorNamespaces.namespaces[namespace] = structorNamespaces.namespaces[namespace] || {}; + structorNamespaces.namespaces[namespace].reducerPropName = reducerPropertyName; + } + copyTasks.push( + commons.copyFile(namespaceModule.absolutePath, path.join(extractSrcDirPath, namespace)) + .then(() => { + const docsDirPath = path.join(config.docsComponentsDirPath(), namespace); + return commons.copyFile(docsDirPath, path.join(extractDocsDirPath, namespace)); + }) + .then(() => { + const defaultsDirPath = path.join(config.componentDefaultsDirPath(), namespace); + return commons.copyFile(defaultsDirPath, path.join(extractDefaultsDirPath, namespace)); + }) + ); + } + }); + return Promise.all(copyTasks); + }) + .then(() => { + return commons.writeJson(path.join(extractDirPath, 'structor-namespaces.json'), structorNamespaces); + }) + .then(() => { + return commons.removeFile(config.sandboxDirPath()); + }); +} \ No newline at end of file diff --git a/src-server/structor/controller.js b/src-server/structor/controller.js index dbf7e690..c44fea14 100644 --- a/src-server/structor/controller.js +++ b/src-server/structor/controller.js @@ -15,7 +15,7 @@ */ import path from 'path'; -import {sortBy} from 'lodash'; +import {sortBy, forOwn} from 'lodash'; import express from 'express'; import rewrite from 'express-urlrewrite'; import httpProxy from 'http-proxy'; @@ -24,6 +24,7 @@ import * as gengineManager from '../commons/gengine'; import * as clientManager from '../commons/clientManager.js'; import * as middlewareCompilerManager from './middlewareCompilerManager.js'; import * as sandboxCompilerManager from './sandboxCompilerManager.js'; +import * as extractManager from '../commons/extractManager.js'; export const STRUCTOR_URLS = [ '/structor', @@ -238,61 +239,14 @@ export function saveGenerated(options) { return storage.saveGenerated(dependencies, files); } -export function extractNamespace(options) { - const {namespace} = options; - const sandboxGeneratorPath = config.sandboxGeneratorDirPath(); - const sandboxDirPath = path.join(config.getProjectDir(), '__sandbox', 'modules', namespace); - const extractDirPath = config.getProjectDir() + '_' + namespace; - const extractSrcDirPath = path.join(extractDirPath, 'src'); - let generatorData = { - namespace, - project: config.getProjectConfig(), - }; - let namespaceModule = undefined; - let structorNamespace = { - name: namespace, - }; - return storage.getComponentTree() - .then(tree => { - generatorData.index = tree; - if (tree.modules && tree.modules[namespace]) { - namespaceModule = tree.modules[namespace]; - } else { - throw Error(`Could not find ${namespace} module in the component tree.`); - } - return gengineManager.process(sandboxGeneratorPath, generatorData); - }) - .then(generatedObject => { - const {files, dependencies} = generatedObject; - return storage.saveGenerated(dependencies, files); - }) - .then(() => { - const namespaceDirPath = namespaceModule.absolutePath; - return commons.copyFile(namespaceDirPath, sandboxDirPath); - }) - .then(() => { - return sandboxCompilerManager.compileSandbox() - .catch(error => { - throw Error( - `It seems that some components from "${namespace}" namespace include components from another namespace.\n\n\n ${error}` - ); - }); - }) - .then(() => { - const namespaceDirPath = namespaceModule.absolutePath; - return commons.copyFile(namespaceDirPath, extractSrcDirPath); - }) - .then(() => { - const reducerFilePath = namespaceModule.reducerFilePath; - if (reducerFilePath) { - const globalReducerSource = generatorData.index.reducersSourceCode; - const reducerPropertyName = gengine.getReducerPropertyName(globalReducerSource, reducerFilePath); - structorNamespace.reducerPropertyName = reducerPropertyName; - } - }) - .then(() => { - return commons.writeJson(path.join(extractDirPath, 'structor-namespace.json'), structorNamespace); - }); +export function preExtractNamespaces(options) { + const {namespaces} = options; + return extractManager.getAllDependencies(namespaces); +} + +export function extractNamespaces(options) { + const {namespaces, dependencies, dirPath} = options; + return extractManager.extractNamespaces(namespaces, dependencies, dirPath); } export function getScaffoldGenerators(options) { diff --git a/src-server/structor/sandboxCompilerManager.js b/src-server/structor/sandboxCompilerManager.js index aa23c9ca..e8543818 100644 --- a/src-server/structor/sandboxCompilerManager.js +++ b/src-server/structor/sandboxCompilerManager.js @@ -27,8 +27,8 @@ export function compileSandbox() { try { webpackConfig = require(config.webpackConfigFilePath()); webpackConfig = cloneDeep(webpackConfig); - const entryFilePath = path.join(config.getProjectDir(), '__sandbox', 'index.js'); - const outputDirPath = path.join(config.getProjectDir(), '__sandbox'); + const entryFilePath = path.join(config.sandboxDirPath(), 'index.js'); + const outputDirPath = config.sandboxDirPath(); const outputFileName = 'bundle.js'; webpackConfig.entry = [entryFilePath]; webpackConfig.output = { @@ -36,7 +36,7 @@ export function compileSandbox() { filename: outputFileName }; webpackConfig.resolve = webpackConfig.resolve || {}; - webpackConfig.resolve.modules = ['__sandbox', 'node_modules']; + webpackConfig.resolve.modules = [config.SANDBOX_DIR, 'node_modules']; webpackConfig.stats = 'errors-only'; compiler = webpack(webpackConfig); } catch (e) { @@ -92,7 +92,7 @@ export function compileSandbox() { console.error(err); reject(err); } else if (jsonStats.errors.length > 0) { - console.log(JSON.stringify(jsonStats.modules, null, 4)); + // console.log(JSON.stringify(jsonStats.modules, null, 4)); reject(jsonStats.errors.join('\n\n')); } else { resolve(); diff --git a/src-server/structor/webpackBuilderMiddleware.js b/src-server/structor/webpackBuilderMiddleware.js index 8a31b2e7..87c1f46f 100644 --- a/src-server/structor/webpackBuilderMiddleware.js +++ b/src-server/structor/webpackBuilderMiddleware.js @@ -19,7 +19,48 @@ export default function webpackBuilderMiddleware(compiler, opts){ compiler.plugin('done', stats => { if(opts.callback){ - stats = stats.toJson(); + stats = stats.toJson({ + // Add asset Information + assets: false, + // Sort assets by a field + assetsSort: "field", + // Add information about cached (not built) modules + cached: false, + // Add children information + children: false, + // Add chunk information (setting this to `false` allows for a less verbose output) + chunks: false, + // Add built modules information to chunk information + chunkModules: false, + // Add the origins of chunks and chunk merging info + chunkOrigins: false, + // Sort the chunks by a field + chunksSort: "field", + // `webpack --colors` equivalent + colors: false, + // Add errors + errors: true, + // Add details to errors (like resolving log) + errorDetails: false, + // Add the hash of the compilation + hash: false, + // Add built modules information + modules: false, + // Sort the modules by a field + modulesSort: "field", + // Add public path information + publicPath: false, + // Add information about the reasons why modules are included + reasons: false, + // Add the source code of modules + source: false, + // Add timing information + timings: false, + // Add webpack version information + version: false, + // Add warnings + warnings: false + }); opts.callback({ status: 'done', time: stats.time,
  • diff --git a/src-client/modules/workspace/containers/LibraryControls/sagas.js b/src-client/modules/workspace/containers/LibraryControls/sagas.js index dfde33f8..4a3fb834 100644 --- a/src-client/modules/workspace/containers/LibraryControls/sagas.js +++ b/src-client/modules/workspace/containers/LibraryControls/sagas.js @@ -14,29 +14,6 @@ * limitations under the License. */ -import { fork, take, call, put, race } from 'redux-saga/effects'; -import * as actions from './actions.js'; -import * as spinnerActions from 'modules/app/containers/AppSpinner/actions'; -import * as messageActions from 'modules/app/containers/AppMessage/actions'; -import { serverApi } from 'api'; -// -//const delay = ms => new Promise(resolve => setTimeout(resolve, ms)); -// -function* extractNamespace(){ - while(true){ - const {payload: {namespace}} = yield take(actions.EXTRACT_NAMESPACE); - yield put(spinnerActions.started('Extracting the source code')); - try { - yield call(serverApi.extractNamespace, namespace); - yield put(messageActions.success('The source code has been extracted successfully.')); - } catch(error) { - yield put(messageActions.failed('Extracting the source code: ' + (error.message ? error.message : error))); - } - yield put(spinnerActions.done('Extracting the source code')); - } -} // main saga export default function* mainSaga() { - yield [fork(extractNamespace)]; - }; diff --git a/src-client/modules/workspace/containers/LibraryPanel/actions.js b/src-client/modules/workspace/containers/LibraryPanel/actions.js index 6c3a0911..0cdef53a 100644 --- a/src-client/modules/workspace/containers/LibraryPanel/actions.js +++ b/src-client/modules/workspace/containers/LibraryPanel/actions.js @@ -23,6 +23,7 @@ import { setSelectedKey } from 'modules/workspace/containers/SelectionBreadcrumb import { setForNew } from 'modules/workspace/containers/ClipboardIndicator/actions'; import { pushHistory } from 'modules/workspace/containers/HistoryControls/actions'; import { saveComponentDefaults } from 'modules/workspace/containers/SaveDefaultModelModal/actions'; +import { showModal as confirmModal } from 'modules/app/containers/ConfirmationModal/actions'; export const LOAD_COMPONENTS = "LibraryPanel/LOAD_COMPONENTS"; export const SET_COMPONENTS = "LibraryPanel/SET_COMPONENTS"; @@ -38,20 +39,24 @@ export const addRecentlyUsed = (componentName, namespace) => { }; export const deleteComponentDefault = (componentName, namespace, defaultsIndex) => (dispatch, getState) => { - const { libraryPanel: {componentTree} } = getState(); - let componentDef = undefined; - try { - componentDef = utilsStore.findComponentDef(componentTree, componentName, namespace); - const {defaults} = componentDef; - if (defaults && defaults.length > defaultsIndex) { - let newDefaults = defaults && defaults.length > 0 ? cloneDeep(defaults) : []; - newDefaults.splice(defaultsIndex, 1); - dispatch(saveComponentDefaults(componentName, namespace, newDefaults)); - } - } catch (e) { - dispatch(failed(e.message)); - } - + dispatch(confirmModal( + `#### Are you sure you want \n#### to delete ${componentName} model variant?`, + () => { + const { libraryPanel: {componentTree} } = getState(); + let componentDef = undefined; + try { + componentDef = utilsStore.findComponentDef(componentTree, componentName, namespace); + const {defaults} = componentDef; + if (defaults && defaults.length > defaultsIndex) { + let newDefaults = defaults && defaults.length > 0 ? cloneDeep(defaults) : []; + newDefaults.splice(defaultsIndex, 1); + dispatch(saveComponentDefaults(componentName, namespace, newDefaults)); + } + } catch (e) { + dispatch(failed(e.message)); + } + } + )); }; export const setComponents = (componentTree) => (dispatch, getState) => { diff --git a/src-client/modules/workspace/containers/LibraryPanel/index.js b/src-client/modules/workspace/containers/LibraryPanel/index.js index 41ecf892..647f42c3 100644 --- a/src-client/modules/workspace/containers/LibraryPanel/index.js +++ b/src-client/modules/workspace/containers/LibraryPanel/index.js @@ -57,7 +57,7 @@ const listContainerStyle = { const labelStyle = { color: 'rgb(107, 107, 107)', - textShadow: '0 1px 0px rgba(255, 255, 255, 0.8)' + textShadow: '0 1px 0px rgba(255, 255, 255, 0.8)', }; const itemLabelStyle = { @@ -81,11 +81,10 @@ const checkBoxLabelStyle = { width: '1.5em', minWidth: '1.5em', flexGrow: 0, + textAlign: 'right', }; -let checkBoxStyle = { - margin: 0, -}; +const dotSectionStyle = {flexGrow: 0, width: '1em', display: 'flex', alignItems: 'center', justifyContent: 'center'}; const subitemLabelStyle = {display: 'flex', flexDirection: 'row', alignItems: 'center'}; @@ -101,12 +100,11 @@ class Container extends Component { constructor(props) { super(props); - this.state = {filer: '', selectedNamespace: null}; + this.state = {filer: ''}; this.handleChangeFind = this.handleChangeFind.bind(this); this.handleClearFind = this.handleClearFind.bind(this); this.handleOnKeyDown = this.handleOnKeyDown.bind(this); this.handleToggleGroup = this.handleToggleGroup.bind(this); - this.handleSelectGroup = this.handleSelectGroup.bind(this); this.handleToggleItem = this.handleToggleItem.bind(this); this.handleDeleteModel = this.handleDeleteModel.bind(this); this.createGroupingPanel = this.createGroupingPanel.bind(this); @@ -115,15 +113,15 @@ class Container extends Component { } handleChangeFind(e) { - var value = this.inputElement.value; - var newState = { + let value = this.inputElement.value; + let newState = { filter: value }; this.setState(newState); } handleOnKeyDown(e) { - if (e.keyCode == 27) { + if (e.keyCode === 27) { this.handleClearFind(e); } } @@ -141,10 +139,6 @@ class Container extends Component { this.props.togglePanelGroup(key); } - handleSelectGroup(e) { - this.setState({selectedNamespace: e.currentTarget.dataset.namespace}); - } - handleToggleItem(e) { e.stopPropagation(); e.preventDefault(); @@ -173,8 +167,7 @@ class Container extends Component { } } - createGroupingPanel(key, title, items, collapsedClassName, isExtractable, isDefault = true) { - const {selectedNamespace} = this.state; + createGroupingPanel(key, title, items, collapsedClassName, isDefault = true) { return (
    -
    - {isExtractable && - - } -
    -
    - - {items.length} - -
    + {/*
    */} + {/**/} + {/*{items.length}*/} + {/**/} + {/*
    */}
    {items}
    -
    +