├── .babelrc ├── .eslintignore ├── .eslintrc ├── .eslintrc-node ├── .gitignore ├── .nvmrc ├── .travis.yml ├── LICENSE ├── README.md ├── __mocks__ ├── ace.js ├── browser-mocks.js ├── generic-stub.js ├── ipc.js └── storage.js ├── build ├── background.png ├── icon.icns ├── icon.ico ├── icon.png └── install-spinner.gif ├── contributing.md ├── gulpfile.js ├── karma.node.conf.js ├── package.json ├── scripts ├── osx │ ├── build.sh │ ├── create-test-postgresql-tables.sh │ ├── dist-linux.sh │ ├── dist-osx.sh │ ├── dist-win.sh │ ├── docker-compose.yml │ ├── install-deps.sh │ ├── install-dist-linux-deps.sh │ ├── install-dist-win-deps.sh │ ├── install-test-deps.sh │ ├── sign.sh │ ├── test-postgresql.sh │ ├── update-info-plist.py │ └── verify-sign.sh └── win │ └── setup_conda.bat ├── server.js ├── src ├── ace │ ├── ace.js │ ├── ext-language_tools.js │ ├── ext-searchbox.js │ ├── ext-settings_menu.js │ ├── keybinding-emacs.js │ ├── keybinding-vim.js │ ├── mode-json.js │ ├── mode-jula.js │ ├── mode-latex.js │ ├── mode-markdown.js │ ├── mode-mysql.js │ ├── mode-pgsql.js │ ├── mode-plain_text.js │ ├── mode-python.js │ ├── mode-r.js │ ├── mode-scala.js │ ├── mode-sql.js │ ├── mode-sqlserver.js │ ├── mode-yaml.js │ ├── readme.md │ ├── snippets │ │ ├── mysql.js │ │ ├── pgsql.js │ │ ├── python.js │ │ ├── r.js │ │ ├── rdoc.js │ │ ├── rhtml.js │ │ ├── sql.js │ │ └── sqlserver.js │ ├── theme-ambiance.js │ ├── theme-chaos.js │ ├── theme-chrome.js │ ├── theme-clouds.js │ ├── theme-clouds_midnight.js │ ├── theme-cobalt.js │ ├── theme-crimson_editor.js │ ├── theme-dawn.js │ ├── theme-dreamweaver.js │ ├── theme-eclipse.js │ ├── theme-github.js │ ├── theme-idle_fingers.js │ ├── theme-katzenmilch.js │ ├── theme-kr_theme.js │ ├── theme-kuroir.js │ ├── theme-merbivore.js │ ├── theme-merbivore_soft.js │ ├── theme-mono_industrial.js │ ├── theme-monokai.js │ ├── theme-pastel_on_dark.js │ ├── theme-solarized_dark.js │ ├── theme-solarized_light.js │ ├── theme-terminal.js │ ├── theme-textmate.js │ ├── theme-tomorrow.js │ ├── theme-tomorrow_night.js │ ├── theme-tomorrow_night_blue.js │ ├── theme-tomorrow_night_bright.js │ ├── theme-tomorrow_night_eighties.js │ ├── theme-twilight.js │ ├── theme-vibrant_ink.js │ └── theme-xcode.js ├── browser │ ├── actions │ │ ├── application.js │ │ ├── database-connection.js │ │ ├── dialogs.js │ │ ├── iopub.js │ │ ├── kernel.js │ │ └── preferences.js │ ├── components │ │ ├── ace-pane │ │ │ ├── ace-pane.css │ │ │ ├── ace-pane.js │ │ │ └── ace-pane.test.js │ │ ├── action-button.js │ │ ├── actionest │ │ │ ├── actionest-button.js │ │ │ └── actionest.css │ │ ├── block-history │ │ │ ├── block-history.css │ │ │ ├── block-history.js │ │ │ ├── expand-block-button.css │ │ │ ├── expand-block-button.js │ │ │ ├── history-blocks │ │ │ │ ├── error-block.css │ │ │ │ ├── error-block.js │ │ │ │ ├── execution-result-block.css │ │ │ │ ├── execution-result-block.js │ │ │ │ ├── image-block.css │ │ │ │ ├── image-block.js │ │ │ │ ├── input-stream-block.css │ │ │ │ ├── input-stream-block.js │ │ │ │ ├── jupyter-response-block.css │ │ │ │ ├── jupyter-response-block.js │ │ │ │ ├── postgresql-response-block.css │ │ │ │ ├── postgresql-response-block.js │ │ │ │ ├── python-error-block.css │ │ │ │ ├── python-error-block.js │ │ │ │ ├── text-stream-block.css │ │ │ │ └── text-stream-block.js │ │ │ ├── history-list.js │ │ │ ├── history-viewer.css │ │ │ └── history-viewer.js │ │ ├── brand-splashes │ │ │ ├── brand-splashes.css │ │ │ ├── logo-rodeo-grey-text.sketch │ │ │ ├── logo-rodeo-grey-text.svg │ │ │ ├── logo-rodeo-large.jsx │ │ │ ├── logo-rodeo-square-large.jsx │ │ │ ├── logo-rodeo-square-large.svg │ │ │ └── logo-rodeo-white-text.svg │ │ ├── data-frame │ │ │ ├── data-frame-loading-icon.jsx │ │ │ ├── data-frame-loading-icon.test.js │ │ │ ├── data-frame.css │ │ │ └── data-frame.jsx │ │ ├── databases │ │ │ ├── database-explorer-tree-header.css │ │ │ ├── database-explorer-tree-header.jsx │ │ │ ├── database-explorer-tree.css │ │ │ └── database-explorer-tree.jsx │ │ ├── dialogs │ │ │ ├── about-rodeo.css │ │ │ ├── about-rodeo.js │ │ │ ├── acknowledgements.css │ │ │ ├── acknowledgements.js │ │ │ ├── acknowledgements.md │ │ │ ├── ask-quit.css │ │ │ ├── ask-quit.js │ │ │ ├── environment-variables-dialog.css │ │ │ ├── environment-variables-dialog.js │ │ │ ├── modal-dialog-container.css │ │ │ ├── modal-dialog-container.js │ │ │ ├── modal-dialog.css │ │ │ ├── modal-dialog.js │ │ │ ├── rodeo-text-dark.png │ │ │ ├── stickers-pane.css │ │ │ └── stickers-pane.js │ │ ├── document-terminal │ │ │ ├── document-terminal-annotation.css │ │ │ ├── document-terminal-annotation.js │ │ │ ├── document-terminal-autocomplete.css │ │ │ ├── document-terminal-autocomplete.js │ │ │ ├── document-terminal-error.css │ │ │ ├── document-terminal-error.js │ │ │ ├── document-terminal-history.js │ │ │ ├── document-terminal-page-break.css │ │ │ ├── document-terminal-page-break.js │ │ │ ├── document-terminal-python-error.css │ │ │ ├── document-terminal-python-error.js │ │ │ ├── document-terminal-text.css │ │ │ ├── document-terminal-text.js │ │ │ ├── document-terminal.css │ │ │ ├── document-terminal.js │ │ │ ├── sticky-bottom-scroll.css │ │ │ └── sticky-bottom-scroll.js │ │ ├── empty │ │ │ ├── empty-suggestion.css │ │ │ └── empty-suggestion.js │ │ ├── files │ │ │ ├── file-list-item.jsx │ │ │ ├── file-list.css │ │ │ ├── file-list.jsx │ │ │ ├── file-tree-header.css │ │ │ ├── file-tree-header.jsx │ │ │ ├── file-tree.css │ │ │ └── file-tree.jsx │ │ ├── forms │ │ │ ├── button-referenced.css │ │ │ ├── button-referenced.js │ │ │ ├── form-item-errors.js │ │ │ ├── form-list.css │ │ │ ├── form-list.js │ │ │ ├── input-checkbox.js │ │ │ ├── input-folder.js │ │ │ ├── input-key-value-list.css │ │ │ ├── input-key-value-list.js │ │ │ ├── input-list.css │ │ │ ├── input-list.js │ │ │ ├── input-number.js │ │ │ ├── input-python-cmd.js │ │ │ ├── input-select.css │ │ │ ├── input-select.js │ │ │ ├── input-text.js │ │ │ ├── readme.md │ │ │ ├── rodeo-logo.png │ │ │ └── save-changes-button-group.js │ │ ├── gray-info │ │ │ ├── gray-info-link-list.js │ │ │ ├── gray-info-link.js │ │ │ ├── gray-info-select.js │ │ │ ├── gray-info.css │ │ │ └── gray-info.js │ │ ├── label-checkbox.jsx │ │ ├── label-checklist.jsx │ │ ├── label-input.jsx │ │ ├── layout-containers │ │ │ ├── full-screen.css │ │ │ └── full-screen.jsx │ │ ├── manage-connections │ │ │ ├── connection-button.js │ │ │ ├── connection-config.js │ │ │ ├── connection-errors.css │ │ │ ├── connection-errors.js │ │ │ ├── connection-list.js │ │ │ ├── manage-connections.css │ │ │ ├── manage-connections.js │ │ │ └── types │ │ │ │ ├── mysql-settings.js │ │ │ │ ├── postgresql-settings.js │ │ │ │ ├── redshift-settings.js │ │ │ │ └── sqlserver-settings.js │ │ ├── marked.js │ │ ├── notifications │ │ │ ├── chat-alt-flat.svg │ │ │ ├── download-cloud-flat.svg │ │ │ ├── info-notification.css │ │ │ ├── info-notification.jsx │ │ │ ├── notifications-container.css │ │ │ ├── notifications-container.jsx │ │ │ ├── notifications.actions.js │ │ │ ├── notifications.reducer.js │ │ │ ├── update-available-notification.css │ │ │ └── update-available-notification.jsx │ │ ├── packages │ │ │ ├── package-search-item-detail.jsx │ │ │ ├── package-search-item.css │ │ │ ├── package-search-item.jsx │ │ │ ├── package-search-list.css │ │ │ ├── package-search-list.jsx │ │ │ ├── packages-list.css │ │ │ └── packages-list.jsx │ │ ├── plot-preview │ │ │ ├── background-plot.jsx │ │ │ ├── document-error-flat.svg │ │ │ ├── foreground-plot.jsx │ │ │ ├── html-flat.svg │ │ │ ├── plot-preview.css │ │ │ └── plot-preview.jsx │ │ ├── prompt │ │ │ ├── prompt.css │ │ │ └── prompt.js │ │ ├── register-rodeo │ │ │ ├── areas-of-interest.yml │ │ │ ├── explanation.md │ │ │ ├── register-rodeo.css │ │ │ └── register-rodeo.jsx │ │ ├── search-text-box │ │ │ ├── search-text-box.css │ │ │ └── search-text-box.jsx │ │ ├── setup │ │ │ ├── fake-terminal.css │ │ │ ├── fake-terminal.jsx │ │ │ ├── logo-rodeo-grey-text.sketch │ │ │ ├── logo-rodeo-grey-text.svg │ │ │ ├── python-test-input.jsx │ │ │ ├── setup-article-preview.css │ │ │ ├── setup-article-preview.jsx │ │ │ ├── setup-initial.jsx │ │ │ ├── setup-install-anaconda.jsx │ │ │ ├── setup-install-package.jsx │ │ │ ├── setup-install-result-buttons.jsx │ │ │ ├── setup-manual-command.css │ │ │ ├── setup-manual-command.jsx │ │ │ ├── setup-no-jupyter.jsx │ │ │ ├── setup-no-matplotlib.jsx │ │ │ ├── setup-no-numpy.jsx │ │ │ ├── setup-no-pandas.jsx │ │ │ ├── setup-no-python.jsx │ │ │ ├── setup-no-scipy.jsx │ │ │ ├── setup-python-error.jsx │ │ │ ├── setup-ready.jsx │ │ │ ├── setup-skip-startup.css │ │ │ ├── setup-skip-startup.js │ │ │ ├── setup.css │ │ │ └── setup.jsx │ │ ├── sidebar │ │ │ ├── logo-python.svg │ │ │ ├── logo-scienceops.png │ │ │ ├── logo-yhat.sketch │ │ │ ├── logo-yhat.svg │ │ │ ├── sidebar-item.jsx │ │ │ ├── sidebar.actions.js │ │ │ ├── sidebar.css │ │ │ ├── sidebar.jsx │ │ │ ├── sidebar.reducer.js │ │ │ ├── slideout-dialog.css │ │ │ └── slideout-dialog.jsx │ │ ├── split-pane │ │ │ ├── lib │ │ │ │ ├── jquery.splitter-0.15.0.js │ │ │ │ └── jquery.splitter.css │ │ │ └── split-pane.jsx │ │ ├── tabbed-form-list-dialog │ │ │ ├── tabbed-form-list-dialog-tab.css │ │ │ ├── tabbed-form-list-dialog-tab.js │ │ │ ├── tabbed-form-list-dialog.css │ │ │ └── tabbed-form-list-dialog.js │ │ ├── tabs │ │ │ ├── closeable.css │ │ │ ├── closeable.js │ │ │ ├── tab-add.css │ │ │ ├── tab-add.js │ │ │ ├── tab-button.css │ │ │ ├── tab-button.js │ │ │ ├── tab-content-list.css │ │ │ ├── tab-content-list.jsx │ │ │ ├── tab-item.css │ │ │ ├── tab-item.js │ │ │ ├── tab-list.css │ │ │ ├── tab-list.js │ │ │ ├── tab-list.test.js │ │ │ ├── tab-overflow-image.css │ │ │ ├── tab-overflow-image.js │ │ │ ├── tabbed-pane-item.css │ │ │ ├── tabbed-pane-item.js │ │ │ ├── tabbed-pane.css │ │ │ └── tabbed-pane.js │ │ ├── tree-view │ │ │ ├── tree-view-item.js │ │ │ ├── tree-view.css │ │ │ └── tree-view.js │ │ ├── unsafe-html.js │ │ ├── unsafe-html.test.js │ │ ├── variable-viewer │ │ │ ├── variable-table.css │ │ │ ├── variable-table.jsx │ │ │ └── variable-viewer.jsx │ │ └── yhat.js │ ├── containers │ │ ├── ask-quit-dialog-viewer │ │ │ ├── ask-quit-dialog-viewer.jsx │ │ │ ├── ask-quit-dialog-viewer.reducer.js │ │ │ └── ask-quit-dialog-viewer.selectors.js │ │ ├── block-terminal-viewer │ │ │ ├── block-terminal-viewer.actions.js │ │ │ ├── block-terminal-viewer.css │ │ │ ├── block-terminal-viewer.js │ │ │ └── block-terminal-viewer.reducer.js │ │ ├── database-viewer │ │ │ ├── database-viewer.actions.js │ │ │ ├── database-viewer.js │ │ │ └── database-viewer.reducer.js │ │ ├── document-terminal-viewer │ │ │ ├── document-terminal-viewer.actions.js │ │ │ ├── document-terminal-viewer.css │ │ │ ├── document-terminal-viewer.js │ │ │ ├── document-terminal-viewer.reducer.js │ │ │ └── features.yml │ │ ├── editor-tab-group │ │ │ ├── ace.actions.js │ │ │ ├── editor-commands.yml │ │ │ ├── editor-tab-group.actions.js │ │ │ ├── editor-tab-group.css │ │ │ ├── editor-tab-group.jsx │ │ │ ├── editor-tab-group.reducer.js │ │ │ ├── editor-tab-group.reducer.test.js │ │ │ ├── initial-story.py │ │ │ ├── known-file-types.js │ │ │ ├── known-file-types.yml │ │ │ └── rodeo-logo │ │ │ │ ├── rodeo-logo.1x.png │ │ │ │ ├── rodeo-logo.2x.png │ │ │ │ └── rodeo-logo.4x.png │ │ ├── environment-variables-dialog-viewer │ │ │ ├── environment-variables-dialog-viewer.actions.js │ │ │ ├── environment-variables-dialog-viewer.css │ │ │ ├── environment-variables-dialog-viewer.js │ │ │ ├── environment-variables-dialog-viewer.reducer.js │ │ │ ├── environment-variables-dialog-viewer.selectors.js │ │ │ └── layout.yml │ │ ├── file-viewer │ │ │ ├── file-viewer.actions.js │ │ │ ├── file-viewer.jsx │ │ │ └── file-viewer.reducer.js │ │ ├── free-tab-group │ │ │ ├── free-tab-group.actions.js │ │ │ ├── free-tab-group.jsx │ │ │ ├── free-tab-group.reducer.js │ │ │ ├── free-tab-group.reducer.test.js │ │ │ └── tab-types.js │ │ ├── free-tabs-only.jsx │ │ ├── free-tabs-only.reducer.js │ │ ├── global-history-viewer │ │ │ ├── global-history-viewer.css │ │ │ ├── global-history-viewer.js │ │ │ └── global-history-viewer.reducer.js │ │ ├── history-viewer │ │ │ ├── history-viewer.actions.js │ │ │ ├── history-viewer.js │ │ │ └── history-viewer.reducer.js │ │ ├── main.initial.js │ │ ├── main.jsx │ │ ├── main.reducer.js │ │ ├── manage-connections-viewer │ │ │ ├── definitions.yml │ │ │ ├── manage-connections-viewer.js │ │ │ ├── manage-connections.actions.js │ │ │ ├── manage-connections.reducer.js │ │ │ └── manage-connections.selectors.js │ │ ├── modal-dialog-viewer │ │ │ ├── dialog-types.js │ │ │ ├── modal-dialog-viewer.jsx │ │ │ ├── modal-dialog.actions.js │ │ │ └── modal-dialog.reducer.js │ │ ├── package-search-viewer │ │ │ ├── package-search-viewer.actions.js │ │ │ ├── package-search-viewer.jsx │ │ │ ├── package-search-viewer.reducer.js │ │ │ └── recommended.yml │ │ ├── plot-viewer │ │ │ ├── plot-viewer.actions.js │ │ │ ├── plot-viewer.jsx │ │ │ └── plot-viewer.reducer.js │ │ ├── preferences-viewer │ │ │ ├── layout.yml │ │ │ ├── preferences-viewer.actions.js │ │ │ ├── preferences-viewer.js │ │ │ ├── preferences-viewer.reducer.js │ │ │ ├── preferences-viewer.reducer.test.js │ │ │ └── preferences-viewer.selectors.js │ │ ├── prompt-viewer │ │ │ ├── default-commands.yml │ │ │ ├── prompt-viewer.actions.js │ │ │ ├── prompt-viewer.js │ │ │ ├── prompt-viewer.reducer.js │ │ │ └── prompt-viewer.test.js │ │ ├── setup-viewer │ │ │ ├── articles.yml │ │ │ ├── setup-viewer.actions.js │ │ │ ├── setup-viewer.jsx │ │ │ └── setup-viewer.reducer.js │ │ ├── startup-text.yml │ │ ├── startup.jsx │ │ ├── startup.reducer.js │ │ ├── studio-layout │ │ │ ├── rodeo-logo.1x.png │ │ │ ├── rodeo-logo.2x.png │ │ │ ├── rodeo-logo.4x.png │ │ │ └── studio-layout.jsx │ │ ├── text.yml │ │ ├── variable-table-viewer.jsx │ │ └── variable-viewer │ │ │ └── variable-viewer.reducer.js │ ├── entry │ │ ├── free-tabs-only.html │ │ ├── free-tabs-only.js │ │ ├── main.html │ │ ├── main.js │ │ ├── startup.html │ │ └── startup.js │ ├── favicon.ico │ ├── lib │ │ ├── ascii-table.min.js │ │ └── ipc.js │ └── services │ │ ├── ace-decorators.js │ │ ├── ace-python-completer.js │ │ ├── ace-python-completer.test.js │ │ ├── ace-settings.js │ │ ├── ace-shortcuts.js │ │ ├── api.js │ │ ├── application-control.js │ │ ├── cid.js │ │ ├── common-react.js │ │ ├── common-react.test.js │ │ ├── common-tabs-actions.js │ │ ├── common-tabs-actions.test.js │ │ ├── common-tabs-reducers.js │ │ ├── common-tabs-reducers.test.js │ │ ├── database-connections.js │ │ ├── dom.js │ │ ├── env.js │ │ ├── errors │ │ ├── index.js │ │ └── validation-error.js │ │ ├── files.js │ │ ├── global-observer.js │ │ ├── guid.js │ │ ├── immutable-util.js │ │ ├── ipc-dispatcher.js │ │ ├── jupyter │ │ ├── client-discovery.js │ │ ├── client.js │ │ ├── conda.js │ │ ├── history.js │ │ ├── python-language.js │ │ └── response.js │ │ ├── layout-mapper.js │ │ ├── log.js │ │ ├── map-reducers.js │ │ ├── map-reducers.test.js │ │ ├── prompt-actions.js │ │ ├── prompt-actions.test.js │ │ ├── pypi.js │ │ ├── react-performance.js │ │ ├── redux-store.js │ │ ├── redux-util.js │ │ ├── registration.js │ │ ├── selection-util.js │ │ ├── store.js │ │ ├── store.test.js │ │ ├── terminal-shortcuts.js │ │ ├── text-util.js │ │ ├── text-util.test.js │ │ ├── track.js │ │ ├── util │ │ ├── prompt-util.js │ │ └── prompt-util.test.js │ │ ├── validation.js │ │ └── xmlrpc.js ├── fonts │ ├── NotoMono-hinted │ │ ├── LICENSE_OFL.txt │ │ └── NotoMono-Regular.ttf │ ├── NotoSans-unhinted │ │ ├── LICENSE_OFL.txt │ │ ├── NotoSans-Bold.ttf │ │ ├── NotoSans-BoldItalic.ttf │ │ ├── NotoSans-Italic.ttf │ │ └── NotoSans-Regular.ttf │ ├── NotoSerif-unhinted │ │ ├── LICENSE_OFL.txt │ │ ├── NotoSerif-Bold.ttf │ │ ├── NotoSerif-BoldItalic.ttf │ │ ├── NotoSerif-Italic.ttf │ │ └── NotoSerif-Regular.ttf │ ├── fonts.css │ ├── lato │ │ ├── DESCRIPTION.en_us.html │ │ ├── FONTLOG.txt │ │ ├── Lato-Black.ttf │ │ ├── Lato-BlackItalic.ttf │ │ ├── Lato-Bold.ttf │ │ ├── Lato-BoldItalic.ttf │ │ ├── Lato-Hairline.ttf │ │ ├── Lato-HairlineItalic.ttf │ │ ├── Lato-Italic.ttf │ │ ├── Lato-Light.ttf │ │ ├── Lato-LightItalic.ttf │ │ ├── Lato-Regular.ttf │ │ ├── METADATA.pb │ │ └── OFL.txt │ └── roboto │ │ ├── COPYRIGHT.txt │ │ ├── DESCRIPTION.en_us.html │ │ ├── LICENSE.txt │ │ ├── METADATA.pb │ │ ├── Roboto-Black.ttf │ │ ├── Roboto-BlackItalic.ttf │ │ ├── Roboto-Bold.ttf │ │ ├── Roboto-BoldItalic.ttf │ │ ├── Roboto-Italic.ttf │ │ ├── Roboto-Light.ttf │ │ ├── Roboto-LightItalic.ttf │ │ ├── Roboto-Medium.ttf │ │ ├── Roboto-MediumItalic.ttf │ │ ├── Roboto-Regular.ttf │ │ ├── Roboto-Thin.ttf │ │ └── Roboto-ThinItalic.ttf ├── node │ ├── application-menu.yml │ ├── index.js │ ├── index.test.js │ ├── kernels │ │ └── python │ │ │ ├── check.py │ │ │ ├── client-response.js │ │ │ ├── client-response.test.js │ │ │ ├── client.js │ │ │ ├── client.test.js │ │ │ ├── language.js │ │ │ ├── language.test.js │ │ │ ├── listen.py │ │ │ └── patch.py │ └── services │ │ ├── args.js │ │ ├── assert.js │ │ ├── assert.test.js │ │ ├── browser-windows.js │ │ ├── chromium-errors.yml │ │ ├── clone.js │ │ ├── db │ │ ├── index.js │ │ ├── index.test.js │ │ ├── option-sanitization.js │ │ └── postgresql │ │ │ ├── get-columns-by-schema-and-table.sql │ │ │ ├── get-schemas.sql │ │ │ ├── get-tables-by-schema.sql │ │ │ └── index.js │ │ ├── electron-winston-transport.js │ │ ├── env.js │ │ ├── errors │ │ └── process-error.js │ │ ├── files.js │ │ ├── files.test.js │ │ ├── installer │ │ ├── commands.js │ │ ├── commands.test.js │ │ ├── context-menu.js │ │ ├── context-menu.test.js │ │ ├── index.js │ │ ├── shortcuts.js │ │ └── shortcuts.test.js │ │ ├── ipc-promises.js │ │ ├── log.js │ │ ├── md.hbs │ │ ├── md.js │ │ ├── md.test.js │ │ ├── menu-definitions.js │ │ ├── plot-server.js │ │ ├── processes.js │ │ ├── processes.test.js │ │ ├── promises.js │ │ ├── promises.test.js │ │ ├── rest.js │ │ ├── survey.js │ │ ├── updater.js │ │ └── win32 │ │ ├── registry.js │ │ ├── system.js │ │ └── system.test.js ├── readme.md ├── shared │ ├── dateUtil.js │ └── env.js └── themes │ ├── cobalt.less │ ├── dark.less │ ├── default.less │ ├── imported │ ├── cobalt.less │ ├── dark.less │ ├── default.less │ ├── presentation.less │ └── unk.less │ ├── lib │ ├── bootstrap-variables.less │ ├── bootswatch.less │ ├── jquery.dataTables.less │ └── misc.less │ ├── presentation.less │ └── structure │ ├── fixed-data-table.less │ ├── forms.less │ ├── global.less │ └── jqconsole.less ├── test ├── browser │ ├── index.js │ ├── mocks │ │ ├── ace.js │ │ ├── ipc.js │ │ └── storage.js │ └── services │ │ └── text-util.js ├── fixtures │ └── windows-registry-commands │ │ ├── install-context-menu.yml │ │ └── uninstall-context-menu.yml ├── mocks │ ├── classes │ │ └── child-process.js │ └── jupyter_examples │ │ ├── create_svg_1.py │ │ ├── create_svg_2.py │ │ ├── example_1.py │ │ ├── example_2.py │ │ ├── example_3.py │ │ ├── example_4.py │ │ ├── example_5.py │ │ ├── example_6.py │ │ ├── example_7.py │ │ └── example_8.py └── node │ └── index.js ├── watch.sh ├── webpack.config.js ├── webpack.dev.config.js └── webpack.main.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["lodash"], 3 | "presets": ["es2015", "react"] 4 | } 5 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | **/lib/*.js 2 | node_modules/* 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .DS_Store 3 | cache 4 | *.pyc 5 | *.log 6 | BETA.md 7 | .vagrant 8 | *.swp 9 | npm-debug.log* 10 | .tmp 11 | 12 | app 13 | dist 14 | node_modules 15 | coverage 16 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 6.4 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "6.4" 4 | cache: 5 | directories: 6 | - node_modules 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Rodeo, An IDE for data science 2 | Copyright (C) 2015 Yhat, Inc. 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero General Public License as 6 | published by the Free Software Foundation, either version 3 of the 7 | License, or (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with this program. If not, see . 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rodeo 2 | 3 | ## [Rodeo Desktop](https://www.yhat.com/products/rodeo) 4 | ![](http://blog.yhathq.com/static/img/rodeo-overview.png) 5 | 6 | ![](https://ga-beacon.appspot.com/UA-46996803-1/rodeo/README.md) 7 | 8 | ## Install 9 | Check [bareback.s.yhat.com](http://bareback.s.yhat.com) for the latest release. Download it! 10 | 11 | 12 | [Contributing](https://github.com/yhat/rodeo/blob/master/contributing.md) 13 | -------------------------------------------------------------------------------- /__mocks__/ace.js: -------------------------------------------------------------------------------- 1 | const dict = { 2 | 'ace/autocomplete': { 3 | AutoComplete: {startCommand: {exec: function () {}}} 4 | } 5 | }; 6 | 7 | function require(key) { 8 | return dict[key]; 9 | } 10 | 11 | function edit() { 12 | return { 13 | getSession: function () { 14 | return { 15 | setValue: function () { 16 | 17 | } 18 | }; 19 | } 20 | }; 21 | } 22 | 23 | export default { 24 | require, 25 | edit 26 | }; 27 | -------------------------------------------------------------------------------- /__mocks__/browser-mocks.js: -------------------------------------------------------------------------------- 1 | 2 | function getSelection() { 3 | return { 4 | containsNode: function () { return false; } 5 | }; 6 | } 7 | 8 | Object.defineProperty(window, 'getSelection', { 9 | value: getSelection 10 | }); 11 | -------------------------------------------------------------------------------- /__mocks__/generic-stub.js: -------------------------------------------------------------------------------- 1 | module.exports = {}; 2 | -------------------------------------------------------------------------------- /__mocks__/ipc.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | export default { 4 | send: _.noop 5 | }; 6 | -------------------------------------------------------------------------------- /__mocks__/storage.js: -------------------------------------------------------------------------------- 1 | class MockStorage { 2 | constructor() { 3 | this.store = {}; 4 | } 5 | 6 | getItem(key) { 7 | return this.store[key] || null; 8 | } 9 | 10 | setItem(key, value) { 11 | this.store[key] = value.toString(); 12 | } 13 | 14 | clear() { 15 | this.store = {}; 16 | } 17 | 18 | setStore(value) { 19 | this.store = value; 20 | } 21 | 22 | getStore() { 23 | return this.store; 24 | } 25 | } 26 | 27 | export default MockStorage; 28 | -------------------------------------------------------------------------------- /build/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/build/background.png -------------------------------------------------------------------------------- /build/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/build/icon.icns -------------------------------------------------------------------------------- /build/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/build/icon.ico -------------------------------------------------------------------------------- /build/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/build/icon.png -------------------------------------------------------------------------------- /build/install-spinner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/build/install-spinner.gif -------------------------------------------------------------------------------- /karma.node.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (karma) { 4 | karma.set({ 5 | autoWatch: false, 6 | browsers: ['CustomElectron'], 7 | browserDisconnectTimeout: 1000 * 60 * 2, 8 | browserNoActivityTimeout: 1000 * 60 * 5, 9 | colors: true, 10 | singleRun: true, 11 | // logLevel: karma.LOG_DEBUG, 12 | reporters: [ 13 | 'mocha' 14 | ], 15 | specReporter: { 16 | suppressErrorSummary: false, // do not print error summary 17 | suppressFailed: false, // do not print information about failed tests 18 | suppressPassed: false, // do not print information about passed tests 19 | suppressSkipped: false, // do not print information about skipped tests 20 | showSpecTiming: true // print the time elapsed for each spec 21 | }, 22 | mochaReporter: { 23 | showDiff: true 24 | }, 25 | customLaunchers: { 26 | CustomElectron: { 27 | base: 'Electron', 28 | flags: ['--enable-logging'] 29 | } 30 | }, 31 | files: [ 32 | 'test/node/**/*.js', 33 | 'src/node/**/*.js' 34 | ], 35 | frameworks: ['mocha', 'chai'], 36 | preprocessors: { 37 | '**/*.js': ['electron'] 38 | }, 39 | plugins: [ 40 | 'karma-mocha-reporter', 41 | 'karma-electron', 42 | 'karma-mocha', 43 | 'karma-chai' 44 | ] 45 | }); 46 | }; 47 | -------------------------------------------------------------------------------- /scripts/osx/build.sh: -------------------------------------------------------------------------------- 1 | STARTING_DIR=$(pwd) 2 | TARGET_DIR=~/Projects/yhat/rodeo 3 | CACHE_MIN=999999999 4 | 5 | #guarantee nvm 6 | echo '#guarantee nvm' 7 | if ! brew list --versions | grep -q nvm; then 8 | brew install nvm 9 | fi 10 | source $(brew --prefix nvm)/nvm.sh 11 | 12 | #install script dependencies 13 | echo '#install script dependencies' 14 | npm install -q --cache-min $CACHE_MIN -g gulp-cli electron-prebuilt 15 | 16 | #build application (production and dev dependnencies) 17 | cd $TARGET_DIR 18 | echo '#build application (production and dev dependnencies)' 19 | rm -rf app dist 20 | npm install -q --cache-min $CACHE_MIN 21 | npm run build 22 | cd $STARTING_DIR 23 | 24 | #install application including production dependencies only (no dev) 25 | echo '#install application including production dependencies only (no dev)' 26 | cd "$TARGET_DIR/app" 27 | npm install -q --production --no-bin-links --cache-min $CACHE_MIN 28 | npm -q dedupe 29 | cd $STARTING_DIR 30 | -------------------------------------------------------------------------------- /scripts/osx/create-test-postgresql-tables.sh: -------------------------------------------------------------------------------- 1 | sleep 5; psql -h localhost --username postgres -c "CREATE TABLE distributors ( \ 2 | did integer, \ 3 | name varchar(40), \ 4 | UNIQUE(name) \ 5 | );" 6 | -------------------------------------------------------------------------------- /scripts/osx/dist-linux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | STARTING_DIR=$(pwd) 3 | TARGET_DIR=~/Projects/yhat/rodeo 4 | 5 | cd $TARGET_DIR 6 | 7 | rm -rf dist 8 | 9 | #dependencies 10 | ./scripts/osx/install-deps.sh 11 | ./scripts/osx/install-dist-linux-deps.sh 12 | 13 | #remember nvm 14 | echo '#guarantee nvm' 15 | source $(brew --prefix nvm)/nvm.sh 16 | nvm use 17 | 18 | #build distributable 19 | node_modules/.bin/build --linux --x64 20 | 21 | #list created files 22 | echo '#list created files' 23 | git ls-files dist -o -x node_modules --directory 24 | 25 | cd $STARTING_DIR 26 | -------------------------------------------------------------------------------- /scripts/osx/dist-osx.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | STARTING_DIR=$(pwd) 3 | TARGET_DIR=~/Projects/yhat/rodeo 4 | 5 | cd $TARGET_DIR 6 | 7 | rm -rf dist 8 | 9 | #dependencies 10 | ./scripts/osx/install-deps.sh 11 | 12 | #remember nvm 13 | echo '#remember nvm' 14 | source $(brew --prefix nvm)/nvm.sh 15 | nvm use 16 | 17 | #build distributable 18 | node_modules/.bin/build --osx --x64 19 | 20 | #list created files 21 | echo '#list created files:' 22 | git ls-files dist -o -x node_modules --directory 23 | 24 | cd $STARTING_DIR 25 | -------------------------------------------------------------------------------- /scripts/osx/dist-win.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | STARTING_DIR=$(pwd) 3 | TARGET_DIR=~/Projects/yhat/rodeo 4 | 5 | cd $TARGET_DIR 6 | 7 | rm -rf dist 8 | 9 | #dependencies 10 | ./scripts/osx/install-deps.sh 11 | ./scripts/osx/install-dist-win-deps.sh 12 | 13 | #remember nvm 14 | echo '#guarantee nvm' 15 | source $(brew --prefix nvm)/nvm.sh 16 | nvm use 17 | 18 | #build distributable 19 | DEBUG=electron-windows-installer:* node_modules/.bin/build --win --x64 20 | 21 | #list created files 22 | echo '#list created files' 23 | git ls-files dist -o -x node_modules --directory 24 | 25 | cd $STARTING_DIR 26 | -------------------------------------------------------------------------------- /scripts/osx/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | postgres1: 4 | image: postgres 5 | ports: 6 | - "5432:5432" 7 | environment: 8 | POSTGRES_DB: postgres 9 | POSTGRES_USER: postgres 10 | POSTGRES_PASSWORD: mysecretpassword 11 | -------------------------------------------------------------------------------- /scripts/osx/install-deps.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # see https://github.com/electron-userland/electron-builder/wiki/Multi-Platform-Build 3 | 4 | STARTING_DIR=$(pwd) 5 | TARGET_DIR=~/Projects/yhat/rodeo 6 | CACHE_MIN=999999999 7 | 8 | #check brew 9 | echo '#check brew' 10 | brew doctor 11 | brew update 12 | brew --version 13 | 14 | # install testing dependencies (osx specific) 15 | echo '#install testing dependencies (osx specific)' 16 | brew tap homebrew/dupes 17 | 18 | if ! brew list --versions | grep -q libjpeg; then 19 | brew install libjpeg 20 | fi 21 | 22 | if ! brew list --versions | grep -q zlib; then 23 | brew install zlib 24 | brew link zlib --force 25 | fi 26 | -------------------------------------------------------------------------------- /scripts/osx/install-dist-linux-deps.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #see https://github.com/electron-userland/electron-builder/wiki/Multi-Platform-Build 3 | 4 | #so we can build linux on mac 5 | echo '#so we can build linux on mac' 6 | 7 | if ! brew list --versions | grep -q gnu-tar; then 8 | brew install gnu-tar 9 | fi 10 | 11 | if ! brew list --versions | grep -q libicns; then 12 | brew install libicns 13 | fi 14 | 15 | if ! brew list --versions | grep -q graphicsmagick; then 16 | brew install graphicsmagick 17 | fi 18 | 19 | if ! brew list --versions | grep -q rpm; then 20 | brew install rpm 21 | fi 22 | -------------------------------------------------------------------------------- /scripts/osx/install-dist-win-deps.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #see https://github.com/electron-userland/electron-builder/wiki/Multi-Platform-Build 3 | 4 | #so we can build windows on mac 5 | echo '#so we can build windows on mac' 6 | 7 | if ! brew list --versions | grep -q xquartz; then 8 | brew install Caskroom/cask/xquartz 9 | fi 10 | 11 | if ! brew list --versions | grep -q wine; then 12 | brew install wine 13 | fi 14 | 15 | if ! brew list --versions | grep -q mono; then 16 | brew install mono 17 | fi 18 | -------------------------------------------------------------------------------- /scripts/osx/install-test-deps.sh: -------------------------------------------------------------------------------- 1 | . ~/.nvm/nvm.sh 2 | export PYENV_ROOT="$HOME/.pyenv" 3 | export PATH="$PYENV_ROOT/bin:$PATH" 4 | export PATH="$PYENV_ROOT/shims:$PATH" 5 | -------------------------------------------------------------------------------- /scripts/osx/sign.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # codesign for OSX 4 | if [ -d dist/Rodeo-darwin-x64/Rodeo.app ]; then 5 | echo 'These are the valid codesigning ids:' 6 | security find-identity -vvvv -p codesigning 7 | 8 | echo 'This is the deep inspection of the current signature of the app:' 9 | codesign --deep --display -vvvv Rodeo.app 10 | 11 | echo 'These are the available Developer IDs:' 12 | certtool y | grep Developer\ ID 13 | 14 | # --sign the action to take 15 | # --deep sign all the things inside 16 | # --force replace any existing signatures 17 | codesign -vvvv --deep --force --sign "5D0C1D5ED6B38D0F63D63D0159422EA1544E8AE1" dist/Rodeo-darwin-x64/Rodeo-1.3.2.dmg 18 | # --verify the action to take 19 | codesign --verify -vvvv dist/Rodeo-darwin-x64/Rodeo.app 20 | spctl -a -vvvv --ignore-cache --no-cache dist/Rodeo-darwin-x64/Rodeo.app/ 21 | fi 22 | -------------------------------------------------------------------------------- /scripts/osx/test-postgresql.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | STARTING_DIR=$(pwd) 4 | TARGET_DIR=~/Projects/yhat/rodeo/scripts/osx 5 | 6 | cd $TARGET_DIR 7 | 8 | docker-compose up 9 | 10 | cd $STARTING_DIR 11 | -------------------------------------------------------------------------------- /scripts/osx/update-info-plist.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | plist = open("dist/Rodeo-darwin-x64/Rodeo.app/Contents/Info.plist").read() 3 | find = """ 4 | """ 5 | idx = plist.index(find) 6 | doctypes = """ CFBundleDocumentTypes 7 | 8 | 9 | CFBundleTypeExtensions 10 | 11 | py 12 | rpy 13 | cpy 14 | python 15 | 16 | CFBundleTypeIconFile 17 | file.icns 18 | CFBundleTypeName 19 | Python source 20 | CFBundleTypeRole 21 | Editor 22 | LSHandlerRank 23 | Alternate 24 | 25 | 26 | """ 27 | 28 | with open("dist/Rodeo-darwin-x64/Rodeo.app/Contents/Info.plist", "wb") as f: 29 | f.write(plist[:idx] + doctypes + plist[idx:]) 30 | -------------------------------------------------------------------------------- /scripts/osx/verify-sign.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # codesign for OSX 4 | if [ -d dist/Rodeo-darwin-x64/Rodeo.app ]; then 5 | echo 'These are the valid codesigning ids:' 6 | security find-identity -vvvv -p codesigning 7 | 8 | echo 'This is the deep inspection of the current signature of the app:' 9 | codesign --deep --display -vvvv Rodeo.app 10 | 11 | echo 'These are the available Developer IDs:' 12 | certtool y | grep Developer\ ID 13 | 14 | # --sign the action to take 15 | # --deep sign all the things inside 16 | # --force replace any existing signatures 17 | # --verify the action to take 18 | codesign --verify -vvvv dist/Rodeo-darwin-x64/Rodeo.app 19 | spctl -a -vvvv --ignore-cache --no-cache dist/Rodeo-darwin-x64/Rodeo.app 20 | fi 21 | -------------------------------------------------------------------------------- /scripts/win/setup_conda.bat: -------------------------------------------------------------------------------- 1 | // install script to set windows right 2 | 3 | pip install jupyter_client ipykernel matplotlib numpy pandas 4 | jupyter install --user 5 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | import express from 'express'; 2 | import webpack from 'webpack'; 3 | import webpackDevMiddleware from 'webpack-dev-middleware'; 4 | import webpackHotMiddleware from 'webpack-hot-middleware'; 5 | import config from './webpack.dev.config.js'; 6 | 7 | const app = express(), 8 | compiler = webpack(config), 9 | PORT = 3001; 10 | 11 | app.use(webpackDevMiddleware(compiler, { 12 | publicPath: config.output.publicPath, 13 | hot: true, 14 | historyApiFallback: true, 15 | stats: { 16 | colors: true 17 | } 18 | })); 19 | 20 | app.use(webpackHotMiddleware(compiler, { 21 | log: console.log, 22 | path: '/__webpack_hmr', 23 | heartbeat: 10 * 1000 24 | })); 25 | 26 | app.listen(PORT, 'localhost', err => { 27 | if (err) { 28 | console.error(err); 29 | return; 30 | } 31 | 32 | console.log(`Listening at http://localhost:${PORT}`); 33 | }); 34 | -------------------------------------------------------------------------------- /src/ace/mode-plain_text.js: -------------------------------------------------------------------------------- 1 | ace.define("ace/mode/plain_text",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/text_highlight_rules","ace/mode/behaviour"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./text_highlight_rules").TextHighlightRules,o=e("./behaviour").Behaviour,u=function(){this.HighlightRules=s,this.$behaviour=new o};r.inherits(u,i),function(){this.type="text",this.getNextLineIndent=function(e,t,n){return""},this.$id="ace/mode/plain_text"}.call(u.prototype),t.Mode=u}) 2 | -------------------------------------------------------------------------------- /src/ace/readme.md: -------------------------------------------------------------------------------- 1 | ACE 2 | === 3 | 4 | There is so much code here that compiling it with the rest of the jsx is a waste, so we put it into its own output file. -------------------------------------------------------------------------------- /src/ace/snippets/mysql.js: -------------------------------------------------------------------------------- 1 | ace.define("ace/snippets/mysql",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="mysql"}) 2 | -------------------------------------------------------------------------------- /src/ace/snippets/pgsql.js: -------------------------------------------------------------------------------- 1 | ace.define("ace/snippets/pgsql",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="pgsql"}) 2 | -------------------------------------------------------------------------------- /src/ace/snippets/rdoc.js: -------------------------------------------------------------------------------- 1 | ace.define("ace/snippets/rdoc",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="rdoc"}) -------------------------------------------------------------------------------- /src/ace/snippets/rhtml.js: -------------------------------------------------------------------------------- 1 | ace.define("ace/snippets/rhtml",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="rhtml"}) -------------------------------------------------------------------------------- /src/ace/snippets/sql.js: -------------------------------------------------------------------------------- 1 | ace.define("ace/snippets/sql",["require","exports","module"],function(e,t,n){"use strict";t.snippetText="snippet tbl\n create table ${1:table} (\n ${2:columns}\n );\nsnippet col\n ${1:name} ${2:type} ${3:default ''} ${4:not null}\nsnippet ccol\n ${1:name} varchar2(${2:size}) ${3:default ''} ${4:not null}\nsnippet ncol\n ${1:name} number ${3:default 0} ${4:not null}\nsnippet dcol\n ${1:name} date ${3:default sysdate} ${4:not null}\nsnippet ind\n create index ${3:$1_$2} on ${1:table}(${2:column});\nsnippet uind\n create unique index ${1:name} on ${2:table}(${3:column});\nsnippet tblcom\n comment on table ${1:table} is '${2:comment}';\nsnippet colcom\n comment on column ${1:table}.${2:column} is '${3:comment}';\nsnippet addcol\n alter table ${1:table} add (${2:column} ${3:type});\nsnippet seq\n create sequence ${1:name} start with ${2:1} increment by ${3:1} minvalue ${4:1};\nsnippet s*\n select * from ${1:table}\n",t.scope="sql"}) 2 | -------------------------------------------------------------------------------- /src/browser/actions/dialogs.js: -------------------------------------------------------------------------------- 1 | import applicationActions from '../actions/application'; 2 | import {local} from '../services/store'; 3 | import registration from '../services/registration'; 4 | import modalDialogActions from '../containers/modal-dialog-viewer/modal-dialog.actions'; 5 | 6 | function showAboutRodeo() { 7 | return modalDialogActions.add('aboutRodeo'); 8 | } 9 | 10 | function showAboutStickers() { 11 | return modalDialogActions.add('aboutStickers'); 12 | } 13 | 14 | function showPreferences() { 15 | return modalDialogActions.add('preferences'); 16 | } 17 | 18 | function showAcknowledgements() { 19 | return modalDialogActions.add('acknowledgements'); 20 | } 21 | 22 | function showRegisterRodeo() { 23 | return function (dispatch) { 24 | if (registration.shouldShowDialog()) { 25 | registration.rememberShowedDialog(); 26 | dispatch(modalDialogActions.add('registerRodeo')); 27 | } 28 | }; 29 | } 30 | 31 | function showAskQuit() { 32 | if (local.get('askQuit') === false) { 33 | return applicationActions.quit(); 34 | } 35 | 36 | return modalDialogActions.add('askQuit'); 37 | } 38 | 39 | export default { 40 | showAboutRodeo, 41 | showAboutStickers, 42 | showAcknowledgements, 43 | showAskQuit, 44 | showPreferences, 45 | showRegisterRodeo 46 | }; 47 | -------------------------------------------------------------------------------- /src/browser/actions/preferences.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import kernel from './kernel'; 3 | import {local} from '../services/store'; 4 | 5 | /** 6 | * @param {[object]} changes 7 | * @returns {function} 8 | */ 9 | function savePreferenceChanges(changes) { 10 | // save the actual changes _immediately_ to ban race conditions 11 | _.each(changes, change => local.set(change.key, change.value)); 12 | 13 | return function (dispatch) { 14 | // notify everyone of the changes that have _already happened_ 15 | _.each(changes, change => dispatch({type: 'PREFERENCE_CHANGE_SAVED', change, meta: {track: true}})); 16 | 17 | // restart kernel only after all changes were announced, and only once 18 | if (_.some(changes, change => _.includes(['pythonCmd', 'workingDirectory'], change.key))) { 19 | dispatch(kernel.restart()); 20 | } 21 | }; 22 | } 23 | 24 | export default { 25 | savePreferenceChanges 26 | }; 27 | -------------------------------------------------------------------------------- /src/browser/components/ace-pane/ace-pane.css: -------------------------------------------------------------------------------- 1 | .ace-pane { 2 | height: 100%; 3 | } 4 | 5 | div.ace_tooltip { 6 | background: initial; 7 | border: 0; 8 | padding: 0; 9 | margin: 0; 10 | box-shadow: none; 11 | max-height: 30%; 12 | overflow-x: auto; 13 | } 14 | 15 | div.ace_editor.ace_autocomplete { 16 | width: 320px; 17 | } 18 | 19 | .rodeo-ace-pane-docstring { 20 | background: #f3f9ff; 21 | border: 1px solid #cde7fe; 22 | padding: 3px; 23 | margin-left: 3px; 24 | box-shadow: 2px 5px 10px #aaafb3; 25 | transition: opacity 0.2s; 26 | white-space: pre-wrap; 27 | font-size: smaller; 28 | } 29 | -------------------------------------------------------------------------------- /src/browser/components/ace-pane/ace-pane.test.js: -------------------------------------------------------------------------------- 1 | /* globals describe, it, expect, jest */ 2 | 3 | jest.mock('ace'); 4 | jest.mock('../../services/ace-shortcuts'); 5 | jest.mock('../../services/ace-settings'); 6 | 7 | import React from 'react'; 8 | import ReactDOM from 'react-dom'; 9 | import TestUtils from 'react-addons-test-utils'; 10 | import AcePane from './ace-pane'; 11 | 12 | describe(__filename, () => { 13 | it('renders', () => { 14 | const reactDocument = TestUtils.renderIntoDocument(), 15 | el = ReactDOM.findDOMNode(reactDocument); 16 | 17 | expect(el.className).toEqual('ace-pane font-monospaced'); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /src/browser/components/action-button.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import commonReact from '../services/common-react'; 3 | 4 | export default React.createClass({ 5 | displayName: 'ActionButton', 6 | propTypes: { 7 | action: React.PropTypes.oneOfType([React.PropTypes.func, React.PropTypes.object]) 8 | }, 9 | contextTypes: { 10 | store: React.PropTypes.object 11 | }, 12 | shouldComponentUpdate() { 13 | // assume correct the first time 14 | return false; 15 | }, 16 | handleClick: function () { 17 | this.context.store.dispatch(this.props.action); 18 | }, 19 | render: function () { 20 | const props = this.props, 21 | className = commonReact.getClassNameList(this); 22 | 23 | return ; 24 | } 25 | }); 26 | -------------------------------------------------------------------------------- /src/browser/components/actionest/actionest-button.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import React from 'react'; 3 | import commonReact from '../../services/common-react'; 4 | import './actionest.css'; 5 | 6 | export default React.createClass({ 7 | displayName: 'ActionestButton', 8 | propTypes: { 9 | icon: React.PropTypes.string.isRequired, 10 | onClick: React.PropTypes.func.isRequired 11 | }, 12 | getDefaultProps: function () { 13 | return {onClick: _.noop}; 14 | }, 15 | shouldComponentUpdate: function (nextProps) { 16 | return commonReact.shouldComponentUpdate(this, nextProps); 17 | }, 18 | render: function () { 19 | const props = this.props, 20 | className = commonReact.getClassNameList(this); 21 | 22 | className.push('actionest'); 23 | className.push('fa', 'fa-' + props.icon); 24 | 25 | return
; 26 | } 27 | }); 28 | -------------------------------------------------------------------------------- /src/browser/components/block-history/block-history.css: -------------------------------------------------------------------------------- 1 | .block-history--empty { 2 | height: 100%; 3 | } 4 | 5 | -------------------------------------------------------------------------------- /src/browser/components/block-history/expand-block-button.css: -------------------------------------------------------------------------------- 1 | .expand-block-button { 2 | height: 15px; 3 | text-align: center; 4 | position: absolute; 5 | bottom: 0; 6 | left: 0; 7 | right: 0; 8 | cursor: pointer; 9 | border-bottom-left-radius: 5px; 10 | border-bottom-right-radius: 5px; 11 | transition: all 0.2s; 12 | box-shadow: none; 13 | } 14 | 15 | .expand-block-button:hover { 16 | box-shadow: inset 0 -6px 5px -2px #ccc; 17 | } 18 | -------------------------------------------------------------------------------- /src/browser/components/block-history/expand-block-button.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import commonReact from '../../services/common-react'; 3 | import './expand-block-button.css'; 4 | 5 | export default React.createClass({ 6 | displayName: 'ExpandBlockButton', 7 | propTypes: { 8 | direction: React.PropTypes.string, 9 | onClick: React.PropTypes.func 10 | }, 11 | shouldComponentUpdate: function (nextProps) { 12 | return commonReact.shouldComponentUpdate(this, nextProps); 13 | }, 14 | render: function () { 15 | const props = this.props, 16 | className = commonReact.getClassNameList(this); 17 | let content; 18 | 19 | if (props.direction === 'up') { 20 | content = ; 21 | } else { 22 | content = ; 23 | } 24 | 25 | return
{content}
; 26 | } 27 | }); 28 | /** 29 | * Created by danestuckel on 10/11/16. 30 | */ 31 | -------------------------------------------------------------------------------- /src/browser/components/block-history/history-blocks/error-block.css: -------------------------------------------------------------------------------- 1 | .error-block { 2 | background-color: #feebeb; 3 | margin: 10px 4px 10px 2px; 4 | border-radius: 5px; 5 | padding: 6px; 6 | padding-top: 2px; 7 | border: 1px solid #d69fa0; 8 | box-shadow: 1px 2px 3px #feebeb; 9 | color: #b32327; 10 | white-space: pre; 11 | overflow-x: auto; 12 | position: relative; 13 | transition: all 0.2s; 14 | } 15 | 16 | .error-block:focus { 17 | box-shadow: 0 2px 15px #ffb2b2, 1px 2px 3px #999; 18 | outline: none; 19 | } 20 | 21 | .error-block > header { 22 | font-size: 10px; 23 | font-weight: bold; 24 | color: #d69fa0; 25 | text-transform: lowercase; 26 | display: flex; 27 | flex-direction: row; 28 | align-content: space-between; 29 | align-items: center; 30 | justify-content: space-between; 31 | border-bottom: 1px solid #d69fa0; 32 | } 33 | 34 | .error-block--compressed { 35 | overflow: hidden; 36 | } 37 | 38 | .error-block__contents-outer { 39 | overflow: hidden; 40 | margin-left:10px; 41 | margin-top: 7px; 42 | } 43 | 44 | .error-block__contents { 45 | overflow-x: auto; 46 | } 47 | 48 | .error-block__suggestions { 49 | text-align: right; 50 | } 51 | -------------------------------------------------------------------------------- /src/browser/components/block-history/history-blocks/execution-result-block.css: -------------------------------------------------------------------------------- 1 | .execution-result-block { 2 | margin: 10px 4px 10px 2px; 3 | border-radius: 5px; 4 | padding: 6px; 5 | padding-top: 2px; 6 | border: 1px solid #ddd; 7 | box-shadow: 1px 2px 3px #999; 8 | color: #333; 9 | position: relative; 10 | transition: all 0.2s; 11 | } 12 | 13 | .execution-result-block:focus { 14 | box-shadow: 0 2px 10px #cce6ff, 1px 2px 3px #999; 15 | outline: none; 16 | } 17 | 18 | .execution-result-block--compressed { 19 | max-height: 45px; 20 | overflow: hidden; 21 | } 22 | 23 | .execution-result-block > header { 24 | font-size: 10px; 25 | font-weight: bold; 26 | color: #aaa; 27 | text-transform: lowercase; 28 | display: flex; 29 | flex-direction: row; 30 | align-content: space-between; 31 | align-items: center; 32 | justify-content: space-between; 33 | } 34 | 35 | .execution-result-block .dataframe { 36 | border: 1px solid #ccc; 37 | margin: 10px; 38 | } 39 | 40 | .execution-result-block .dataframe td, 41 | .execution-result-block .dataframe th { 42 | padding: 0 5px; 43 | } 44 | -------------------------------------------------------------------------------- /src/browser/components/block-history/history-blocks/image-block.css: -------------------------------------------------------------------------------- 1 | .image-block { 2 | margin: 10px 4px 10px 2px; 3 | border-radius: 5px; 4 | padding: 6px; 5 | padding-top: 2px; 6 | border: 1px solid #ddd; 7 | box-shadow: 1px 2px 3px #999; 8 | color: #333; 9 | position: relative; 10 | transition: all 0.2s; 11 | } 12 | 13 | .image-block:focus { 14 | box-shadow: 0 2px 10px #cce6ff, 1px 2px 3px #999; 15 | outline: none; 16 | } 17 | 18 | .image-block--expanded { 19 | overflow: auto; 20 | } 21 | 22 | .image-block--compressed { 23 | overflow: hidden; 24 | } 25 | 26 | .image-block__contents-outer { 27 | overflow: hidden; 28 | margin-left: 10px; 29 | } 30 | 31 | .image-block > header { 32 | font-size: 10px; 33 | font-weight: bold; 34 | color: #aaa; 35 | text-transform: lowercase; 36 | display: flex; 37 | flex-direction: row; 38 | align-content: space-between; 39 | align-items: center; 40 | justify-content: space-between; 41 | border-bottom: 1px solid #ccc; 42 | } 43 | 44 | .image-block img { 45 | width: 100%; 46 | } 47 | -------------------------------------------------------------------------------- /src/browser/components/block-history/history-blocks/input-stream-block.css: -------------------------------------------------------------------------------- 1 | .input-stream-block { 2 | margin: 10px 4px 10px 2px; 3 | border-radius: 5px; 4 | padding: 6px; 5 | padding-top: 2px; 6 | border: 1px solid #ddd; 7 | box-shadow: 1px 2px 3px #999; 8 | color: #333; 9 | position: relative; 10 | transition: all 0.2s; 11 | } 12 | 13 | .input-stream-block:focus { 14 | box-shadow: 0 2px 10px #cce6ff, 1px 2px 3px #999; 15 | outline: none; 16 | } 17 | 18 | .input-stream-block--expanded { 19 | overflow: auto; 20 | } 21 | 22 | .input-stream-block--compressed { 23 | overflow: hidden; 24 | } 25 | 26 | .input-stream-block__contents-outer { 27 | overflow: hidden; 28 | margin-left: 10px; 29 | } 30 | 31 | .input-stream-block__contents { 32 | white-space: pre-wrap; 33 | } 34 | 35 | .input-stream-block > header { 36 | font-size: 10px; 37 | font-weight: bold; 38 | color: #aaa; 39 | text-transform: lowercase; 40 | display: flex; 41 | flex-direction: row; 42 | align-content: space-between; 43 | align-items: center; 44 | justify-content: space-between; 45 | border-bottom: 1px solid #ccc; 46 | } 47 | 48 | .input-stream-block__menu .fa { 49 | margin-left: 5px; 50 | } 51 | -------------------------------------------------------------------------------- /src/browser/components/block-history/history-blocks/jupyter-response-block.css: -------------------------------------------------------------------------------- 1 | .jupyter-response-block { 2 | margin: 15px; 3 | border-radius: 5px; 4 | padding: 0 5px 5px; 5 | border: 1px solid #ddd; 6 | box-shadow: 0 0 15px #e4f1fd, inset -1px -2px 3px #ccc; 7 | position: relative; 8 | transition: all 0.2s; 9 | } 10 | 11 | .jupyter-response-block__menu { 12 | text-align: right; 13 | } 14 | 15 | .jupyter-response-block-items > *:first-child { 16 | margin-top: 0; 17 | padding-top: 0; 18 | } 19 | 20 | .jupyter-response-block-items > *:last-child { 21 | margin-bottom: 5px; 22 | } 23 | -------------------------------------------------------------------------------- /src/browser/components/block-history/history-blocks/postgresql-response-block.css: -------------------------------------------------------------------------------- 1 | .postgresql-response-block { 2 | margin: 15px; 3 | border-radius: 5px; 4 | padding: 0 5px 5px; 5 | border: 1px solid #ddd; 6 | box-shadow: 0 0 15px #e4f1fd, inset -1px -2px 3px #ccc; 7 | position: relative; 8 | transition: all 0.2s; 9 | } 10 | 11 | .postgresql-response-block__menu { 12 | text-align: right; 13 | } 14 | 15 | .postgresql-response-block__items > *:first-child { 16 | margin-top: 0; 17 | padding-top: 0; 18 | } 19 | 20 | .postgresql-response-block__items > *:last-child { 21 | margin-bottom: 5px; 22 | } 23 | -------------------------------------------------------------------------------- /src/browser/components/block-history/history-blocks/python-error-block.css: -------------------------------------------------------------------------------- 1 | .python-error-block { 2 | background-color: #feebeb; 3 | margin: 10px 4px 10px 2px; 4 | border-radius: 5px; 5 | padding: 6px; 6 | padding-top: 2px; 7 | border: 1px solid #d69fa0; 8 | box-shadow: 1px 2px 3px #feebeb; 9 | color: #b32327; 10 | white-space: pre; 11 | overflow-x: auto; 12 | position: relative; 13 | transition: all 0.2s; 14 | } 15 | 16 | .python-error-block:focus { 17 | box-shadow: 0 2px 15px #ffb2b2, 1px 2px 3px #999; 18 | outline: none; 19 | } 20 | 21 | .python-error-block > header { 22 | font-size: 10px; 23 | font-weight: bold; 24 | color: #d69fa0; 25 | text-transform: lowercase; 26 | display: flex; 27 | flex-direction: row; 28 | align-content: space-between; 29 | align-items: center; 30 | justify-content: space-between; 31 | border-bottom: 1px solid #d69fa0; 32 | } 33 | 34 | .python-error-block--compressed { 35 | overflow: hidden; 36 | } 37 | 38 | .python-error-block__contents-outer { 39 | overflow: hidden; 40 | margin-left:10px; 41 | margin-top: 7px; 42 | } 43 | 44 | .python-error-block__contents { 45 | overflow-x: auto; 46 | } 47 | 48 | .python-error-block__suggestions { 49 | text-align: right; 50 | } 51 | -------------------------------------------------------------------------------- /src/browser/components/block-history/history-blocks/text-stream-block.css: -------------------------------------------------------------------------------- 1 | .text-stream-block { 2 | margin: 10px 4px 10px 2px; 3 | border-radius: 5px; 4 | padding: 6px; 5 | padding-top: 2px; 6 | border: 1px solid #ddd; 7 | box-shadow: 1px 2px 3px #999; 8 | color: #333; 9 | position: relative; 10 | transition: all 0.2s; 11 | } 12 | 13 | .text-stream-block:focus { 14 | box-shadow: 0 2px 10px #cce6ff, 1px 2px 3px #999; 15 | outline: none; 16 | } 17 | 18 | .text-stream-block--expanded { 19 | overflow-y: auto; 20 | overflow-x: inherit; 21 | } 22 | 23 | .text-stream-block--compressed { 24 | overflow: hidden; 25 | } 26 | 27 | .text-stream-block__contents-outer { 28 | overflow: hidden; 29 | margin-left:10px; 30 | } 31 | 32 | .text-stream-block__contents { 33 | overflow: hidden; 34 | white-space: pre-wrap; 35 | } 36 | 37 | .text-stream-block > header { 38 | font-size: 10px; 39 | font-weight: bold; 40 | color: #aaa; 41 | text-transform: lowercase; 42 | display: flex; 43 | flex-direction: row; 44 | align-content: space-between; 45 | align-items: center; 46 | justify-content: space-between; 47 | border-bottom: 1px solid #ccc; 48 | } 49 | -------------------------------------------------------------------------------- /src/browser/components/block-history/history-list.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import React from 'react'; 3 | import commonReact from '../../services/common-react'; 4 | 5 | /** 6 | * @class PackagesViewer 7 | * @extends ReactComponent 8 | */ 9 | export default React.createClass({ 10 | displayName: 'HistoryList', 11 | propTypes: { 12 | filter: React.PropTypes.string.isRequired, 13 | history: React.PropTypes.array.isRequired 14 | }, 15 | shouldComponentUpdate: function (nextProps) { 16 | return commonReact.shouldComponentUpdate(this, nextProps); 17 | }, 18 | render: function () { 19 | const props = this.props, 20 | className = commonReact.getClassNameList(this), 21 | history = _.filter(props.history, item => !props.filter || item.text.indexOf(props.filter) > -1); 22 | 23 | return ( 24 |
25 | 26 | 27 | {_.map(history, (item, index) => )} 28 | 29 |
{item.text}
30 |
31 | ); 32 | } 33 | }); 34 | -------------------------------------------------------------------------------- /src/browser/components/block-history/history-viewer.css: -------------------------------------------------------------------------------- 1 | .rodeo .history-viewer { 2 | height: 100%; 3 | overflow: auto; 4 | } 5 | 6 | .rodeo .history-viewer td { 7 | border: 0 8 | } 9 | -------------------------------------------------------------------------------- /src/browser/components/block-history/history-viewer.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import React from 'react'; 3 | import commonReact from '../../services/common-react'; 4 | import './history-viewer.css'; 5 | import EmptySuggestion from '../empty/empty-suggestion'; 6 | import HistoryList from './history-list'; 7 | 8 | /** 9 | * @class PackagesViewer 10 | * @extends ReactComponent 11 | */ 12 | export default React.createClass({ 13 | displayName: 'HistoryViewer', 14 | propTypes: { 15 | filter: React.PropTypes.string.isRequired, 16 | history: React.PropTypes.array.isRequired 17 | }, 18 | shouldComponentUpdate: function (nextProps) { 19 | return commonReact.shouldComponentUpdate(this, nextProps); 20 | }, 21 | render: function () { 22 | const props = this.props, 23 | className = commonReact.getClassNameList(this), 24 | contents = []; 25 | 26 | if (props.history && props.history.length) { 27 | contents.push(); 28 | } else { 29 | contents.push(); 30 | } 31 | 32 | return
{contents}
; 33 | } 34 | }); 35 | -------------------------------------------------------------------------------- /src/browser/components/brand-splashes/brand-splashes.css: -------------------------------------------------------------------------------- 1 | img.brand-splash { 2 | width: 100%; 3 | } 4 | -------------------------------------------------------------------------------- /src/browser/components/brand-splashes/logo-rodeo-grey-text.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/browser/components/brand-splashes/logo-rodeo-grey-text.sketch -------------------------------------------------------------------------------- /src/browser/components/brand-splashes/logo-rodeo-large.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import logo from './logo-rodeo-grey-text.svg'; 3 | import './brand-splashes.css'; 4 | 5 | /** 6 | * @class BrandSplash 7 | * @extends ReactComponent 8 | */ 9 | export default React.createClass({ 10 | displayName: 'BrandSplash', 11 | render: function () { 12 | return ; 13 | } 14 | }); 15 | -------------------------------------------------------------------------------- /src/browser/components/brand-splashes/logo-rodeo-square-large.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import logo from './logo-rodeo-square-large.svg'; 3 | import './brand-splashes.css'; 4 | 5 | /** 6 | * @class BrandSplash 7 | * @extends ReactComponent 8 | */ 9 | export default React.createClass({ 10 | displayName: 'BrandSplash', 11 | render: function () { 12 | return ; 13 | } 14 | }); 15 | -------------------------------------------------------------------------------- /src/browser/components/data-frame/data-frame-loading-icon.jsx: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import React from 'react'; 3 | 4 | /** 5 | * @class DataFrameLoadingIcon 6 | * @extends ReactComponent 7 | */ 8 | export default React.createClass({ 9 | displayName: 'DataFrameLoadingIcon', 10 | propTypes: { 11 | isLoading: React.PropTypes.bool.isRequired, 12 | label: React.PropTypes.string.isRequired 13 | }, 14 | getInitialState: function () { 15 | return {}; 16 | }, 17 | componentDidMount: function () { 18 | _.defer(() => this.setState({ 19 | hasRendered: true 20 | })); 21 | }, 22 | hasRendered: function () { 23 | this.setState({ 24 | hasRendered: true 25 | }); 26 | }, 27 | render: function () { 28 | const props = this.props, 29 | state = this.state, 30 | style = { 31 | opacity: props.isLoading && state.hasRendered ? 1 : 0 32 | }; 33 | 34 | return ( 35 |
36 | 37 |
{props.label}
38 |
39 | ); 40 | } 41 | }); 42 | -------------------------------------------------------------------------------- /src/browser/components/data-frame/data-frame-loading-icon.test.js: -------------------------------------------------------------------------------- 1 | /* globals describe, it, expect, jest */ 2 | 3 | import React from 'react'; 4 | import ReactDOM from 'react-dom'; 5 | import TestUtils from 'react-addons-test-utils'; 6 | import DataFrameLoadingIcon from './data-frame-loading-icon.jsx'; 7 | 8 | jest.useFakeTimers() 9 | 10 | describe('UnsafeHtml', () => { 11 | 12 | it('renders html with opacity 0 at first', () => { 13 | const reactDocument = TestUtils.renderIntoDocument(), 14 | el = ReactDOM.findDOMNode(reactDocument); 15 | 16 | expect(el.style.getPropertyValue('opacity')).toEqual('0'); 17 | }); 18 | 19 | it('renders html with opacity 1 right after', () => { 20 | const reactDocument = TestUtils.renderIntoDocument(), 21 | el = ReactDOM.findDOMNode(reactDocument); 22 | 23 | jest.runAllTimers(); 24 | 25 | expect(el.style.getPropertyValue('opacity')).toEqual('1'); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /src/browser/components/data-frame/data-frame.css: -------------------------------------------------------------------------------- 1 | .data-frame-container { 2 | overflow: hidden; 3 | } 4 | 5 | .data-frame-container .data-frame-loading-icon { 6 | position: absolute; 7 | top: calc(50% - 20px); 8 | left: calc(50% - 65px); 9 | text-align: center; 10 | transition: opacity 0.2s; 11 | } 12 | 13 | .data-frame-container .public_fixedDataTableCell_cellContent { 14 | white-space: nowrap; 15 | } 16 | 17 | -------------------------------------------------------------------------------- /src/browser/components/databases/database-explorer-tree-header.css: -------------------------------------------------------------------------------- 1 | .file-tree-header { 2 | padding: 2px; 3 | border-bottom: 1px solid #ccc; 4 | } 5 | 6 | .file-tree-header .item { 7 | cursor: pointer; 8 | color: #999; 9 | transition: all 0.2s; 10 | display: inline-block; 11 | margin-left: 8px; 12 | margin-right: 8px; 13 | } 14 | 15 | .file-tree-header .item:first-child { 16 | margin-left: 6px; 17 | } 18 | 19 | .file-tree-header .item:hover { 20 | color: #333; 21 | } 22 | 23 | .file-tree-header .item .fa { 24 | padding-right: 5px; 25 | } 26 | -------------------------------------------------------------------------------- /src/browser/components/databases/database-explorer-tree-header.jsx: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import React from 'react'; 3 | import commonReact from '../../services/common-react'; 4 | import './database-explorer-tree-header.css'; 5 | 6 | /** 7 | * @class FileList 8 | * @description Visual representation of the chrome around a list of files. Can show parent, sorts files by directory/file. 9 | * @extends ReactComponent 10 | * @property props 11 | */ 12 | export default React.createClass({ 13 | displayName: 'FileTreeHeader', 14 | propTypes: { 15 | 16 | }, 17 | render: function () { 18 | const props = this.props, 19 | className = commonReact.getClassNameList(this); 20 | 21 | return ( 22 |
23 |
{'Parent'}
24 |
{'Home'}
25 |
{'Working Directory'}
26 |
27 | ); 28 | } 29 | }); 30 | -------------------------------------------------------------------------------- /src/browser/components/databases/database-explorer-tree.css: -------------------------------------------------------------------------------- 1 | .file-tree { 2 | position: relative; 3 | overflow: auto; 4 | height: 100%; 5 | } 6 | -------------------------------------------------------------------------------- /src/browser/components/dialogs/about-rodeo.css: -------------------------------------------------------------------------------- 1 | .about-rodeo { 2 | padding: 20px; 3 | max-width: 600px; 4 | position: relative; 5 | } 6 | 7 | .about-rodeo img { 8 | max-height: 200px; 9 | width: 90%; 10 | } 11 | 12 | .about-rodeo button { 13 | margin: 10px auto 10px auto; 14 | display: block; 15 | } 16 | 17 | .about-rodeo .version { 18 | top: 0; 19 | right: 0; 20 | position: absolute; 21 | margin: 10px 16px; 22 | } 23 | -------------------------------------------------------------------------------- /src/browser/components/dialogs/about-rodeo.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Marked from '../marked'; 3 | import ActionButton from '../action-button'; 4 | import dialogActions from '../../actions/dialogs'; 5 | import rodeoTextDarkImage from './rodeo-text-dark.png'; 6 | import commonReact from '../../services/common-react'; 7 | import './about-rodeo.css'; 8 | 9 | export default React.createClass({ 10 | displayName: 'AboutRodeo', 11 | contextTypes: { 12 | text: React.PropTypes.object 13 | }, 14 | shouldComponentUpdate(nextProps) { 15 | return commonReact.shouldComponentUpdate(this, nextProps); 16 | }, 17 | render() { 18 | const className = commonReact.getClassNameList(this), 19 | text = this.context.text; 20 | 21 | return ( 22 |
23 | 24 |
{__VERSION__}
25 | {text.builtByYhat} 26 | {text.includesOpenSource} 27 | 28 | {text.acknowledgements} 29 | 30 | {text.usageMetrics} 31 |
32 | ); 33 | } 34 | }); 35 | -------------------------------------------------------------------------------- /src/browser/components/dialogs/acknowledgements.css: -------------------------------------------------------------------------------- 1 | .acknowledgements { 2 | display: flex; 3 | flex-direction: column; 4 | padding: 20px; 5 | max-width: 600px; 6 | position: relative; 7 | } 8 | 9 | .acknowledgements img { 10 | max-height: 200px; 11 | width: 90%; 12 | } 13 | 14 | .acknowledgements .scrollable { 15 | overflow-y: scroll; 16 | } 17 | -------------------------------------------------------------------------------- /src/browser/components/dialogs/acknowledgements.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Marked from '../marked'; 3 | import acknowledgementsText from './acknowledgements.md'; 4 | import './acknowledgements.css'; 5 | import rodeoTextDarkImage from './rodeo-text-dark.png'; 6 | 7 | export default React.createClass({ 8 | displayName: 'Acknowledgements', 9 | render: function () { 10 | return ( 11 |
12 | 13 |
14 | {acknowledgementsText} 15 |
16 |
17 | ); 18 | } 19 | }); 20 | -------------------------------------------------------------------------------- /src/browser/components/dialogs/ask-quit.css: -------------------------------------------------------------------------------- 1 | .ask-quit__question { 2 | display: flex; 3 | justify-content: center; 4 | margin: 20px; 5 | font-size: large; 6 | } 7 | 8 | .ask-quit__item { 9 | display: flex; 10 | justify-content: center; 11 | margin: 20px; 12 | } 13 | 14 | .ask-quit__small-item { 15 | display: flex; 16 | justify-content: center; 17 | margin: 10px; 18 | transform: scale(0.8); 19 | } 20 | -------------------------------------------------------------------------------- /src/browser/components/dialogs/environment-variables-dialog.css: -------------------------------------------------------------------------------- 1 | .environment-variables-dialog { 2 | position: relative; 3 | min-height: 400px; 4 | height: 100%; 5 | } 6 | 7 | .environment-variables-dialog > footer { 8 | bottom: 0; 9 | right: 0; 10 | padding: 7px 20px; 11 | height: 50px; 12 | text-align: right; 13 | position: relative; 14 | } 15 | 16 | .environment-variables-dialog__content { 17 | padding: 20px; 18 | overflow-y: scroll; 19 | position: relative; 20 | display: flex; 21 | flex-direction: row; 22 | align-content: stretch; 23 | align-items: stretch; 24 | height: calc(100% - 50px); 25 | } 26 | -------------------------------------------------------------------------------- /src/browser/components/dialogs/modal-dialog-container.css: -------------------------------------------------------------------------------- 1 | .modal-dialog-container { 2 | position: absolute; 3 | display: none; 4 | top: 0; 5 | bottom: 0; 6 | left: 0; 7 | right: 0; 8 | z-index: 1000; /* higher than split-panes */ 9 | } 10 | 11 | .modal-dialog-container .inner-container { 12 | position: absolute; 13 | display: flex; 14 | top: 0; 15 | bottom: 0; 16 | left: 0; 17 | right: 0; 18 | justify-content: center; 19 | flex-direction: column; 20 | } 21 | 22 | .modal-dialog-container .inner-container:last-child { 23 | background-color: rgba(50, 50, 100, 0.5); 24 | z-index: 11; 25 | } 26 | 27 | .modal-dialog-container.modal-dialog-container--active { 28 | display: block; 29 | } 30 | -------------------------------------------------------------------------------- /src/browser/components/dialogs/modal-dialog.css: -------------------------------------------------------------------------------- 1 | .modal-dialog-instance { 2 | margin-left: auto; 3 | margin-right: auto; 4 | display: flex; 5 | flex-direction: column; 6 | min-width: 400px; 7 | max-width: 1000px; 8 | max-height: 90%; 9 | z-index: 11; 10 | background-color: white; 11 | box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.4); 12 | transition: all 0.8s; 13 | opacity: 0; 14 | border-radius: 2px; 15 | } 16 | 17 | .modal-dialog-instance.modal-dialog-instance--small { 18 | width: 100px; 19 | } 20 | 21 | .modal-dialog-instance.modal-dialog-instance--full { 22 | width: 100%; 23 | height: 100%; 24 | } 25 | 26 | .modal-dialog-instance.modal-dialog-instance--visible { 27 | opacity: 1; 28 | } 29 | 30 | .modal-dialog-instance > header { 31 | flex: 0 0 10px; 32 | position: relative; 33 | background-color: #337ab7; 34 | color: #fff; 35 | padding: 2px 12px; 36 | border-top-left-radius: 2px; 37 | border-top-right-radius: 2px; 38 | font-weight: bold; 39 | } 40 | 41 | .modal-dialog-instance > footer { 42 | flex: 0 0 40px; 43 | position: relative; 44 | } 45 | 46 | .modal-dialog-instance button { 47 | margin-left: 10px; 48 | } 49 | -------------------------------------------------------------------------------- /src/browser/components/dialogs/modal-dialog.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import React from 'react'; 3 | import ReactDOM from 'react-dom'; 4 | import commonReact from '../../services/common-react'; 5 | import './modal-dialog.css'; 6 | 7 | export default React.createClass({ 8 | displayName: 'ModalDialog', 9 | propTypes: { 10 | buttons: React.PropTypes.array, 11 | onApply: React.PropTypes.func, 12 | onCancel: React.PropTypes.func, 13 | onOK: React.PropTypes.func, 14 | title: React.PropTypes.string 15 | }, 16 | contextTypes: { 17 | text: React.PropTypes.object.isRequired 18 | }, 19 | componentDidMount() { 20 | const el = ReactDOM.findDOMNode(this); 21 | 22 | _.defer(() => el.classList.add('modal-dialog-instance--visible')); 23 | }, 24 | shouldComponentUpdate(nextProps) { 25 | return commonReact.shouldComponentUpdate(this, nextProps); 26 | }, 27 | render() { 28 | const props = this.props, 29 | className = commonReact.getClassNameList(this); 30 | let header; 31 | 32 | className.push('modal-dialog-instance'); 33 | 34 | if (props.title) { 35 | header =
{props.title}
; 36 | } 37 | 38 | return ( 39 |
40 | {header} 41 | {props.children} 42 |
43 | ); 44 | } 45 | }); 46 | -------------------------------------------------------------------------------- /src/browser/components/dialogs/rodeo-text-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/browser/components/dialogs/rodeo-text-dark.png -------------------------------------------------------------------------------- /src/browser/components/dialogs/stickers-pane.css: -------------------------------------------------------------------------------- 1 | .stickers-pane { 2 | text-align: center; 3 | padding: 20px; 4 | max-width: 600px; 5 | position: relative; 6 | } 7 | 8 | .stickers-pane__logo { 9 | display: block; 10 | margin: 10px; 11 | } 12 | 13 | .stickers-pane__logo img { 14 | height: 100px; 15 | } 16 | -------------------------------------------------------------------------------- /src/browser/components/document-terminal/document-terminal-annotation.css: -------------------------------------------------------------------------------- 1 | .document-terminal-annotation { 2 | overflow: hidden; 3 | padding: 2px; 4 | margin: 5px; 5 | position: relative; 6 | cursor: pointer; 7 | } 8 | 9 | .document-terminal-annotation img { 10 | width: 100%; 11 | height: auto; 12 | } 13 | 14 | .document-terminal-annotation__image { 15 | display: block; 16 | height: auto; 17 | width: 20%; 18 | min-width: 100px; 19 | max-width: 200px; 20 | overflow: hidden; 21 | padding: 2px; 22 | margin: 5px; 23 | position: relative; 24 | } 25 | -------------------------------------------------------------------------------- /src/browser/components/document-terminal/document-terminal-autocomplete.css: -------------------------------------------------------------------------------- 1 | .document-terminal-autocomplete { 2 | display: flex; 3 | flex-direction: row; 4 | flex-wrap: wrap; 5 | border: solid 1px rgba(0, 135, 255, 0.2); 6 | background-color: rgba(0, 135, 255, 0.05); 7 | margin: 6px; 8 | padding: 4px; 9 | } 10 | 11 | .document-terminal-autocomplete-item { 12 | white-space: pre; 13 | margin-right: 20px; 14 | margin-left: 10px; 15 | } 16 | -------------------------------------------------------------------------------- /src/browser/components/document-terminal/document-terminal-autocomplete.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import commonReact from '../../services/common-react'; 3 | import textUtil from '../../services/text-util'; 4 | import './document-terminal-autocomplete.css'; 5 | 6 | export default React.createClass({ 7 | displayName: 'DocumentTerminalAutocomplete', 8 | propTypes: { 9 | matches: React.PropTypes.array.isRequired 10 | }, 11 | shouldComponentUpdate: function (nextProps) { 12 | return commonReact.shouldComponentUpdate(this, nextProps); 13 | }, 14 | render: function () { 15 | const props = this.props, 16 | matches = props.matches, 17 | className = commonReact.getClassNameList(this), 18 | longestLen = textUtil.longestLength(matches), 19 | paddedMatches = matches.map(match => textUtil.padRight(match, longestLen)); 20 | 21 | return ( 22 |
23 | {paddedMatches.map(match => {match})} 24 |
25 | ); 26 | } 27 | }); 28 | -------------------------------------------------------------------------------- /src/browser/components/document-terminal/document-terminal-error.css: -------------------------------------------------------------------------------- 1 | .document-terminal-error { 2 | padding: 0; 3 | position: relative; 4 | color: #b11e22; 5 | margin: 0 10px; 6 | } 7 | 8 | .document-terminal-error__suggestions { 9 | text-align: right; 10 | } 11 | -------------------------------------------------------------------------------- /src/browser/components/document-terminal/document-terminal-page-break.css: -------------------------------------------------------------------------------- 1 | .document-terminal-page-break { 2 | clear: both; 3 | border: 0; 4 | margin-top: 0; 5 | margin-bottom: 0; 6 | } 7 | -------------------------------------------------------------------------------- /src/browser/components/document-terminal/document-terminal-page-break.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import commonReact from '../../services/common-react'; 3 | import './document-terminal-page-break.css'; 4 | 5 | export default React.createClass({ 6 | displayName: 'DocumentTerminalPageBreak', 7 | shouldComponentUpdate: function (nextProps) { 8 | return false; 9 | }, 10 | render: function () { 11 | const className = commonReact.getClassNameList(this); 12 | 13 | return
; 14 | } 15 | }); 16 | /** 17 | * Created by danestuckel on 10/11/16. 18 | */ 19 | -------------------------------------------------------------------------------- /src/browser/components/document-terminal/document-terminal-python-error.css: -------------------------------------------------------------------------------- 1 | .document-terminal-python-error { 2 | padding: 0; 3 | position: relative; 4 | color: #b11e22; 5 | margin: 0 10px; 6 | } 7 | 8 | .document-terminal-python-error__suggestions { 9 | text-align: right; 10 | } 11 | -------------------------------------------------------------------------------- /src/browser/components/document-terminal/document-terminal-text.css: -------------------------------------------------------------------------------- 1 | .document-terminal-text { 2 | color: #333; 3 | margin: 0 10px; 4 | white-space: pre-wrap; 5 | word-break: break-all; 6 | } 7 | -------------------------------------------------------------------------------- /src/browser/components/document-terminal/document-terminal-text.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import commonReact from '../../services/common-react'; 3 | import './document-terminal-text.css'; 4 | 5 | export default React.createClass({ 6 | displayName: 'DocumentTerminalText', 7 | propTypes: { 8 | html: React.PropTypes.string.isRequired, 9 | id: React.PropTypes.string.isRequired 10 | }, 11 | shouldComponentUpdate: function (nextProps) { 12 | return commonReact.shouldComponentUpdate(this, nextProps); 13 | }, 14 | render: function () { 15 | const props = this.props, 16 | className = commonReact.getClassNameList(this); 17 | 18 | return ( 19 |
24 | ); 25 | } 26 | }); 27 | -------------------------------------------------------------------------------- /src/browser/components/document-terminal/document-terminal.css: -------------------------------------------------------------------------------- 1 | .document-terminal { 2 | position: relative; 3 | height: 100%; 4 | display: flex; 5 | flex-direction: column; 6 | align-items: stretch; 7 | align-content: stretch; 8 | } 9 | 10 | .document-terminal .sticky-bottom-scroll { 11 | flex-grow: 5; 12 | overflow-y: auto; 13 | white-space: pre-wrap; 14 | } 15 | 16 | .document-terminal .prompt { 17 | flex-grow: 0; 18 | flex-shrink: 0; 19 | } 20 | -------------------------------------------------------------------------------- /src/browser/components/document-terminal/document-terminal.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import commonReact from '../../services/common-react'; 3 | import './document-terminal.css'; 4 | 5 | export default React.createClass({ 6 | displayName: 'DocumentTerminal', 7 | propTypes: { 8 | onClick: React.PropTypes.func, 9 | onPaste: React.PropTypes.func 10 | }, 11 | shouldComponentUpdate: function (nextProps) { 12 | return commonReact.shouldComponentUpdate(this, nextProps); 13 | }, 14 | render: function () { 15 | const props = this.props, 16 | className = commonReact.getClassNameList(this), 17 | style = { 18 | fontSize: props.fontSize + 'px' 19 | }; 20 | 21 | className.push('font-monospaced'); 22 | 23 | return ( 24 |
{props.children}
30 | ); 31 | } 32 | }); 33 | -------------------------------------------------------------------------------- /src/browser/components/document-terminal/sticky-bottom-scroll.css: -------------------------------------------------------------------------------- 1 | .sticky-bottom-scroll { 2 | overflow-y: auto; 3 | display: block; 4 | } 5 | -------------------------------------------------------------------------------- /src/browser/components/empty/empty-suggestion.css: -------------------------------------------------------------------------------- 1 | .empty-suggestion { 2 | color: #cbcbcb; 3 | display: flex; 4 | align-items: center; 5 | justify-content: center; 6 | height: 100%; 7 | font-size: 14px; 8 | } 9 | -------------------------------------------------------------------------------- /src/browser/components/empty/empty-suggestion.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './empty-suggestion.css'; 3 | import commonReact from '../../services/common-react'; 4 | import Marked from '../marked'; 5 | 6 | export default React.createClass({ 7 | displayName: 'EmptySuggestion', 8 | propTypes: { 9 | label: React.PropTypes.string.isRequired 10 | }, 11 | getDefaultProps() { 12 | return { 13 | label: '' 14 | }; 15 | }, 16 | shouldComponentUpdate: function (nextProps) { 17 | return commonReact.shouldComponentUpdate(this, nextProps); 18 | }, 19 | render: function () { 20 | const props = this.props, 21 | className = commonReact.getClassNameList(this); 22 | 23 | className.push('font-sans'); 24 | 25 | return
{props.label}
; 26 | } 27 | }); 28 | -------------------------------------------------------------------------------- /src/browser/components/files/file-list.css: -------------------------------------------------------------------------------- 1 | .file-list { 2 | position: relative; 3 | overflow: auto; 4 | height: 100%; 5 | } 6 | 7 | .file-list-item { 8 | color: #808080; 9 | padding: 2px 10px; 10 | display: block; 11 | cursor: pointer; 12 | } 13 | 14 | .file-list-item .fa-before:before { 15 | padding-right: 6px; 16 | } 17 | 18 | .file-list-item:hover { 19 | background-color: #dddddd; 20 | } 21 | 22 | .file-list-item.file-list-item-selected { 23 | background-color: #95d7ff; 24 | } 25 | 26 | .file-list-item.selected:hover { 27 | background-color: #b7e5ff; 28 | } 29 | -------------------------------------------------------------------------------- /src/browser/components/files/file-list.jsx: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import React from 'react'; 3 | import FileListItem from './file-list-item.jsx'; 4 | import './file-list.css'; 5 | 6 | /** 7 | * @class FileList 8 | * @description Visual representation of the chrome around a list of files. Can show parent, sorts files by directory/file. 9 | * @extends ReactComponent 10 | * @property props 11 | */ 12 | export default React.createClass({ 13 | displayName: 'FileList', 14 | propTypes: { 15 | id: React.PropTypes.string, 16 | onGoToSpecialDirectory: React.PropTypes.func 17 | }, 18 | render: function () { 19 | const props = this.props; 20 | let parent, 21 | files = React.Children.toArray(props.children); 22 | 23 | files = _.filter(files, item => !props.filter || item.props.label.indexOf(props.filter) > -1); 24 | 25 | if (props.onGoToSpecialDirectory) { 26 | parent = ( 27 | 33 | ); 34 | } 35 | 36 | return ( 37 |
38 | {parent} 39 | {files.filter(file => file.props.isDirectory)} 40 | {files.filter(file => !file.props.isDirectory)} 41 |
42 | ); 43 | } 44 | }); 45 | -------------------------------------------------------------------------------- /src/browser/components/files/file-tree-header.css: -------------------------------------------------------------------------------- 1 | .file-tree-header { 2 | padding: 2px; 3 | border-bottom: 1px solid #ccc; 4 | } 5 | 6 | .file-tree-header .item { 7 | cursor: pointer; 8 | color: #999; 9 | transition: all 0.2s; 10 | display: inline-block; 11 | margin-left: 8px; 12 | margin-right: 8px; 13 | } 14 | 15 | .file-tree-header .item:first-child { 16 | margin-left: 6px; 17 | } 18 | 19 | .file-tree-header .item:hover { 20 | color: #333; 21 | } 22 | 23 | .file-tree-header .item .fa { 24 | padding-right: 5px; 25 | } 26 | -------------------------------------------------------------------------------- /src/browser/components/files/file-tree-header.jsx: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import React from 'react'; 3 | import commonReact from '../../services/common-react'; 4 | import './file-tree-header.css'; 5 | 6 | /** 7 | * @class FileList 8 | * @description Visual representation of the chrome around a list of files. Can show parent, sorts files by directory/file. 9 | * @extends ReactComponent 10 | * @property props 11 | */ 12 | export default React.createClass({ 13 | displayName: 'FileTreeHeader', 14 | propTypes: { 15 | onGoToSpecialDirectory: React.PropTypes.func.isRequired 16 | }, 17 | render: function () { 18 | const props = this.props, 19 | className = commonReact.getClassNameList(this); 20 | 21 | return ( 22 |
23 |
{'Parent'}
24 |
{'Home'}
25 |
{'Working Directory'}
26 |
27 | ); 28 | } 29 | }); 30 | -------------------------------------------------------------------------------- /src/browser/components/files/file-tree.css: -------------------------------------------------------------------------------- 1 | .file-tree { 2 | position: relative; 3 | overflow: auto; 4 | height: 100%; 5 | } 6 | -------------------------------------------------------------------------------- /src/browser/components/forms/button-referenced.css: -------------------------------------------------------------------------------- 1 | .button-referenced { 2 | margin-left: 0; 3 | } 4 | -------------------------------------------------------------------------------- /src/browser/components/forms/button-referenced.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import React from 'react'; 3 | import commonReact from '../../services/common-react'; 4 | 5 | export default React.createClass({ 6 | displayName: 'ButtonReferenced', 7 | contextTypes: { 8 | text: React.PropTypes.object 9 | }, 10 | shouldComponentUpdate: function (nextProps) { 11 | return commonReact.shouldComponentUpdate(this, nextProps); 12 | }, 13 | render: function () { 14 | const props = this.props, 15 | text = this.context.text, 16 | className = commonReact.getClassNameList(this), 17 | handleClick = props.clickHandler && _.isFunction(props[props.clickHandler]) && _.partial(props[props.clickHandler], props.value); 18 | let content; 19 | 20 | if (handleClick) { 21 | content = ; 22 | } else { 23 | content = ; 24 | } 25 | 26 | return
{content}
; 27 | } 28 | }); 29 | -------------------------------------------------------------------------------- /src/browser/components/forms/form-list.css: -------------------------------------------------------------------------------- 1 | .form-list { 2 | width: 100%; 3 | } 4 | 5 | .form-item { 6 | margin: 20px; 7 | } 8 | 9 | .form-item:first-child { 10 | margin-top: 10px; 11 | } 12 | 13 | .form-item .form-input { 14 | margin-left: 20px; 15 | } 16 | 17 | /* input group is a input combined with a button */ 18 | .input-group { 19 | position: relative; 20 | display: table; 21 | border-collapse: separate; 22 | margin-left: 20px; 23 | } 24 | 25 | .input-group input.form-input { 26 | display: table-cell; 27 | margin-left: 0; 28 | } 29 | 30 | .input-group select.form-input { 31 | display: table-cell; 32 | } 33 | 34 | .input-group .input-group-container { 35 | vertical-align: top; 36 | display: table-cell; 37 | width: 1%; 38 | } 39 | -------------------------------------------------------------------------------- /src/browser/components/forms/input-checkbox.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import commonReact from '../../services/common-react'; 3 | 4 | export default React.createClass({ 5 | displayName: 'InputCheckbox', 6 | propTypes: { 7 | onChange: React.PropTypes.func.isRequired, 8 | originalValue: React.PropTypes.bool, 9 | value: React.PropTypes.bool 10 | }, 11 | contextTypes: { 12 | text: React.PropTypes.object 13 | }, 14 | shouldComponentUpdate: function (nextProps) { 15 | return commonReact.shouldComponentUpdate(this, nextProps); 16 | }, 17 | render: function () { 18 | const props = this.props, 19 | text = this.context.text, 20 | className = commonReact.getClassNameList(this); 21 | 22 | return ( 23 |
24 | 25 | 26 |
27 | ); 28 | } 29 | }); 30 | -------------------------------------------------------------------------------- /src/browser/components/forms/input-number.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import commonReact from '../../services/common-react'; 3 | 4 | export default React.createClass({ 5 | displayName: 'InputNumber', 6 | propTypes: { 7 | onChange: React.PropTypes.func.isRequired, 8 | originalValue: React.PropTypes.number, 9 | value: React.PropTypes.number 10 | }, 11 | contextTypes: { 12 | text: React.PropTypes.object 13 | }, 14 | shouldComponentUpdate: function (nextProps) { 15 | return commonReact.shouldComponentUpdate(this, nextProps); 16 | }, 17 | render: function () { 18 | const props = this.props, 19 | text = this.context.text, 20 | className = commonReact.getClassNameList(this); 21 | 22 | if (props.originalValue !== props.value) { 23 | className.push('number-input--modified'); 24 | } 25 | 26 | return ( 27 |
28 | 29 | 30 |
31 | ); 32 | } 33 | }); 34 | -------------------------------------------------------------------------------- /src/browser/components/forms/input-select.css: -------------------------------------------------------------------------------- 1 | .input-select select { 2 | display: table-cell; 3 | height: 30px; 4 | padding-right: 20px; 5 | padding-left: 5px; 6 | } 7 | -------------------------------------------------------------------------------- /src/browser/components/forms/input-text.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import commonReact from '../../services/common-react'; 3 | 4 | export default React.createClass({ 5 | displayName: 'TextInput', 6 | propTypes: { 7 | onChange: React.PropTypes.func.isRequired, 8 | originalValue: React.PropTypes.string, 9 | value: React.PropTypes.string 10 | }, 11 | contextTypes: { 12 | text: React.PropTypes.object 13 | }, 14 | shouldComponentUpdate: function (nextProps) { 15 | return commonReact.shouldComponentUpdate(this, nextProps); 16 | }, 17 | render: function () { 18 | const props = this.props, 19 | text = this.context.text, 20 | className = commonReact.getClassNameList(this); 21 | 22 | if (props.originalValue !== props.value) { 23 | className.push('preferences-text--modified'); 24 | } 25 | 26 | return ( 27 |
28 | 29 | 30 |
31 | ); 32 | } 33 | }); 34 | -------------------------------------------------------------------------------- /src/browser/components/forms/readme.md: -------------------------------------------------------------------------------- 1 | # Forms 2 | 3 | A FormList contains form items. 4 | 5 | A FormItem has a value. If the value is different than the originalValue, then the item state is modified. 6 | 7 | If a FormItem has errors, then they have FormItemErrors. 8 | -------------------------------------------------------------------------------- /src/browser/components/forms/rodeo-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/browser/components/forms/rodeo-logo.png -------------------------------------------------------------------------------- /src/browser/components/gray-info/gray-info-link-list.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './gray-info.css'; 3 | import commonReact from '../../services/common-react'; 4 | 5 | export default React.createClass({ 6 | displayName: 'GrayInfoLinkList', 7 | shouldComponentUpdate: function () { 8 | return true; 9 | }, 10 | render: function () { 11 | const props = this.props, 12 | className = commonReact.getClassNameList(this); 13 | 14 | return
{props.children}
; 15 | } 16 | }); 17 | -------------------------------------------------------------------------------- /src/browser/components/gray-info/gray-info-link.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './gray-info.css'; 3 | import commonReact from '../../services/common-react'; 4 | 5 | export default React.createClass({ 6 | displayName: 'GrayInfoLink', 7 | propTypes: { 8 | icon: React.PropTypes.string, 9 | label: React.PropTypes.string, 10 | onClick: React.PropTypes.func.isRequired, 11 | title: React.PropTypes.string 12 | }, 13 | shouldComponentUpdate: function (nextProps) { 14 | return commonReact.shouldComponentUpdate(this, nextProps); 15 | }, 16 | render: function () { 17 | const props = this.props, 18 | className = commonReact.getClassNameList(this); 19 | let icon; 20 | 21 | if (props.icon) { 22 | icon = ; 23 | } 24 | 25 | return ( 26 |
27 | {icon} 28 | {props.label} 29 |
30 | ); 31 | } 32 | }); 33 | -------------------------------------------------------------------------------- /src/browser/components/gray-info/gray-info.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './gray-info.css'; 3 | import commonReact from '../../services/common-react'; 4 | 5 | export default React.createClass({ 6 | displayName: 'GrayInfo', 7 | shouldComponentUpdate: function (nextProps) { 8 | return commonReact.shouldComponentUpdate(this, nextProps); 9 | }, 10 | render: function () { 11 | const props = this.props, 12 | className = commonReact.getClassNameList(this); 13 | 14 | return
{props.children}
; 15 | } 16 | }); 17 | -------------------------------------------------------------------------------- /src/browser/components/layout-containers/full-screen.css: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | main, 4 | .full-screen { 5 | height: 100%; 6 | } 7 | 8 | .full-screen--row { 9 | display: flex; 10 | flex-direction: row; 11 | } 12 | 13 | .full-screen--row > * { 14 | flex: 1 1; 15 | } 16 | 17 | .splitter_panel { 18 | height: 100%; 19 | } 20 | -------------------------------------------------------------------------------- /src/browser/components/layout-containers/full-screen.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import commonReact from '../../services/common-react'; 3 | import './full-screen.css'; 4 | 5 | export default React.createClass({ 6 | displayName: 'FullScreen', 7 | propTypes: { 8 | row: React.PropTypes.bool 9 | }, 10 | render: function () { 11 | const props = this.props, 12 | className = commonReact.getClassNameList(this); 13 | 14 | if (props.row) { 15 | className.push('full-screen--row'); 16 | } 17 | 18 | return
{props.children}
; 19 | } 20 | }); 21 | -------------------------------------------------------------------------------- /src/browser/components/manage-connections/connection-config.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import commonReact from '../../services/common-react'; 3 | import PostgresqlSettings from './types/postgresql-settings'; 4 | // import MysqlSettings from './types/mysql-settings'; 5 | // import RedshiftSettings from './types/redshift-settings'; 6 | // import SqlserverSettings from './types/sqlserver-settings'; 7 | 8 | export default React.createClass({ 9 | displayName: 'ConnectionConfig', 10 | propTypes: { 11 | definitions: React.PropTypes.object.isRequired, 12 | list: React.PropTypes.array, // could be nothing 13 | onChange: React.PropTypes.func.isRequired 14 | }, 15 | shouldComponentUpdate: function (nextProps) { 16 | return commonReact.shouldComponentUpdate(this, nextProps); 17 | }, 18 | render: function () { 19 | const props = this.props, 20 | className = commonReact.getClassNameList(this), 21 | types = { 22 | postgresql: () => 23 | }, 24 | type = props.type || props.definitions.defaultType; // no item selected, so none. 25 | 26 | return
{types[type]()}
; 27 | } 28 | }); 29 | -------------------------------------------------------------------------------- /src/browser/components/manage-connections/connection-errors.css: -------------------------------------------------------------------------------- 1 | .connection-errors { 2 | background-color: #ff8280; 3 | border-radius: 5px; 4 | padding: 5px 10px; 5 | margin: 10px; 6 | } 7 | -------------------------------------------------------------------------------- /src/browser/components/manage-connections/connection-errors.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import React from 'react'; 3 | import commonReact from '../../services/common-react'; 4 | import './connection-errors.css'; 5 | 6 | function filterErrorMessages(error) { 7 | if (error.message) { 8 | if (_.includes(error.message, 'ECONNREFUSED')) { 9 | return 'Connection refused'; 10 | } else if (_.includes(error.message, 'getaddrinfo ENOTFOUND')) { 11 | return 'Address not found'; 12 | } else if (/role ".+" does not exist/.test(error.message)) { 13 | return 'User not found'; 14 | } else if (/database ".+" does not exist/.test(error.message)) { 15 | return 'Database not found'; 16 | } else { 17 | return error.message; 18 | } 19 | } else { 20 | return error.toString(); 21 | } 22 | } 23 | 24 | export default React.createClass({ 25 | displayName: 'ConnectionErrors', 26 | propTypes: { 27 | }, 28 | shouldComponentUpdate: function (nextProps) { 29 | return commonReact.shouldComponentUpdate(this, nextProps); 30 | }, 31 | render: function () { 32 | const props = this.props, 33 | className = commonReact.getClassNameList(this); 34 | 35 | return ( 36 |
37 | {props.errors.map(error =>
{filterErrorMessages(error)}
)} 38 |
39 | ); 40 | } 41 | }); 42 | -------------------------------------------------------------------------------- /src/browser/components/notifications/chat-alt-flat.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 16 | 17 | 18 | 19 | 20 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/browser/components/notifications/download-cloud-flat.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/browser/components/notifications/info-notification.css: -------------------------------------------------------------------------------- 1 | .info-notification { 2 | margin: 7px; 3 | padding: 9px; 4 | display: block; 5 | position: relative; 6 | min-width: 250px; 7 | max-width: 400px; 8 | max-height: 90%; 9 | z-index: 11; 10 | background-color: white; 11 | box-shadow: 4px 4px 16px rgba(0, 0, 0, 0.4); 12 | transition: all 0.8s; 13 | opacity: 0; 14 | border-radius: 5px; 15 | min-height: 50px; 16 | } 17 | 18 | .info-notification .icon-container { 19 | display: block; 20 | text-align: center; 21 | } 22 | .info-notification .icon-container img { 23 | width: 80px; 24 | } 25 | 26 | .info-notification p:first-child { 27 | margin-top: 10px; 28 | } 29 | 30 | .info-notification p:last-child { 31 | margin-bottom: 0; 32 | } 33 | 34 | .info-notification .info-notification-content { 35 | margin-left: 20px; 36 | margin-right: 60px; 37 | min-height: 27px; 38 | } 39 | 40 | .info-notification.notification-show { 41 | opacity: 1; 42 | } 43 | 44 | .info-notification button { 45 | position: absolute; 46 | bottom: 0; 47 | right: 0; 48 | margin: 12px; 49 | } 50 | -------------------------------------------------------------------------------- /src/browser/components/notifications/info-notification.jsx: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import React from 'react'; 3 | import ReactDOM from 'react-dom'; 4 | import './info-notification.css'; 5 | import negativeMessage from './chat-alt-flat.svg'; 6 | 7 | const showClass = 'notification-show'; 8 | 9 | /** 10 | * @class InfoNotification 11 | * @extends ReactComponent 12 | * @property props 13 | */ 14 | export default React.createClass({ 15 | displayName: 'InfoNotification', 16 | propTypes: { 17 | id: React.PropTypes.string.isRequired, 18 | onOK: React.PropTypes.func 19 | }, 20 | componentDidMount: function () { 21 | const el = ReactDOM.findDOMNode(this); 22 | 23 | _.defer(() => el.classList.add(showClass)); 24 | }, 25 | render: function () { 26 | const props = this.props; 27 | 28 | return ( 29 |
30 |
31 |
{props.children}
32 | 33 |
34 | ); 35 | } 36 | }); 37 | -------------------------------------------------------------------------------- /src/browser/components/notifications/notifications-container.css: -------------------------------------------------------------------------------- 1 | .notifications-container { 2 | position: absolute; 3 | display: block; 4 | top: 0; 5 | right: 0; 6 | z-index: 1000; /* higher than split-panes */ 7 | } 8 | -------------------------------------------------------------------------------- /src/browser/components/notifications/notifications.actions.js: -------------------------------------------------------------------------------- 1 | export function add(contentType, title, content) { 2 | return {type: 'ADD_NOTIFICATION', contentType, title, content}; 3 | } 4 | 5 | export function close(notification) { 6 | return {type: 'CLOSE_NOTIFICATION', notification}; 7 | } 8 | 9 | export function closeAll() { 10 | return {type: 'CLOSE_ALL_NOTIFICATIONS'}; 11 | } 12 | 13 | export default { 14 | add, 15 | close, 16 | closeAll 17 | }; 18 | -------------------------------------------------------------------------------- /src/browser/components/notifications/update-available-notification.css: -------------------------------------------------------------------------------- 1 | .update-available-notification { 2 | margin: 7px; 3 | padding: 9px; 4 | display: block; 5 | position: relative; 6 | min-width: 250px; 7 | max-width: 400px; 8 | max-height: 90%; 9 | z-index: 11; 10 | background-color: white; 11 | box-shadow: 4px 4px 16px rgba(0, 0, 0, 0.4); 12 | transition: all 0.8s; 13 | opacity: 0; 14 | border-radius: 5px; 15 | min-height: 50px; 16 | text-align: center; 17 | } 18 | 19 | .update-available-notification .icon-container { 20 | display: block; 21 | } 22 | 23 | .update-available-notification .icon-container img { 24 | width: 80px; 25 | } 26 | 27 | .update-available-notification .info-notification-content { 28 | margin-left: 20px; 29 | margin-right: 20px; 30 | min-height: 27px; 31 | margin-top: 26px; 32 | } 33 | 34 | .update-available-notification.notification-show { 35 | opacity: 1; 36 | } 37 | 38 | .update-available-notification > footer { 39 | display: flex; 40 | justify-content: space-around; 41 | } 42 | 43 | .info-notification button { 44 | margin: 12px; 45 | } 46 | -------------------------------------------------------------------------------- /src/browser/components/packages/package-search-list.css: -------------------------------------------------------------------------------- 1 | .package-search-list { 2 | padding: 10px; 3 | overflow-y: auto; 4 | height: 100%; 5 | } 6 | 7 | .package-search-list > header { 8 | margin-left: auto; 9 | margin-right: auto; 10 | width: 80%; 11 | display: table; 12 | } 13 | 14 | .package-search-list > header input { 15 | width: 100%; 16 | display: table-cell; 17 | } 18 | 19 | .package-search-list .suggestion { 20 | display: flex; 21 | align-items: center; 22 | justify-content: center; 23 | color: #cbcbcb; 24 | } 25 | 26 | .package-search-list .button-shift { 27 | display: table-cell; 28 | width: 1%; 29 | white-space: nowrap; 30 | vertical-align: middle; 31 | position: relative; 32 | font-size: 0; 33 | padding-left: 10px; 34 | } 35 | -------------------------------------------------------------------------------- /src/browser/components/packages/packages-list.css: -------------------------------------------------------------------------------- 1 | .packages-list .btn { 2 | margin: 10px; 3 | } 4 | 5 | .packages-list .package-actions { 6 | display: flex; 7 | align-items: center; 8 | justify-content: center; 9 | } 10 | 11 | .packages-list button .fa { 12 | margin-right: 10px; 13 | } 14 | -------------------------------------------------------------------------------- /src/browser/components/plot-preview/foreground-plot.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import UnsafeHTML from '../unsafe-html.js'; 3 | import './plot-preview.css'; 4 | import commonReact from '../../services/common-react'; 5 | 6 | /** 7 | * @class ForegroundPlot 8 | * @extends ReactComponent 9 | * @property props 10 | */ 11 | export default React.createClass({ 12 | displayName: 'ForegroundPlot', 13 | propTypes: { 14 | data: React.PropTypes.object.isRequired, 15 | id: React.PropTypes.string.isRequired 16 | }, 17 | shouldComponentUpdate(nextProps) { 18 | return commonReact.shouldComponentUpdate(this, nextProps); 19 | }, 20 | render: function () { 21 | const props = this.props, 22 | data = props.data; 23 | let plotComponent; 24 | 25 | if (data['image/png']) { 26 | plotComponent =
; 27 | } else if (data['image/svg']) { 28 | plotComponent =
; 29 | } else if (data['text/html']) { 30 | let frameId = 'frame-' + props.id; 31 | 32 | plotComponent = ; 33 | } else { 34 | plotComponent =
{'Plot must be png, svg, html or javascript.'}
; 35 | } 36 | 37 | return plotComponent; 38 | } 39 | }); 40 | -------------------------------------------------------------------------------- /src/browser/components/prompt/prompt.css: -------------------------------------------------------------------------------- 1 | .prompt { 2 | color: #999; 3 | display: block; 4 | white-space: pre-wrap; 5 | overflow: auto; 6 | background-color: #fff; 7 | font-family: monospace; 8 | font-size: 12px; 9 | position: relative; 10 | outline: none; 11 | } 12 | 13 | .prompt .prompt-line { 14 | position: relative; 15 | } 16 | 17 | .prompt--prompt, 18 | .prompt--continue { 19 | -webkit-user-select: none; 20 | -moz-user-select: none; 21 | -ms-user-select: none; 22 | -o-user-select: none; 23 | user-select: none; 24 | } 25 | 26 | .prompt__cursor { 27 | background-color: #ccc; 28 | color: transparent; 29 | display: inline; 30 | position: absolute; 31 | z-index: 0; 32 | } 33 | 34 | .prompt:focus { 35 | color: #333; 36 | outline: none; 37 | } 38 | 39 | .prompt:focus .prompt__cursor { 40 | background-color: #111; 41 | } 42 | 43 | .prompt__cursor--thinBlinking { 44 | width: 2px; 45 | } 46 | 47 | .prompt:focus .prompt__cursor--thinBlinking { 48 | animation-name: prompt__cursor__animation; 49 | animation-duration: 1s; 50 | animation-iteration-count: infinite; 51 | animation-timing-function: steps(1, start); 52 | } 53 | 54 | @keyframes prompt__cursor__animation { 55 | 0% { opacity: 1; } 56 | 50% { opacity: 0; } 57 | } 58 | -------------------------------------------------------------------------------- /src/browser/components/register-rodeo/areas-of-interest.yml: -------------------------------------------------------------------------------- 1 | label: Areas of Interest 2 | items: 3 | - label: Machine Learning 4 | name: interest.machine-learning 5 | - label: Linear Programming 6 | name: interest.linear-programming 7 | - label: Optimization 8 | name: interest.optimization 9 | - label: Neural Networks 10 | name: interest.neural-networks 11 | - label: Risk/Financial Modeling 12 | name: interest.risk-and-finiancial-modeling 13 | - label: Simulation 14 | name: interest.simulation 15 | - label: Cryptozoology 16 | name: interest.cryptozoology 17 | - label: Naval History 18 | name: interest.naval-history 19 | - label: Urban Exploring 20 | name: interest.urban-exploring 21 | 22 | -------------------------------------------------------------------------------- /src/browser/components/register-rodeo/explanation.md: -------------------------------------------------------------------------------- 1 | Let us recommend relevant blog posts, tutorials and other content! 2 | 3 | By letting us know what is relevant to you, we can 4 | create more content of that kind, and it will help prioritize new features for Rodeo. 5 | -------------------------------------------------------------------------------- /src/browser/components/search-text-box/search-text-box.css: -------------------------------------------------------------------------------- 1 | .search-text-box { 2 | border-radius: 8px; 3 | box-shadow: 1px 2px 5px 1px #aaa; 4 | white-space: nowrap; 5 | display: inline-block; 6 | margin: 0; 7 | padding: 0; 8 | height: 22px; 9 | } 10 | 11 | .search-text-box .search-text-box-icon { 12 | border-top-left-radius: 10px; 13 | border-bottom-left-radius: 10px; 14 | border: 0; 15 | display: inline-block; 16 | margin: 0; 17 | line-height: 16px; 18 | padding: 3px; 19 | padding-left: 6px; 20 | } 21 | 22 | .search-text-box input { 23 | border-top-right-radius: 10px; 24 | border-bottom-right-radius: 10px; 25 | border: 0; 26 | width: 30px; 27 | transition: width 0.4s; 28 | display: inline-block; 29 | margin: 0; 30 | line-height: 16px; 31 | padding: 3px; 32 | padding-right: 6px; 33 | vertical-align: top; 34 | } 35 | 36 | .search-text-box input:hover { 37 | width: 60px; 38 | } 39 | 40 | .search-text-box input:focus { 41 | width: 160px; 42 | } 43 | -------------------------------------------------------------------------------- /src/browser/components/search-text-box/search-text-box.jsx: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import React from 'react'; 3 | import './search-text-box.css'; 4 | import commonReact from '../../services/common-react'; 5 | 6 | /** 7 | * @class FilterTextBox 8 | * @extends ReactComponent 9 | * @property props 10 | */ 11 | export default React.createClass({ 12 | displayName: 'FilterTextBox', 13 | propTypes: { 14 | className: React.PropTypes.string, 15 | onChange: React.PropTypes.func, 16 | placeholder: React.PropTypes.string 17 | }, 18 | shouldComponentUpdate(nextProps) { 19 | return commonReact.shouldComponentUpdate(this, nextProps); 20 | }, 21 | handleFilterChange: _.debounce(function () { 22 | const value = this.refs.search.value; 23 | 24 | this.props.onChange(value); 25 | }, 300), 26 | render: function () { 27 | const className = ['search-text-box', this.props.className].join(' '); 28 | 29 | return ( 30 |
31 |
32 | 33 |
34 | 39 |
40 | ); 41 | } 42 | }); 43 | -------------------------------------------------------------------------------- /src/browser/components/setup/fake-terminal.css: -------------------------------------------------------------------------------- 1 | .fake-terminal { 2 | border: solid 1px #888; 3 | background-color: #FFF; 4 | display: block; 5 | white-space: pre-wrap; 6 | font-family: "Inconsolata","Inconsolata-dz", Monaco, Menlo, Consolas, "Courier New", monospace; 7 | font-size: 14px; 8 | color: #222; 9 | text-align: left; 10 | padding: 5px; 11 | overflow-x: visible; 12 | overflow-y: auto; 13 | box-shadow: inset 2px 2px 50px #acc, 2px 2px 10px #aaa; 14 | transition: all 0.6s; 15 | } 16 | 17 | .fake-terminal .prompt { 18 | padding-right: 10px; 19 | } 20 | 21 | .fake-terminal .errors { 22 | border-radius: 5px; 23 | margin-top: 5px; 24 | padding: 5px 10px; 25 | } 26 | 27 | .fake-terminal .errors .fa { 28 | margin-right: 10px; 29 | } 30 | 31 | .fake-terminal .stderr { 32 | background-color: transparent; 33 | color: #0062ff; 34 | } 35 | 36 | .fake-terminal .exit-code { 37 | background: linear-gradient(0deg, rgba(255, 130, 128, 0.5), rgba(255, 130, 128, 0.3) 30%, rgba(255, 255, 255, 0)); 38 | /* border-radius: 5px; */ 39 | padding: 5px 10px; 40 | margin: 10px -5px -5px; 41 | } 42 | -------------------------------------------------------------------------------- /src/browser/components/setup/logo-rodeo-grey-text.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/browser/components/setup/logo-rodeo-grey-text.sketch -------------------------------------------------------------------------------- /src/browser/components/setup/setup-article-preview.css: -------------------------------------------------------------------------------- 1 | .setup-article-preview { 2 | display: flex; 3 | align-items: center; 4 | justify-content: space-around; 5 | flex-wrap: wrap; 6 | text-align: left; 7 | width: 80%; 8 | margin: 20px auto; 9 | font-size: 14px; 10 | border: 1px solid #eee; 11 | padding: 20px 5px; 12 | box-shadow: 1px 5px 6px #aaa; 13 | cursor: pointer; 14 | } 15 | 16 | .setup-article-preview:hover { 17 | border: 1px solid #ccc; 18 | color: #333; 19 | } 20 | 21 | .setup-article-preview h2 { 22 | margin-top: 0; 23 | font-size: 16px; 24 | } 25 | 26 | .setup-article-preview a { 27 | color: #666; 28 | text-decoration: none; 29 | } 30 | 31 | .setup-article-preview a:hover { 32 | color: #666; 33 | text-decoration: none; 34 | } 35 | 36 | .setup-article-preview .setup-article { 37 | width: 600px; 38 | min-height: 150px; 39 | overflow: hidden; 40 | } 41 | 42 | .setup-article .setup-article-image { 43 | float: left; 44 | width: 40%; 45 | margin: 0 10px 20px; 46 | min-height: 120px; 47 | background-size: cover; 48 | background-position: center; 49 | } 50 | -------------------------------------------------------------------------------- /src/browser/components/setup/setup-article-preview.jsx: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import React from 'react'; 3 | import Marked from '../marked'; 4 | import './setup-article-preview.css'; 5 | import commonReact from '../../services/common-react'; 6 | 7 | export default React.createClass({ 8 | displayName: 'SetupArticlePreview', 9 | propTypes: { 10 | articles: React.PropTypes.array.isRequired, 11 | onOpenExternal: React.PropTypes.func.isRequired 12 | }, 13 | shouldComponentUpdate: function (nextProps) { 14 | return commonReact.shouldComponentUpdate(this, nextProps); 15 | }, 16 | render: function () { 17 | const props = this.props, 18 | className = commonReact.getClassNameList(this); 19 | 20 | return ( 21 |
22 |
23 | {_.map(props.articles, (article, index) => { 24 | const style = { 25 | backgroundImage: `url(${article.imageSrc})` 26 | }; 27 | 28 | return ( 29 | props.onOpenExternal(article.href)}> 30 | 31 |
{article.description}
32 |
33 | ); 34 | })} 35 |
36 |
37 | ); 38 | } 39 | }); 40 | -------------------------------------------------------------------------------- /src/browser/components/setup/setup-install-package.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import commonReact from '../../services/common-react'; 3 | import SetupInstallResultButtons from './setup-install-result-buttons.jsx'; 4 | 5 | export default React.createClass({ 6 | displayName: 'SetupInstallPackage', 7 | propTypes: { 8 | explanationLabel: React.PropTypes.string.isRequired, 9 | onCancel: React.PropTypes.func.isRequired, 10 | onPackageInstall: React.PropTypes.func.isRequired, 11 | packageName: React.PropTypes.string.isRequired, 12 | terminal: React.PropTypes.object.isRequired 13 | }, 14 | componentDidMount: function () { 15 | const props = this.props; 16 | 17 | props.onPackageInstall(props.packageName); 18 | }, 19 | shouldComponentUpdate: function (nextProps) { 20 | return commonReact.shouldComponentUpdate(this, nextProps); 21 | }, 22 | render: function () { 23 | const props = this.props, 24 | className = commonReact.getClassNameList(this); 25 | 26 | return ( 27 |
28 |
29 | 30 |
31 |
32 | ); 33 | } 34 | }); 35 | -------------------------------------------------------------------------------- /src/browser/components/setup/setup-manual-command.css: -------------------------------------------------------------------------------- 1 | .setup-manual-command .input-python-cmd input { 2 | padding-left: 5px; 3 | } 4 | -------------------------------------------------------------------------------- /src/browser/components/setup/setup-ready.jsx: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import React from 'react'; 3 | import commonReact from '../../services/common-react'; 4 | 5 | export default React.createClass({ 6 | displayName: 'SetupReady', 7 | propTypes: { 8 | className: React.PropTypes.string, 9 | onCancel: React.PropTypes.func.isRequired, 10 | onFinish: React.PropTypes.func.isRequired 11 | }, 12 | contextTypes: { 13 | text: React.PropTypes.object.isRequired 14 | }, 15 | shouldComponentUpdate: function (nextProps) { 16 | return commonReact.shouldComponentUpdate(this, nextProps); 17 | }, 18 | render: function () { 19 | const props = this.props, 20 | text = this.context.text, 21 | className = commonReact.getClassNameList(this); 22 | 23 | return ( 24 |
25 |
26 | 27 |
28 |
29 | ); 30 | } 31 | }); 32 | -------------------------------------------------------------------------------- /src/browser/components/setup/setup-skip-startup.css: -------------------------------------------------------------------------------- 1 | .setup-skip-startup { 2 | display: inline-block; 3 | position: absolute; 4 | right: 20px; 5 | bottom: 20px; 6 | opacity: 0; 7 | transition: opacity 0.5s; 8 | } 9 | 10 | .setup-skip-startup--visible { 11 | opacity: 0.4; 12 | } 13 | 14 | .setup-skip-startup--visible:hover { 15 | opacity: 1; 16 | } 17 | -------------------------------------------------------------------------------- /src/browser/components/setup/setup-skip-startup.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import commonReact from '../../services/common-react'; 3 | import './setup-skip-startup.css'; 4 | 5 | export default React.createClass({ 6 | displayName: 'SetupSkipStartup', 7 | propTypes: { 8 | onSkipStartup: React.PropTypes.func 9 | }, 10 | contextTypes: { 11 | text: React.PropTypes.object.isRequired 12 | }, 13 | shouldComponentUpdate: function (nextProps) { 14 | return commonReact.shouldComponentUpdate(this, nextProps); 15 | }, 16 | render: function () { 17 | const props = this.props, 18 | text = this.context.text, 19 | className = ['setup-skip-startup']; 20 | 21 | if (props.isMainWindowReady) { 22 | className.push('setup-skip-startup--visible'); 23 | } 24 | 25 | return ( 26 |
27 | 28 |
29 | ); 30 | } 31 | }); 32 | -------------------------------------------------------------------------------- /src/browser/components/sidebar/logo-scienceops.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/browser/components/sidebar/logo-scienceops.png -------------------------------------------------------------------------------- /src/browser/components/sidebar/logo-yhat.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/browser/components/sidebar/logo-yhat.sketch -------------------------------------------------------------------------------- /src/browser/components/sidebar/logo-yhat.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | logo-yhat 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | ŷ 11 | 12 | 13 | hat 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/browser/components/sidebar/sidebar-item.jsx: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import React from 'react'; 3 | import commonReact from '../../services/common-react'; 4 | 5 | /** 6 | * @class SidebarItem 7 | * @extends ReactComponent 8 | * @property props 9 | */ 10 | export default React.createClass({ 11 | displayName: 'SidebarItem', 12 | propTypes: { 13 | icon: React.PropTypes.string, 14 | id: React.PropTypes.string, 15 | label: React.PropTypes.string, 16 | onClick: React.PropTypes.func 17 | }, 18 | shouldComponentUpdate(nextProps) { 19 | return commonReact.shouldComponentUpdate(this, nextProps); 20 | }, 21 | render: function () { 22 | const props = this.props, 23 | className = commonReact.getClassNameList(this); 24 | 25 | return ( 26 |
{props.children}
27 | ); 28 | } 29 | }); 30 | -------------------------------------------------------------------------------- /src/browser/components/sidebar/sidebar.actions.js: -------------------------------------------------------------------------------- 1 | import track from '../../services/track'; 2 | 3 | export function showURL(url) { 4 | track({category: 'sidebar', action: 'show_url', label: url}); 5 | return {type: 'SHOW_URL_IN_SIDEBAR', url}; 6 | } 7 | 8 | export function openURL(url) { 9 | track({category: 'sidebar', action: 'open_url', label: url}); 10 | require('electron').shell.openExternal(url); 11 | return {type: 'OPEN_EXTERNAL_URL', url}; 12 | } 13 | 14 | export function hide() { 15 | track({category: 'sidebar', action: 'hide'}); 16 | return {type: 'HIDE_URL_IN_SIDEBAR'}; 17 | } 18 | 19 | export default { 20 | showURL, 21 | openURL, 22 | hide 23 | }; 24 | -------------------------------------------------------------------------------- /src/browser/components/sidebar/sidebar.css: -------------------------------------------------------------------------------- 1 | .sidebar { 2 | height: 100%; 3 | flex: 0 0 52px; 4 | font-size: 10px; 5 | } 6 | 7 | .sidebar-container { 8 | position: relative; 9 | display: flex; 10 | flex-direction: column; 11 | justify-content: flex-end; 12 | align-items: stretch; 13 | height: 100%; 14 | background-color: #337ab7; 15 | } 16 | 17 | .sidebar-top { 18 | flex: 1 0; 19 | display: flex; 20 | flex-direction: column; 21 | justify-content: flex-start; 22 | align-items: stretch; 23 | } 24 | 25 | .sidebar-item { 26 | cursor: pointer; 27 | flex: 0 0 60px; 28 | transition: all 0.4s; 29 | color: #efefef; 30 | padding: 4px; 31 | text-align: center; 32 | } 33 | 34 | .sidebar-top .sidebar-item { 35 | /* things in the top have bigger names but better images */ 36 | font-size: 8px; 37 | } 38 | 39 | .sidebar-item span:first-child { 40 | display: block; 41 | font-size: 28px; 42 | line-height: 28px; 43 | padding-top: 3px; 44 | } 45 | 46 | .sidebar-item img { 47 | max-width: 40px; 48 | max-height: 40px; 49 | } 50 | 51 | .sidebar-item:last-child { 52 | margin-bottom: 15px; 53 | } 54 | 55 | .sidebar-item:hover { 56 | cursor: pointer; 57 | background-color: #8DC8FB; 58 | } 59 | 60 | .sidebar-item:active { 61 | cursor: pointer; 62 | background-color: #D1EAFF; 63 | } 64 | -------------------------------------------------------------------------------- /src/browser/components/sidebar/sidebar.reducer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Modals work on a stack. A modal that triggers another modal is stacking on top, such that cancelling the top modal 4 | * returns to the first. 5 | * @module 6 | */ 7 | 8 | import _ from 'lodash'; 9 | import mapReducers from '../../services/map-reducers'; 10 | 11 | const initialState = { 12 | isExpanded: false 13 | }; 14 | 15 | /** 16 | * @param {Array} state 17 | * @param {object} action 18 | * @returns {Array} 19 | */ 20 | function showURL(state, action) { 21 | state = _.clone(state); 22 | 23 | if (!state.isExpanded) { 24 | state = _.clone(state); 25 | state.isExpanded = true; 26 | state.url = action.url; 27 | } else if (state.isExpanded && state.url !== action.url) { 28 | state = _.clone(state); 29 | state.url = action.url; 30 | } else if (state.isExpanded && state.url === action.url) { 31 | // close like a toggle 32 | state = _.clone(state); 33 | state.isExpanded = false; 34 | } 35 | 36 | return state; 37 | } 38 | 39 | /** 40 | * @param {Array} state 41 | * @returns {Array} 42 | */ 43 | function hide(state) { 44 | state = _.clone(state); 45 | state.isExpanded = false; 46 | 47 | return state; 48 | } 49 | 50 | export default mapReducers({ 51 | SHOW_URL_IN_SIDEBAR: showURL, 52 | HIDE_URL_IN_SIDEBAR: hide 53 | }, initialState); 54 | -------------------------------------------------------------------------------- /src/browser/components/sidebar/slideout-dialog.css: -------------------------------------------------------------------------------- 1 | .slideout-dialog { 2 | position: absolute; 3 | transition: all 0.4s; 4 | background-color: #337ab7; 5 | } 6 | 7 | .slideout-dialog iframe { 8 | width: 100%; 9 | height: 100%; 10 | padding: 10px 0 10px 10px; 11 | } 12 | 13 | .slideout-dialog.slideout-dialog-show { 14 | width: 500px; 15 | height: 100%; 16 | z-index: 9000; 17 | right: 0; 18 | margin-right: 52px; 19 | overflow: hidden; 20 | } 21 | -------------------------------------------------------------------------------- /src/browser/components/sidebar/slideout-dialog.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './slideout-dialog.css'; 3 | import commonReact from '../../services/common-react'; 4 | 5 | const showClass = 'slideout-dialog-show'; 6 | 7 | /** 8 | * @class SlideoutDialog 9 | * @extends ReactComponent 10 | * @property props 11 | */ 12 | export default React.createClass({ 13 | displayName: 'SlideoutDialog', 14 | propTypes: { 15 | isExpanded: React.PropTypes.bool, 16 | url: React.PropTypes.string 17 | }, 18 | shouldComponentUpdate(nextProps) { 19 | return commonReact.shouldComponentUpdate(this, nextProps); 20 | }, 21 | render: function () { 22 | const props = this.props, 23 | className = commonReact.getClassNameList(this); 24 | 25 | if (props.isExpanded) { 26 | className.push(showClass); 27 | } 28 | 29 | return ( 30 |
31 | 32 |
33 | ); 34 | } 35 | }); 36 | -------------------------------------------------------------------------------- /src/browser/components/tabbed-form-list-dialog/tabbed-form-list-dialog-tab.css: -------------------------------------------------------------------------------- 1 | .tabbed-form-list-dialog-tab { 2 | cursor: pointer; 3 | padding: 10px 15px; 4 | } 5 | 6 | .tabbed-form-list-dialog-tab:hover { 7 | background-color: #e1e1e1; 8 | } 9 | 10 | .tabbed-form-list-dialog-tab--disabled { 11 | background-color: inherit; 12 | color: grey; 13 | cursor: default; 14 | } 15 | 16 | .tabbed-form-list-dialog-tab--disabled:hover { 17 | background-color: inherit; 18 | } 19 | 20 | .tabbed-form-list-dialog-tab--active { 21 | background-color: #dff0ff; 22 | } 23 | -------------------------------------------------------------------------------- /src/browser/components/tabbed-form-list-dialog/tabbed-form-list-dialog-tab.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import commonReact from '../../services/common-react'; 3 | import './tabbed-form-list-dialog-tab.css'; 4 | 5 | export default React.createClass({ 6 | displayName: 'TabbedFormListDialogTab', 7 | propTypes: { 8 | active: React.PropTypes.bool, 9 | disabled: React.PropTypes.bool, 10 | id: React.PropTypes.string, 11 | label: React.PropTypes.string.isRequired, 12 | onClick: React.PropTypes.func 13 | }, 14 | contextTypes: { 15 | text: React.PropTypes.object.isRequired 16 | }, 17 | shouldComponentUpdate: function (nextProps) { 18 | return commonReact.shouldComponentUpdate(this, nextProps); 19 | }, 20 | render: function () { 21 | const props = this.props, 22 | text = this.context.text, 23 | className = commonReact.getClassNameList(this); 24 | 25 | if (props.active) { 26 | className.push('tabbed-form-list-dialog--active'); 27 | } 28 | 29 | if (props.disabled) { 30 | className.push('tabbed-form-list-dialog--disabled'); 31 | } 32 | 33 | return
{text[props.label]}
; 34 | } 35 | }); 36 | -------------------------------------------------------------------------------- /src/browser/components/tabbed-form-list-dialog/tabbed-form-list-dialog.css: -------------------------------------------------------------------------------- 1 | .tabbed-form-list-dialog { 2 | position: relative; 3 | min-height: 400px; 4 | height: 100%; 5 | } 6 | 7 | .tabbed-form-list-dialog > footer { 8 | bottom: 0; 9 | right: 0; 10 | padding: 7px 20px; 11 | height: 50px; 12 | text-align: right; 13 | position: relative; 14 | } 15 | 16 | .tabbed-form-list-dialog__content { 17 | position: relative; 18 | display: flex; 19 | flex-direction: row; 20 | align-content: stretch; 21 | align-items: stretch; 22 | height: calc(100% - 50px); 23 | } 24 | -------------------------------------------------------------------------------- /src/browser/components/tabs/closeable.css: -------------------------------------------------------------------------------- 1 | .closeable { 2 | margin-left: 6px; 3 | cursor: pointer; 4 | color: #cccccc; 5 | font-weight: 400; 6 | transition: all 0.4s; 7 | 8 | -webkit-touch-callout: none; /* iOS Safari */ 9 | -webkit-user-select: none; /* Chrome/Safari/Opera */ 10 | -moz-user-select: none; /* Firefox */ 11 | -ms-user-select: none; /* Internet Explorer/Edge */ 12 | user-select: none; /* Non-prefixed version, currently 13 | not supported by any browser */ 14 | } 15 | 16 | .closeable:hover { 17 | color: #cc4736; 18 | font-weight: 700; 19 | } 20 | -------------------------------------------------------------------------------- /src/browser/components/tabs/closeable.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import commonReact from '../../services/common-react'; 3 | import './closeable.css'; 4 | 5 | const closeTabClass = 'tabbed-pane-close'; 6 | 7 | export default React.createClass({ 8 | displayName: 'Closeable', 9 | propTypes: { 10 | className: React.PropTypes.string, 11 | onClick: React.PropTypes.func.isRequired 12 | }, 13 | shouldComponentUpdate(nextProps) { 14 | return commonReact.shouldComponentUpdate(this, nextProps); 15 | }, 16 | render: function () { 17 | const props = this.props, 18 | className = commonReact.getClassNameList(this).concat(['fa', 'fa-times', closeTabClass]); 19 | 20 | return ( 21 | 25 | ); 26 | } 27 | }); 28 | -------------------------------------------------------------------------------- /src/browser/components/tabs/tab-add.css: -------------------------------------------------------------------------------- 1 | .tab-add { 2 | padding: 6px 8px 0; 3 | } 4 | -------------------------------------------------------------------------------- /src/browser/components/tabs/tab-add.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import commonReact from '../../services/common-react'; 3 | import './tab-add.css'; 4 | 5 | export default React.createClass({ 6 | displayName: 'TabAdd', 7 | propTypes: { 8 | onClick: React.PropTypes.func.isRequired 9 | }, 10 | shouldComponentUpdate() { 11 | return false; 12 | }, 13 | render: function () { 14 | const props = this.props, 15 | className = commonReact.getClassNameList(this); 16 | 17 | 18 | return
  • 19 | 20 |
  • ; 21 | } 22 | }); 23 | -------------------------------------------------------------------------------- /src/browser/components/tabs/tab-button.css: -------------------------------------------------------------------------------- 1 | .tab-button button { 2 | white-space: nowrap; 3 | display: inline-block; 4 | height: 29px; 5 | background-color: white; 6 | padding: 1px 10px; 7 | border-style: hidden; 8 | color: #888; 9 | cursor: pointer; 10 | transition: all 0.2s; 11 | } 12 | 13 | .tab-button button:hover { 14 | color: #222 15 | } 16 | 17 | .tab-button button:active { 18 | color: #aaa 19 | } 20 | 21 | .tab-button .fa { 22 | margin-right: 5px; 23 | } 24 | -------------------------------------------------------------------------------- /src/browser/components/tabs/tab-button.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import React from 'react'; 3 | import commonReact from '../../services/common-react'; 4 | import './tab-button.css'; 5 | 6 | export default React.createClass({ 7 | displayName: 'TabButton', 8 | propTypes: { 9 | icon: React.PropTypes.string.isRequired, 10 | label: React.PropTypes.string.isRequired, 11 | onClick: React.PropTypes.func, // not required when disabled 12 | title: React.PropTypes.oneOfType([React.PropTypes.object, React.PropTypes.string]) 13 | }, 14 | shouldComponentUpdate(nextProps) { 15 | return commonReact.shouldComponentUpdate(this, nextProps); 16 | }, 17 | render: function () { 18 | const props = this.props, 19 | className = commonReact.getClassNameList(this), 20 | iconClassName = ['fa', 'fa-' + props.icon]; 21 | let title; 22 | 23 | if (props.title) { 24 | if (_.isObject(props.title) && props.title !== null) { 25 | title = props.title[process.platform] || props.title.default; 26 | } else if (_.isString(props.title)) { 27 | title = props.title; 28 | } 29 | } 30 | 31 | return ( 32 |
  • 33 | 37 |
  • 38 | ); 39 | } 40 | }); 41 | -------------------------------------------------------------------------------- /src/browser/components/tabs/tab-content-list.css: -------------------------------------------------------------------------------- 1 | .tab-content-list { 2 | flex: 1 1; 3 | overflow: hidden; /* allow individual components decide if they scroll / take the full space */ 4 | } 5 | 6 | -------------------------------------------------------------------------------- /src/browser/components/tabs/tab-item.css: -------------------------------------------------------------------------------- 1 | .tab-item { 2 | height: 24px; 3 | text-overflow: ellipsis; 4 | white-space: nowrap; 5 | min-width: 50px; 6 | padding: 6px 8px 0; 7 | border-bottom: 1px solid #dddddd; 8 | box-shadow: inset -1px -1px 2px #fff; 9 | cursor: pointer; 10 | transition: all 0.2s; 11 | position: relative; 12 | } 13 | 14 | .tab-item .tab-label { 15 | transition: all 0.2s; 16 | color: #888; 17 | } 18 | 19 | .tab-item.active .tab-label { 20 | transform: translate(0, -2px); 21 | color: #222; 22 | } 23 | 24 | .tab-item .lift { 25 | position: absolute; 26 | bottom: 0; 27 | left: 0; 28 | height: 0; 29 | width: 100%; 30 | transition: height 0.2s; 31 | background-color: #337ab7; 32 | } 33 | 34 | .tab-item.active .lift { 35 | height: 2px; 36 | } 37 | 38 | .tab-item, 39 | .tab-item * { 40 | -webkit-touch-callout: none; /* iOS Safari */ 41 | -webkit-user-select: none; /* Chrome/Safari/Opera */ 42 | -moz-user-select: none; /* Firefox */ 43 | -ms-user-select: none; /* Internet Explorer/Edge */ 44 | user-select: none; /* Non-prefixed version, currently 45 | not supported by any browser */ 46 | } 47 | -------------------------------------------------------------------------------- /src/browser/components/tabs/tab-list.css: -------------------------------------------------------------------------------- 1 | ul.tab-list { 2 | list-style: none; 3 | margin: 0; 4 | padding: 0; 5 | position: relative; 6 | flex: 0 0; 7 | border-bottom: 1px solid #dddddd; 8 | } 9 | 10 | ul.tab-list > li { 11 | display: inline-block; 12 | position: relative; 13 | min-height: 30px; 14 | vertical-align: top; 15 | } 16 | -------------------------------------------------------------------------------- /src/browser/components/tabs/tab-list.test.js: -------------------------------------------------------------------------------- 1 | /* globals describe, it, expect, jest */ 2 | 3 | import React from 'react'; 4 | import ReactDOM from 'react-dom'; 5 | import TestUtils from 'react-addons-test-utils'; 6 | import TabList from './tab-list.js'; 7 | 8 | describe(__filename, () => { 9 | it('renders', () => { 10 | const reactDocument = TestUtils.renderIntoDocument(), 11 | el = ReactDOM.findDOMNode(reactDocument); 12 | 13 | expect(el.className).toEqual('tab-list'); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/browser/components/tabs/tab-overflow-image.css: -------------------------------------------------------------------------------- 1 | /*noinspection CssOptimizeSimilarProperties*/ 2 | .tab-overflow-image a { 3 | background-size: auto 80%; 4 | background-repeat: no-repeat; 5 | background-position: center; 6 | display: block; 7 | width: 30px; 8 | height: 30px; 9 | } 10 | 11 | .tab-overflow-image:first-child { 12 | margin-left: 2px; 13 | } 14 | -------------------------------------------------------------------------------- /src/browser/components/tabs/tab-overflow-image.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import commonReact from '../../services/common-react'; 3 | import './tab-overflow-image.css'; 4 | 5 | export default React.createClass({ 6 | displayName: 'TabOverflowImage', 7 | propTypes: { 8 | onClick: React.PropTypes.func.isRequired, 9 | src: React.PropTypes.string.isRequired 10 | }, 11 | shouldComponentUpdate(nextProps) { 12 | return commonReact.shouldComponentUpdate(this, nextProps); 13 | }, 14 | render: function () { 15 | const props = this.props, 16 | className = commonReact.getClassNameList(this), 17 | style = { 18 | backgroundImage: 'url(' + props.src + ')' 19 | }; 20 | 21 | 22 | return ( 23 |
  • {' '}
  • 24 | ); 25 | } 26 | }); 27 | -------------------------------------------------------------------------------- /src/browser/components/tabs/tabbed-pane-item.css: -------------------------------------------------------------------------------- 1 | .tabbed-pane-item { 2 | display: none; 3 | overflow: hidden; 4 | } 5 | 6 | .tabbed-pane-item.active { 7 | display: block; 8 | height: 100%; 9 | } 10 | -------------------------------------------------------------------------------- /src/browser/components/tabs/tabbed-pane-item.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './tabbed-pane-item.css'; 3 | import commonReact from '../../services/common-react'; 4 | 5 | /** 6 | * @class TabbedPaneItem 7 | * @extends ReactComponent 8 | * @property props 9 | */ 10 | export default React.createClass({ 11 | displayName: 'TabbedPaneItem', 12 | propTypes: { 13 | active: React.PropTypes.bool, 14 | closeable: React.PropTypes.bool, 15 | icon: React.PropTypes.string, 16 | id: React.PropTypes.string, 17 | label: React.PropTypes.string.isRequired 18 | }, 19 | shouldComponentUpdate: function (nextProps) { 20 | return commonReact.shouldComponentUpdate(this, nextProps); 21 | }, 22 | render: function () { 23 | const props = this.props, 24 | className = commonReact.getClassNameList(this); 25 | 26 | if (props.active) { 27 | className.push('active'); 28 | } 29 | 30 | return
    {props.children}
    ; 31 | } 32 | }); 33 | -------------------------------------------------------------------------------- /src/browser/components/tabs/tabbed-pane.css: -------------------------------------------------------------------------------- 1 | .full-screen div.tabbed-pane { /* annoyingly specific over vsplitter */ 2 | display: flex; 3 | flex-direction: column; 4 | justify-content: flex-start; 5 | align-items: stretch; 6 | overflow: hidden; 7 | align-content: stretch; 8 | } 9 | 10 | .tabbed-pane .left { 11 | float: left; 12 | min-height: 30px; 13 | min-width: 20px; 14 | } 15 | 16 | .tabbed-pane .right { 17 | float: right; 18 | min-height: 30px; 19 | min-width: 20px; 20 | } 21 | 22 | .tabbed-pane .right .search-text-box { 23 | margin-top: 3px; 24 | margin-right: 10px; 25 | } 26 | 27 | .tabbed-pane .fa-before:before { 28 | padding-right: 6px; 29 | } 30 | 31 | .tab-content { 32 | flex: 1 1; 33 | position: relative; 34 | } 35 | 36 | /* override bootstrap... */ 37 | .tab-pane { 38 | display: block; 39 | top: 0; 40 | bottom: 0; 41 | left: 0; 42 | right: 0; 43 | position: absolute; 44 | overflow: auto; 45 | } 46 | 47 | -------------------------------------------------------------------------------- /src/browser/components/tree-view/tree-view.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import commonReact from '../../services/common-react'; 3 | import TreeViewItem from './tree-view-item'; 4 | import './tree-view.css'; 5 | 6 | export default React.createClass({ 7 | displayName: 'TreeView', 8 | shouldComponentUpdate: function (nextProps) { 9 | return commonReact.shouldComponentUpdate(this, nextProps); 10 | }, 11 | propsTypes: { 12 | height: React.PropTypes.number, 13 | items: React.PropTypes.array.isRequired, 14 | width: React.PropTypes.number 15 | }, 16 | render: function () { 17 | const props = this.props, 18 | className = commonReact.getClassNameList(this); 19 | 20 | return ; 21 | } 22 | }); 23 | -------------------------------------------------------------------------------- /src/browser/components/unsafe-html.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import commonReact from '../services/common-react'; 4 | 5 | export default React.createClass({ 6 | displayName: 'UnsafeHTML', 7 | propTypes: { 8 | id: React.PropTypes.string.isRequired, 9 | onLoad: React.PropTypes.func, 10 | src: React.PropTypes.string.isRequired 11 | }, 12 | componentDidMount: function () { 13 | const el = ReactDOM.findDOMNode(this); 14 | 15 | if (el) { 16 | el.setAttribute('src', this.props.src); 17 | } 18 | }, 19 | shouldComponentUpdate(nextProps, nextState) { 20 | return commonReact.shouldComponentUpdate(this, nextProps, nextState); 21 | }, 22 | render: function () { 23 | const props = this.props, 24 | className = commonReact.getClassNameList(this); 25 | 26 | return ( 27 | 34 | ); 35 | } 36 | }); 37 | -------------------------------------------------------------------------------- /src/browser/components/unsafe-html.test.js: -------------------------------------------------------------------------------- 1 | /* globals describe, it, expect */ 2 | 3 | import React from 'react'; 4 | import ReactDOM from 'react-dom'; 5 | import TestUtils from 'react-addons-test-utils'; 6 | import UnsafeHtml from './unsafe-html.js'; 7 | 8 | describe(__filename, () => { 9 | it('renders html', () => { 10 | const reactDocument = TestUtils.renderIntoDocument(), 11 | el = ReactDOM.findDOMNode(reactDocument); 12 | 13 | expect(el.src).toEqual('abc'); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/browser/components/variable-viewer/variable-table.css: -------------------------------------------------------------------------------- 1 | .variable-table { 2 | height: 100%; 3 | } 4 | 5 | .variable-table .public_fixedDataTableCell_cellContent { 6 | white-space: nowrap; 7 | } 8 | 9 | .variable-table .public_fixedDataTableCell_wrap1 { 10 | width: 100%; 11 | } 12 | -------------------------------------------------------------------------------- /src/browser/components/variable-viewer/variable-viewer.jsx: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import React from 'react'; 3 | import commonReact from '../../services/common-react'; 4 | import EmptySuggestion from '../empty/empty-suggestion'; 5 | import VariableTable from './variable-table.jsx'; 6 | 7 | /** 8 | * @class PackagesViewer 9 | * @extends ReactComponent 10 | * @property {object} state 11 | * @property {object} props 12 | */ 13 | export default React.createClass({ 14 | displayName: 'VariableViewer', 15 | propTypes: { 16 | filter: React.PropTypes.string, 17 | onShowDataFrame: React.PropTypes.func.isRequired, 18 | variables: React.PropTypes.object, 19 | visible: React.PropTypes.bool.isRequired 20 | }, 21 | shouldComponentUpdate: function (nextProps, nextState) { 22 | return commonReact.shouldComponentUpdate(this, nextProps, nextState); 23 | }, 24 | render: function () { 25 | const props = this.props; 26 | let content; 27 | 28 | if (props.variables && _.some(props.variables, variable => variable.length > 0)) { 29 | content = ; 30 | } else { 31 | content = ; 32 | } 33 | 34 | return content; 35 | } 36 | }); 37 | -------------------------------------------------------------------------------- /src/browser/components/yhat.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {send} from 'ipc'; 3 | import commonReact from '../services/common-react'; 4 | 5 | export default React.createClass({ 6 | displayName: 'Yhat', 7 | shouldComponentUpdate(nextProps, nextState) { 8 | return commonReact.shouldComponentUpdate(this, nextProps, nextState); 9 | }, 10 | handleYhat: () => send('openExternal', 'http://yhat.com/').catch(error => console.error(error)), 11 | render: function () { 12 | return ( 13 | 14 | {'ŷ'} 15 | {'hat'} 16 | 17 | ); 18 | } 19 | }); 20 | -------------------------------------------------------------------------------- /src/browser/containers/ask-quit-dialog-viewer/ask-quit-dialog-viewer.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import commonReact from '../../services/common-react'; 3 | import {connect} from 'react-redux'; 4 | import AskQuit from '../../components/dialogs/ask-quit'; 5 | import selectors from './ask-quit-dialog-viewer.selectors'; 6 | import applicationActions from '../../actions/application'; 7 | import actions from '../../actions/preferences'; 8 | 9 | /** 10 | * @param {function} dispatch 11 | * @returns {object} 12 | */ 13 | function mapDispatchToProps(dispatch) { 14 | return { 15 | onAskQuitChange: changes => dispatch(actions.savePreferenceChanges(changes)), 16 | onQuit: () => dispatch(applicationActions.quit()) 17 | }; 18 | } 19 | 20 | export default connect(selectors.getAskQuit, mapDispatchToProps)(React.createClass({ 21 | displayName: 'AskQuitDialogViewer', 22 | propTypes: { 23 | onCancel: React.PropTypes.func.isRequired 24 | }, 25 | shouldComponentUpdate(nextProps) { 26 | return commonReact.shouldComponentUpdate(this, nextProps); 27 | }, 28 | handleAskQuitChange(event) { 29 | const props = this.props, 30 | oldValue = props.askQuit, 31 | value = event.target.checked; 32 | 33 | if (oldValue !== value) { 34 | props.onAskQuitChange([{key: 'askQuit', value}]); 35 | } 36 | }, 37 | render() { 38 | return ; 39 | } 40 | })); 41 | -------------------------------------------------------------------------------- /src/browser/containers/ask-quit-dialog-viewer/ask-quit-dialog-viewer.reducer.js: -------------------------------------------------------------------------------- 1 | import Immutable from 'seamless-immutable'; 2 | import mapReducers from '../../services/map-reducers'; 3 | import {local} from '../../services/store'; 4 | 5 | export function getInitialState() { 6 | 7 | return Immutable({ 8 | askQuit: local.get('askQuit') || true 9 | }); 10 | } 11 | 12 | function quiting(state) { 13 | return state.set('state', 'quiting'); 14 | } 15 | 16 | function quit(state) { 17 | return state.set('state', 'quit'); 18 | } 19 | 20 | function changeSaved(state, action) { 21 | const key = action.change.key; 22 | 23 | if (key === 'askQuit') { 24 | state = state.set('askQuit', action.change.value); 25 | } 26 | 27 | return state; 28 | } 29 | 30 | export default mapReducers({ 31 | QUITING: quiting, 32 | QUIT: quit, 33 | PREFERENCE_CHANGE_SAVED: changeSaved 34 | }, {}); 35 | -------------------------------------------------------------------------------- /src/browser/containers/ask-quit-dialog-viewer/ask-quit-dialog-viewer.selectors.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import {createSelector} from 'reselect'; 3 | 4 | const contentType = 'askQuit', 5 | modalDialogs = state => state.modalDialogs, 6 | getAskQuit = createSelector( 7 | modalDialogs, 8 | modalDialogs => { 9 | const dialog = _.isObject(modalDialogs) && _.find(modalDialogs.items, {contentType}); 10 | 11 | return dialog && dialog.content; 12 | } 13 | ); 14 | 15 | export default { 16 | getAskQuit 17 | }; 18 | -------------------------------------------------------------------------------- /src/browser/containers/block-terminal-viewer/block-terminal-viewer.css: -------------------------------------------------------------------------------- 1 | .block-terminal-viewer { 2 | position: relative; 3 | height: 100%; 4 | display: flex; 5 | flex-direction: column; 6 | align-items: stretch; 7 | align-content: stretch; 8 | } 9 | 10 | .block-terminal-viewer .block-history { 11 | flex-grow: 5; 12 | overflow-y: auto; 13 | } 14 | 15 | .block-terminal-viewer .prompt { 16 | flex-grow: 0; 17 | flex-shrink: 0; 18 | } 19 | -------------------------------------------------------------------------------- /src/browser/containers/document-terminal-viewer/document-terminal-viewer.css: -------------------------------------------------------------------------------- 1 | .document-terminal-viewer { 2 | height: 100%; 3 | position: relative; 4 | } 5 | 6 | .document-terminal-viewer .document-terminal { 7 | height: calc(100% - 20px); 8 | } 9 | 10 | .document-terminal-viewer .gray-info { 11 | height: 20px; 12 | } 13 | 14 | .document-terminal-viewer .prompt { 15 | margin-left: 10px; 16 | margin-right: 10px; 17 | color: #666; 18 | background-color: inherit; 19 | font-family: inherit; 20 | font-size: inherit; 21 | transition: color 1s; 22 | } 23 | 24 | .document-terminal-viewer .empty-suggestion.empty-suggestion--visible { 25 | opacity: 1; 26 | } 27 | 28 | .document-terminal-viewer .empty-suggestion { 29 | position: absolute; 30 | width: 100%; 31 | opacity: 0; 32 | transition: opacity 0.5s; 33 | top: 0; 34 | z-index: -1; 35 | } 36 | 37 | -------------------------------------------------------------------------------- /src/browser/containers/document-terminal-viewer/features.yml: -------------------------------------------------------------------------------- 1 | - onClick: onClear 2 | icon: trash 3 | label: Clear 4 | title: Ctrl + L 5 | keyboardShortcuts: 6 | - key: l 7 | alt: false 8 | meta: false 9 | shift: false 10 | ctrl: true 11 | selection: false 12 | - key: k 13 | alt: false 14 | meta: false 15 | shift: false 16 | ctrl: true 17 | selection: false 18 | - key: l 19 | alt: false 20 | meta: false 21 | shift: false 22 | ctrl: true 23 | selection: true 24 | - key: k 25 | alt: false 26 | meta: false 27 | shift: false 28 | ctrl: true 29 | selection: true 30 | - onClick: onInterrupt 31 | icon: stop 32 | label: Interrupt 33 | title: Ctrl + C 34 | whenBusy: true 35 | keyboardShortcuts: 36 | - key: c 37 | alt: false 38 | meta: false 39 | shift: false 40 | ctrl: true 41 | selection: false 42 | - onClick: onRestart 43 | icon: refresh 44 | label: Restart 45 | title: "⌘ + R" 46 | keyboardShortcuts: 47 | - key: r 48 | alt: false 49 | meta: true 50 | shift: false 51 | ctrl: false 52 | selection: false 53 | -------------------------------------------------------------------------------- /src/browser/containers/editor-tab-group/editor-commands.yml: -------------------------------------------------------------------------------- 1 | - name: executeFile 2 | bindKey: 3 | win: shift-ctrl-Enter 4 | mac: Shift-Command-Enter 5 | 6 | - name: executeSelection 7 | scrollIntoView: animate 8 | bindKey: 9 | win: ctrl-Enter 10 | mac: Command-Enter 11 | 12 | - name: selectJupyterBlock 13 | scrollIntoView: animate 14 | bindKey: 15 | win: ctrl-Enter 16 | mac: Command-Enter 17 | 18 | - name: interrupt 19 | bindKey: 20 | win: ctrl-shift-c 21 | mac: ctrl-c 22 | 23 | - name: blockindent 24 | bindKey: 25 | win: ctrl-\] 26 | mac: Command-\] 27 | 28 | - name: blockoutdent 29 | bindKey: 30 | win: ctrl-\[|Shift-Tab 31 | mac: Command-\[|Shift-Tab 32 | 33 | - name: openPreferences 34 | bindKey: 35 | win: ctrl-, 36 | mac: Command-, 37 | 38 | - name: autocomplete 39 | scrollIntoView: animate 40 | bindKey: 41 | win: Tab 42 | mac: Tab 43 | -------------------------------------------------------------------------------- /src/browser/containers/editor-tab-group/editor-tab-group.css: -------------------------------------------------------------------------------- 1 | .tab-content-list .ace-pane { 2 | /* temporary until moved into own component */ 3 | height: calc(100% - 20px); 4 | } 5 | -------------------------------------------------------------------------------- /src/browser/containers/editor-tab-group/initial-story.py: -------------------------------------------------------------------------------- 1 | # Press CTRL + ENTER to run a single line in the console 2 | print('Welcome to Rodeo!') 3 | 4 | # Press CTRL + ENTER with text selected to run multiple lines 5 | # For example, select the following lines 6 | x = 7 7 | x**2 8 | # and remember to press CTRL + ENTER 9 | 10 | # Here is an example of using Rodeo: 11 | 12 | # Install packages 13 | 14 | ! pip install pandas 15 | ! pip install numpy 16 | 17 | # Import packages 18 | 19 | import numpy as np 20 | import pandas as pd 21 | 22 | N = 100 23 | df = pd.DataFrame({ 24 | 'A': pd.date_range(start='2016-01-01',periods=N,freq='D'), 25 | 'x': np.linspace(0,stop=N-1,num=N), 26 | 'y': np.random.rand(N), 27 | 'C': np.random.choice(['Low','Medium','High'],N).tolist(), 28 | 'D': np.random.normal(100, 10, size=(N)).tolist() 29 | }) 30 | df.head() 31 | 32 | # Another example of making a plot: 33 | 34 | from matplotlib import pyplot as plt 35 | x=df.x 36 | with plt.style.context('fivethirtyeight'): 37 | plt.plot(x, np.sin(x*5) + x + np.random.randn(N)*15) 38 | plt.plot(x, np.sin(x*5) + 0.5 * x + np.random.randn(N)*5) 39 | plt.plot(x, np.sin(x) + 2 * x + np.random.randn(N)*20) 40 | 41 | plt.title('Random lines') 42 | plt.show() 43 | -------------------------------------------------------------------------------- /src/browser/containers/editor-tab-group/rodeo-logo/rodeo-logo.1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/browser/containers/editor-tab-group/rodeo-logo/rodeo-logo.1x.png -------------------------------------------------------------------------------- /src/browser/containers/editor-tab-group/rodeo-logo/rodeo-logo.2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/browser/containers/editor-tab-group/rodeo-logo/rodeo-logo.2x.png -------------------------------------------------------------------------------- /src/browser/containers/editor-tab-group/rodeo-logo/rodeo-logo.4x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/browser/containers/editor-tab-group/rodeo-logo/rodeo-logo.4x.png -------------------------------------------------------------------------------- /src/browser/containers/environment-variables-dialog-viewer/environment-variables-dialog-viewer.actions.js: -------------------------------------------------------------------------------- 1 | import reduxUtil from '../../services/redux-util'; 2 | 3 | const prefix = reduxUtil.fromFilenameToPrefix(__filename); 4 | 5 | function cancelChanges() { 6 | return {type: prefix + 'CANCEL_CHANGES'}; 7 | } 8 | 9 | function saveChanges() { 10 | return {type: prefix + 'SAVE_CHANGES'}; 11 | } 12 | 13 | function startEdit(item, container) { 14 | return {type: prefix + 'START_EDIT', payload: {item, container}}; 15 | } 16 | 17 | function saveEdit(payload) { 18 | return {type: prefix + 'SAVE_EDIT', payload}; 19 | } 20 | 21 | function cancelEdit(payload) { 22 | return {type: prefix + 'CANCEL_EDIT', payload}; 23 | } 24 | 25 | function changeEditValue(item, target, value) { 26 | return {type: prefix + 'CHANGE_EDIT_VALUE', payload: {item, target, value}}; 27 | } 28 | 29 | function reload() { 30 | return {type: prefix + 'RELOAD'}; 31 | } 32 | 33 | function removeKey(item, key) { 34 | return {type: prefix + 'REMOVE_KEY', payload: {item, key}}; 35 | } 36 | 37 | export default { 38 | cancelChanges, 39 | saveChanges, 40 | startEdit, 41 | saveEdit, 42 | cancelEdit, 43 | changeEditValue, 44 | reload, 45 | removeKey 46 | }; 47 | -------------------------------------------------------------------------------- /src/browser/containers/environment-variables-dialog-viewer/environment-variables-dialog-viewer.css: -------------------------------------------------------------------------------- 1 | /* environment variables from the system */ 2 | .input-list__item--system { 3 | background-color: #eff9ff; 4 | color: #666; 5 | } 6 | 7 | .input-key-value-list__item--system { 8 | background-color: #eff9ff; 9 | color: #666; 10 | } 11 | -------------------------------------------------------------------------------- /src/browser/containers/environment-variables-dialog-viewer/environment-variables-dialog-viewer.selectors.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import {createSelector} from 'reselect'; 3 | 4 | const contentType = 'environmentVariables', 5 | modalDialogs = state => state.modalDialogs, 6 | getEnvironmentVariablesViewer = createSelector( 7 | modalDialogs, 8 | modalDialogs => { 9 | const dialog = _.isObject(modalDialogs) && _.find(modalDialogs.items, {contentType}); 10 | 11 | return dialog && dialog.content; 12 | } 13 | ); 14 | 15 | export default { 16 | getEnvironmentVariablesViewer 17 | }; 18 | -------------------------------------------------------------------------------- /src/browser/containers/environment-variables-dialog-viewer/layout.yml: -------------------------------------------------------------------------------- 1 | # id: some unique value 2 | # label: key in the i18n text 3 | - 4 | id: environmentVariableExplanation 5 | explanation: environmentVariableExplanation 6 | type: marked 7 | 8 | - 9 | id: environmentVariablePath 10 | key: environmentVariablePath 11 | label: environmentVariablePathExplanation 12 | type: list 13 | listColumnLabel: environmentVariablePath 14 | 15 | - 16 | id: environmentVariablePythonPath 17 | key: environmentVariablePythonPath 18 | label: environmentVariablePythonPathExplanation 19 | type: list 20 | listColumnLabel: environmentVariablePythonPath 21 | 22 | - 23 | id: remainingEnvironmentVariables 24 | key: remainingEnvironmentVariables 25 | label: editingEnvironmentVariableExplanation 26 | type: keyValueList 27 | -------------------------------------------------------------------------------- /src/browser/containers/free-tabs-only.reducer.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux'; 2 | import applicationControl from '../services/application-control'; 3 | import freeTabGroups from './free-tab-group/free-tab-group.reducer'; 4 | 5 | function broadcast(state, action) { 6 | applicationControl.shareAction(action); 7 | 8 | if (!state) { 9 | return {}; 10 | } 11 | 12 | return state; 13 | } 14 | 15 | export default combineReducers({ 16 | freeTabGroups, 17 | broadcast 18 | }); 19 | -------------------------------------------------------------------------------- /src/browser/containers/global-history-viewer/global-history-viewer.css: -------------------------------------------------------------------------------- 1 | .global-history-viewer { 2 | overflow: auto; 3 | height: 100%; 4 | } 5 | -------------------------------------------------------------------------------- /src/browser/containers/history-viewer/history-viewer.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import commonReact from '../../services/common-react'; 3 | import BlockHistory from '../../components/block-history/block-history'; 4 | 5 | export default React.createClass({ 6 | displayName: 'HistoryViewer', 7 | shouldComponentUpdate: function (nextProps) { 8 | return commonReact.shouldComponentUpdate(this, nextProps); 9 | }, 10 | render: function () { 11 | return ; 12 | } 13 | }); 14 | -------------------------------------------------------------------------------- /src/browser/containers/manage-connections-viewer/definitions.yml: -------------------------------------------------------------------------------- 1 | defaultType: postgresql 2 | types: 3 | - 4 | name: postgresql 5 | label: Postgresql 6 | knownConfigurationOptions: 7 | host: string 8 | port: number 9 | database: string 10 | username: string 11 | password: string 12 | defaults: 13 | host: localhost 14 | port: 5432 15 | database: postgres 16 | username: postgres 17 | password: mysecretpassword 18 | - 19 | name: redshift 20 | label: Redshift 21 | defaults: {} 22 | - 23 | name: sqlserver 24 | label: SqlServer 25 | defaults: {} 26 | - 27 | name: mysql 28 | label: MySql 29 | defaults: {} 30 | -------------------------------------------------------------------------------- /src/browser/containers/manage-connections-viewer/manage-connections-viewer.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {connect} from 'react-redux'; 3 | import ManageConnections from '../../components/manage-connections/manage-connections'; 4 | import actions from './manage-connections.actions'; 5 | import definitions from './definitions.yml'; 6 | import selectors from './manage-connections.selectors'; 7 | 8 | /** 9 | * @param {function} dispatch 10 | * @returns {object} 11 | */ 12 | function mapDispatchToProps(dispatch) { 13 | return { 14 | onCancel: id => dispatch(actions.cancel(id)), 15 | onOK: (id, result) => dispatch(actions.ok(id, result)), 16 | onAddConnection: () => dispatch(actions.addConnection()), 17 | onConnect: id => dispatch(actions.connect(id)), 18 | onDisconnect: id => dispatch(actions.disconnect(id)), 19 | onRemoveConnection: id => dispatch(actions.removeConnection(id)), 20 | onChange: change => dispatch(actions.addChange(change)), 21 | onSelectConnection: id => dispatch(actions.selectConnection(id)) 22 | }; 23 | } 24 | 25 | export default connect(selectors.getConnectionsViewer, mapDispatchToProps)(React.createClass({ 26 | displayName: 'ManageConnectionsViewer', 27 | render: function () { 28 | return ; 29 | } 30 | })); 31 | -------------------------------------------------------------------------------- /src/browser/containers/manage-connections-viewer/manage-connections.selectors.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import {createSelector} from 'reselect'; 3 | 4 | const contentType = 'manageConnections', 5 | modalDialogs = state => state.modalDialogs, 6 | getConnectionsViewer = createSelector( 7 | modalDialogs, 8 | modalDialogs => { 9 | const dialog = _.isObject(modalDialogs) && _.find(modalDialogs.items, {contentType}); 10 | 11 | return dialog && dialog.content; 12 | } 13 | ); 14 | 15 | export default { 16 | getConnectionsViewer 17 | }; 18 | -------------------------------------------------------------------------------- /src/browser/containers/modal-dialog-viewer/modal-dialog-viewer.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {connect} from 'react-redux'; 3 | import ModalDialogContainer from '../../components/dialogs/modal-dialog-container'; 4 | import actions from './modal-dialog.actions'; 5 | import commonReact from '../../services/common-react'; 6 | 7 | function mapStateToProps(state) { 8 | return state.modalDialogs; 9 | } 10 | 11 | /** 12 | * @param {function} dispatch 13 | * @returns {object} 14 | */ 15 | function mapDispatchToProps(dispatch) { 16 | return { 17 | onCancel: id => dispatch(actions.cancel(id)), 18 | onCancelAll: () => dispatch(actions.cancelAll()), 19 | onOK: (id, result) => dispatch(actions.ok(id, result)), 20 | onRegister: () => dispatch(actions.register()) 21 | }; 22 | } 23 | 24 | export default connect(mapStateToProps, mapDispatchToProps)(React.createClass({ 25 | displayName: 'ModalDialogViewer', 26 | shouldComponentUpdate(nextProps) { 27 | return commonReact.shouldComponentUpdate(this, nextProps); 28 | }, 29 | render: function () { 30 | return ; 31 | } 32 | })); 33 | -------------------------------------------------------------------------------- /src/browser/containers/modal-dialog-viewer/modal-dialog.actions.js: -------------------------------------------------------------------------------- 1 | function add(contentType) { 2 | return {type: 'ADD_MODAL_DIALOG', payload: {contentType}, meta: {sender: 'self', track: true}}; 3 | } 4 | 5 | function ok(id, result) { 6 | return {type: 'OK_MODAL_DIALOG', payload: {id, result}, meta: {sender: 'self'}}; 7 | } 8 | 9 | function cancel(id) { 10 | return {type: 'CANCEL_MODAL_DIALOG', payload: {id}, meta: {sender: 'self'}}; 11 | } 12 | 13 | function cancelAll() { 14 | return {type: 'CANCEL_ALL_MODAL_DIALOGS', meta: {sender: 'self'}}; 15 | } 16 | 17 | export default { 18 | add, 19 | ok, 20 | cancel, 21 | cancelAll 22 | }; 23 | -------------------------------------------------------------------------------- /src/browser/containers/package-search-viewer/package-search-viewer.jsx: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import React from 'react'; 3 | import PackageSearchList from '../../components/packages/package-search-list.jsx'; 4 | 5 | export default React.createClass({ 6 | displayName: 'PackageSearchViewer', 7 | render: function () { 8 | return ; 9 | } 10 | }); 11 | -------------------------------------------------------------------------------- /src/browser/containers/plot-viewer/plot-viewer.actions.js: -------------------------------------------------------------------------------- 1 | import reduxUtil from '../../services/redux-util'; 2 | 3 | const prefix = reduxUtil.fromFilenameToPrefix(__filename); 4 | 5 | function focus(groupId, id, plot) { 6 | return {type: prefix + 'FOCUS_PLOT', groupId, id, plot}; 7 | } 8 | 9 | function remove(groupId, id, plot) { 10 | return {type: prefix + 'REMOVE_PLOT', groupId, id, plot}; 11 | } 12 | 13 | export default { 14 | focus, 15 | remove 16 | }; 17 | -------------------------------------------------------------------------------- /src/browser/containers/plot-viewer/plot-viewer.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PlotPreview from '../../components/plot-preview/plot-preview.jsx'; 3 | import commonReact from '../../services/common-react'; 4 | 5 | /** 6 | * @class PlotViewer 7 | * @extends ReactComponent 8 | * @property props 9 | * @property {Array} props.plots 10 | */ 11 | export default React.createClass({ 12 | displayName: 'PlotViewer', 13 | shouldComponentUpdate: function (nextProps) { 14 | return commonReact.shouldComponentUpdate(this, nextProps); 15 | }, 16 | render: function () { 17 | return ; 18 | } 19 | }); 20 | -------------------------------------------------------------------------------- /src/browser/containers/preferences-viewer/preferences-viewer.selectors.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import {createSelector} from 'reselect'; 3 | 4 | const contentType = 'preferences', 5 | modalDialogs = state => state.modalDialogs, 6 | getPreferencesViewer = createSelector( 7 | modalDialogs, 8 | modalDialogs => { 9 | const dialog = _.isObject(modalDialogs) && _.find(modalDialogs.items, {contentType}); 10 | 11 | return dialog && dialog.content; 12 | } 13 | ); 14 | 15 | export default { 16 | getPreferencesViewer 17 | }; 18 | -------------------------------------------------------------------------------- /src/browser/containers/prompt-viewer/prompt-viewer.actions.js: -------------------------------------------------------------------------------- 1 | import reduxUtil from '../../services/redux-util'; 2 | 3 | // Don't share with other windows 4 | // Setting this means these actions will not be broadcast 5 | const sender = 'self', 6 | prefixType = reduxUtil.fromFilenameToPrefix(__filename); 7 | 8 | function autocomplete(groupId, id, payload) { 9 | return {type: prefixType + 'AUTOCOMPLETE', groupId, id, payload, meta: {sender}}; 10 | } 11 | 12 | function createCommand(groupId, id, payload) { 13 | return {type: prefixType + 'COMMAND', groupId, id, payload, meta: {sender}}; 14 | } 15 | 16 | function copyToPrompt(groupId, id, payload) { 17 | return {type: prefixType + 'COPY_TO_PROMPT', groupId, id, payload, meta: {sender}}; 18 | } 19 | 20 | export default { 21 | autocomplete, 22 | createCommand, 23 | copyToPrompt 24 | }; 25 | -------------------------------------------------------------------------------- /src/browser/containers/prompt-viewer/prompt-viewer.reducer.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import mapReducers from '../../services/map-reducers'; 3 | import promptActions from '../../services/prompt-actions'; 4 | import reduxUtil from '../../services/redux-util'; 5 | 6 | const prefixType = reduxUtil.fromFilenameToPrefix(__filename); 7 | 8 | function command(state, action) { 9 | const payload = action.payload, 10 | name = payload.name; 11 | 12 | if (promptActions[name]) { 13 | state = promptActions[name](state, payload); 14 | } 15 | 16 | return state; 17 | } 18 | 19 | function copyToPrompt(state, action) { 20 | const payload = action.payload, 21 | lines = payload.lines; 22 | 23 | // put lines 24 | return _.assign({}, state, { 25 | lines, 26 | cursor: {row: lines.length - 1, column: _.last(lines).length}, 27 | historyIndex: -1 28 | }); 29 | } 30 | 31 | function autocomplete(state, action) { 32 | const suggestions = action.payload; 33 | 34 | console.log(suggestions); 35 | 36 | return state; 37 | } 38 | 39 | export default mapReducers(reduxUtil.addPrefixToKeys(prefixType, { 40 | AUTOCOMPLETE: autocomplete, 41 | COPY_TO_PROMPT: copyToPrompt, 42 | COMMAND: command 43 | }), {}); 44 | -------------------------------------------------------------------------------- /src/browser/containers/setup-viewer/articles.yml: -------------------------------------------------------------------------------- 1 | %YAML 1.2 2 | --- 3 | - 4 | href: http://blog.yhat.com/posts/moving-from-r-to-python.html 5 | imageSrc: http://blog.yhat.com/static/img/r-to-python.jpg 6 | description: | 7 | ## Moving from R to Python: The Libraries You Need to Know 8 | 9 | Migrating from R to Python? Make sure you know about these packages. 10 | -------------------------------------------------------------------------------- /src/browser/containers/setup-viewer/setup-viewer.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {connect} from 'react-redux'; 3 | import Setup from '../../components/setup/setup.jsx'; 4 | import actions from './setup-viewer.actions'; 5 | import articles from './articles.yml'; 6 | 7 | function mapStateToProps(state) { 8 | return state.setup; 9 | } 10 | 11 | function mapDispatchToProps(dispatch) { 12 | return { 13 | onCancel: () => dispatch(actions.cancel()), 14 | onExecute: () => dispatch(actions.execute()), 15 | onFinish: () => dispatch(actions.finish()), 16 | onInputChange: (key, event) => dispatch(actions.changeInput(key, event)), 17 | onOpenExternal: url => dispatch(actions.openExternal(url)), 18 | onPackageInstall: targetPackage => dispatch(actions.installPackage(targetPackage)), 19 | onRestart: () => dispatch(actions.restart()), 20 | onSkipStartup: () => dispatch(actions.skipStartup()), 21 | onTransition: contentType => dispatch(actions.transition(contentType)) 22 | }; 23 | } 24 | 25 | export default connect(mapStateToProps, mapDispatchToProps)(React.createClass({ 26 | displayName: 'SetupViewer', 27 | render: function () { 28 | return ; 29 | } 30 | })); 31 | -------------------------------------------------------------------------------- /src/browser/containers/startup.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import SetupViewer from './setup-viewer/setup-viewer.jsx'; 3 | import {Provider} from 'react-redux'; 4 | import FullScreen from '../components/layout-containers/full-screen.jsx'; 5 | import rootReducer from './startup.reducer'; 6 | import reduxStore from '../services/redux-store'; 7 | import ipcDispatcher from '../services/ipc-dispatcher'; 8 | import text from './startup-text.yml'; 9 | 10 | const store = reduxStore.create(rootReducer); 11 | 12 | ipcDispatcher(store.dispatch); 13 | 14 | /** 15 | * @class Startup 16 | * @extends ReactComponent 17 | */ 18 | export default React.createClass({ 19 | displayName: 'Startup', 20 | childContextTypes: { 21 | store: React.PropTypes.object.isRequired, 22 | text: React.PropTypes.object.isRequired 23 | }, 24 | getChildContext: function () { 25 | return {store, text}; 26 | }, 27 | render: function () { 28 | return ( 29 | 30 | 31 | 32 | 33 | 34 | ); 35 | } 36 | }); 37 | -------------------------------------------------------------------------------- /src/browser/containers/startup.reducer.js: -------------------------------------------------------------------------------- 1 | import applicationControl from '../services/application-control'; 2 | import { combineReducers } from 'redux'; 3 | import setup from './setup-viewer/setup-viewer.reducer'; 4 | 5 | function broadcast(state, action) { 6 | applicationControl.shareAction(action); 7 | 8 | if (!state) { 9 | return {}; 10 | } 11 | 12 | return state; 13 | } 14 | 15 | export default combineReducers({ 16 | setup, 17 | broadcast 18 | }); 19 | -------------------------------------------------------------------------------- /src/browser/containers/studio-layout/rodeo-logo.1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/browser/containers/studio-layout/rodeo-logo.1x.png -------------------------------------------------------------------------------- /src/browser/containers/studio-layout/rodeo-logo.2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/browser/containers/studio-layout/rodeo-logo.2x.png -------------------------------------------------------------------------------- /src/browser/containers/studio-layout/rodeo-logo.4x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/browser/containers/studio-layout/rodeo-logo.4x.png -------------------------------------------------------------------------------- /src/browser/containers/variable-viewer/variable-viewer.reducer.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import mapReducers from '../../services/map-reducers'; 3 | 4 | function variablesChanged(state, action) { 5 | if (!_.isEqual(state.variables, action.payload)) { 6 | state = state.set('variables', action.payload); 7 | } 8 | 9 | return state; 10 | } 11 | 12 | export default mapReducers({ 13 | VARIABLES_CHANGED: variablesChanged 14 | }, {}); 15 | -------------------------------------------------------------------------------- /src/browser/entry/free-tabs-only.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Rodeo 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
    15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/browser/entry/free-tabs-only.js: -------------------------------------------------------------------------------- 1 | import { AppContainer } from 'react-hot-loader'; 2 | import React from 'react'; 3 | import ReactDOM from 'react-dom'; 4 | import App from '../containers/free-tabs-only.jsx'; 5 | 6 | const rootEl = document.querySelector('main'); 7 | 8 | ReactDOM.render( 9 | 10 | 11 | , 12 | rootEl 13 | ); 14 | 15 | if (module.hot) { 16 | module.hot.accept('../containers/free-tabs-only.jsx', () => { 17 | // If you use Webpack 2 in ES modules mode, you can 18 | // use here rather than require() a . 19 | const NextApp = require('../containers/free-tabs-only.jsx').default; 20 | 21 | ReactDOM.render( 22 | 23 | 24 | , 25 | rootEl 26 | ); 27 | }); 28 | } 29 | 30 | ReactDOM.render(React.createElement(App, null), document.querySelector('main')); 31 | -------------------------------------------------------------------------------- /src/browser/entry/startup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Rodeo Startup 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
    15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/browser/entry/startup.js: -------------------------------------------------------------------------------- 1 | import { AppContainer } from 'react-hot-loader'; 2 | import React from 'react'; 3 | import ReactDOM from 'react-dom'; 4 | import App from './../containers/startup.jsx'; 5 | 6 | /** 7 | * Use #content because
    is deeper. There should be a header and footer for the page that will be 8 | * consistent in all the setup screens. 9 | */ 10 | const rootEl = document.querySelector('main'); 11 | 12 | ReactDOM.render( 13 | 14 | 15 | , 16 | rootEl 17 | ); 18 | 19 | if (module.hot) { 20 | module.hot.accept('./../containers/startup.jsx', () => { 21 | // If you use Webpack 2 in ES modules mode, you can 22 | // use here rather than require() a . 23 | const NextApp = require('./../containers/startup.jsx').default; 24 | 25 | ReactDOM.render( 26 | 27 | 28 | , 29 | rootEl 30 | ); 31 | }); 32 | } 33 | -------------------------------------------------------------------------------- /src/browser/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/browser/favicon.ico -------------------------------------------------------------------------------- /src/browser/services/api.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Currently, we use ipc to communicate to the API. In the future, this will change 3 | * @module 4 | */ 5 | 6 | import ipc from 'ipc'; 7 | import bluebird from 'bluebird'; 8 | 9 | export default { 10 | send: bluebird.method(ipc.send), 11 | on: ipc.on 12 | }; 13 | -------------------------------------------------------------------------------- /src/browser/services/cid.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This has to be unique within a particular client, so simple counting will do. 3 | * @module 4 | */ 5 | 6 | import textUtil from './text-util'; 7 | 8 | const windowPostfix = textUtil.getRandomCharacters(5); 9 | 10 | /** 11 | * @returns {function} 12 | */ 13 | export default (function () { 14 | let i = 0; 15 | 16 | return function () { 17 | if (i == Number.MAX_SAFE_INTEGER) { 18 | i = 0; 19 | } 20 | return 'cid-' + (i++).toString(36) + '-' + windowPostfix; 21 | }; 22 | }()); 23 | -------------------------------------------------------------------------------- /src/browser/services/common-react.test.js: -------------------------------------------------------------------------------- 1 | /* globals describe, it, expect */ 2 | 3 | import _ from 'lodash'; 4 | import lib from './common-react'; 5 | 6 | describe(__filename, function () { 7 | describe('shallowCompare', function () { 8 | it('is true when both are equal', function () { 9 | const instance = {props: {}, state: {}}; 10 | 11 | expect(lib.shallowEqual(instance, {}, {})).toEqual(true); 12 | }); 13 | 14 | it('is true when states are equal', function () { 15 | const instance = {state: {}}; 16 | 17 | expect(lib.shallowEqual(instance, undefined, {})).toEqual(true); 18 | }); 19 | 20 | it('is true when props are equal', function () { 21 | const instance = {props: {}}; 22 | 23 | expect(lib.shallowEqual(instance, {})).toEqual(true); 24 | }); 25 | 26 | it('is false when props are not equal', function () { 27 | const instance = {props: {}}; 28 | 29 | expect(lib.shallowEqual(instance, {a: 'b'})).toEqual(false); 30 | }); 31 | 32 | it('is true when props are equal except for functions', function () { 33 | const instance = {props: {a: _.constant('b')}}; 34 | 35 | expect(lib.shallowEqual(instance, {a: _.constant('b')})).toEqual(true); 36 | }); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /src/browser/services/database-connections.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import api from './api'; 3 | 4 | /** 5 | * Any properties that are strings and empty are removed from shallowly cloned object 6 | * @param {object} obj 7 | * @returns {object} 8 | */ 9 | function removeEmptyStrings(obj) { 10 | return _.reduce(obj, (obj, value, key) => { 11 | if (typeof value === 'string') { 12 | if (value) { 13 | obj[key] = value; 14 | } 15 | } else { 16 | obj[key] = value; 17 | } 18 | 19 | return obj; 20 | }, {}); 21 | } 22 | 23 | function connect(connectionConfig) { 24 | return api.send('databaseConnect', removeEmptyStrings(connectionConfig)); 25 | } 26 | 27 | function query(context) { 28 | return api.send('databaseQuery', context.id, context.text); 29 | } 30 | 31 | function getInfo(id) { 32 | return api.send('databaseInfo', id); 33 | } 34 | 35 | function disconnect(id) { 36 | return api.send('databaseDisconnect', id); 37 | } 38 | 39 | export default { 40 | connect, 41 | disconnect, 42 | getInfo, 43 | query 44 | }; 45 | -------------------------------------------------------------------------------- /src/browser/services/dom.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Helper functions for tranversing the dom without jQuery 3 | * @module 4 | */ 5 | 6 | /** 7 | * @param {Node} node 8 | * @param {string} nodeName 9 | * @returns {Element|Node|false} 10 | */ 11 | export function getParentNodeOf(node, nodeName) { 12 | nodeName = nodeName.toUpperCase(); 13 | while (node.parentNode && node.nodeName !== nodeName) { 14 | node = node.parentNode; 15 | } 16 | return node.nodeName === nodeName && node; 17 | } 18 | 19 | -------------------------------------------------------------------------------- /src/browser/services/errors/index.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | function toObject(error) { 4 | const properties = {}; 5 | 6 | _.assign(properties, _.pick(error, ['message', 'stack'])); 7 | _.each(error, (value, key) => properties[key] = value); 8 | 9 | return properties; 10 | } 11 | 12 | export default { 13 | toObject 14 | }; 15 | -------------------------------------------------------------------------------- /src/browser/services/errors/validation-error.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | function ValidationError(message, properties) { 4 | const error = Error.call(this, message); 5 | 6 | this.name = 'ValidationError'; 7 | this.message = error.message; 8 | this.stack = error.stack; 9 | _.assign(this, properties); 10 | } 11 | ValidationError.prototype = Object.create(Error.prototype); 12 | ValidationError.prototype.constructor = ValidationError; 13 | 14 | export default ValidationError; 15 | -------------------------------------------------------------------------------- /src/browser/services/global-observer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 3 | */ 4 | 5 | import Eventify from 'eventify'; 6 | 7 | const observer = {}; 8 | 9 | Eventify.enable(observer); 10 | 11 | /** 12 | * Triggers when something in the window resizes, possibly requiring others to resize around them. 13 | * 14 | * Other things that resize should trigger this observer event as well 15 | */ 16 | function triggerOnResize() { 17 | window.addEventListener('focus', () => observer.trigger('resize')); 18 | window.addEventListener('resize', () => observer.trigger('resize')); 19 | } 20 | 21 | triggerOnResize(); 22 | 23 | export default observer; 24 | -------------------------------------------------------------------------------- /src/browser/services/guid.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This has to be unique between clients, which is different than the cid. 3 | * @module 4 | */ 5 | 6 | /** 7 | * @returns {string} 8 | */ 9 | function s4() { 10 | return Math.floor((1 + Math.random()) * 0x10000) 11 | .toString(16) 12 | .substring(1); 13 | } 14 | 15 | export default (function () { 16 | return function () { 17 | return s4() + s4() + '-' + s4() + '-' + s4() + '-' + 18 | s4() + '-' + s4() + s4() + s4(); 19 | }; 20 | }()); 21 | -------------------------------------------------------------------------------- /src/browser/services/immutable-util.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import Immutable from 'seamless-immutable'; 3 | 4 | function unshift(state, item) { 5 | const mutableArray = state.asMutable(); 6 | 7 | mutableArray.unshift(item); 8 | 9 | return Immutable(mutableArray); 10 | } 11 | 12 | function unshiftAtPath(state, path, item) { 13 | return state.updateIn(path, array => { 14 | return unshift(array, item); 15 | }); 16 | } 17 | 18 | function push(state, item) { 19 | const mutableArray = state.asMutable(); 20 | 21 | mutableArray.push(item); 22 | 23 | return Immutable(mutableArray); 24 | } 25 | 26 | function pushAtPath(state, path, item) { 27 | return state.updateIn(path, array => { 28 | return push(array, item); 29 | }); 30 | } 31 | 32 | function removeAt(state, index) { 33 | if (_.isArray(state)) { 34 | state = state.asMutable(); 35 | 36 | state.splice(index, 1); 37 | 38 | return Immutable(state); 39 | } 40 | 41 | return state.without(index); 42 | } 43 | 44 | function removeAtPath(state, path, index) { 45 | return state.updateIn(path, obj => { 46 | return removeAt(obj, index); 47 | }); 48 | } 49 | 50 | export default { 51 | removeAt, 52 | removeAtPath, 53 | push, 54 | pushAtPath, 55 | unshift, 56 | unshiftAtPath 57 | }; 58 | -------------------------------------------------------------------------------- /src/browser/services/jupyter/conda.js: -------------------------------------------------------------------------------- 1 | import api from '../api'; 2 | 3 | function copyCondaToHome() { 4 | return api.send('copyCondaToHome'); 5 | } 6 | 7 | export default { 8 | copyCondaToHome 9 | }; 10 | -------------------------------------------------------------------------------- /src/browser/services/jupyter/response.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | const requests = {}; // track requests so we can resolve their promises later 4 | 5 | /** 6 | * @param {function} dispatch 7 | * @param {JupyterClientResponse} response 8 | */ 9 | function handle(dispatch, response) { 10 | let msg_id = _.get(response, 'result.parent_header.msg_id'), 11 | request = requests[msg_id]; 12 | 13 | if (request) { 14 | if (request.resolveEvent === _.get(response, 'result.msg_type')) { 15 | request.deferred.resolve({request, response}); 16 | delete requests[msg_id]; 17 | } else { 18 | request.unmatchedResponses = request.unmatchedResponses || []; 19 | request.unmatchedResponses.push(response); 20 | } 21 | } else { 22 | return dispatch({type: 'JUPYTER_RESPONSE', payload: response}); 23 | } 24 | } 25 | 26 | /** 27 | * Add a request to be responded to. 28 | * 29 | * @param {string} id 30 | * @param {object} request 31 | */ 32 | function addRequest(id, request) { 33 | requests[id] = request; 34 | } 35 | 36 | export default { 37 | handle, 38 | addRequest 39 | }; 40 | -------------------------------------------------------------------------------- /src/browser/services/log.js: -------------------------------------------------------------------------------- 1 | const types = { 2 | info: true, 3 | debug: true, 4 | warn: true, 5 | error: true 6 | }; 7 | 8 | export function log(type) { 9 | if (types[type]) { 10 | /* eslint no-console: 0 */ 11 | console[type].apply(console, Array.prototype.slice.call(arguments, 1)); 12 | } 13 | } 14 | 15 | export function asInternal(prefix) { 16 | return function (type) { 17 | log.apply(null, [type, prefix].concat(Array.prototype.slice.call(arguments, 1))); 18 | }; 19 | } 20 | 21 | export default log; 22 | -------------------------------------------------------------------------------- /src/browser/services/map-reducers.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {object} reducerMap 3 | * @param {*} initialState 4 | * @returns {function} 5 | */ 6 | export default function (reducerMap, initialState) { 7 | return function (state, action) { 8 | if (!state) { 9 | state = initialState; 10 | } 11 | 12 | if (reducerMap[action.type]) { 13 | return reducerMap[action.type](state, action) || state; 14 | } else { 15 | return state; 16 | } 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /src/browser/services/map-reducers.test.js: -------------------------------------------------------------------------------- 1 | /* globals describe, it, expect, jest */ 2 | 3 | import lib from './map-reducers'; 4 | 5 | describe(__filename, function () { 6 | 7 | it('returns initial state when not given state', function () { 8 | const reducerMap = {}, 9 | initialState = {a: 'b'}, 10 | state = undefined, 11 | action = {}; 12 | 13 | expect(lib(reducerMap, initialState)(state, action)).toEqual(initialState); 14 | }); 15 | 16 | it('runs function matching action', function () { 17 | const spy = jest.fn(), 18 | reducerMap = {a: spy}, 19 | initialState = {}, 20 | state = {}, 21 | action = {type: 'a'}; 22 | 23 | lib(reducerMap, initialState)(state, action); 24 | 25 | expect(spy).toBeCalledWith(state, action); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /src/browser/services/react-performance.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Performance grouping 3 | */ 4 | 5 | let events = []; 6 | 7 | function mark(componentInstance, eventName, props) { 8 | events.push([componentInstance.constructor.displayName, eventName, props]); 9 | } 10 | 11 | function report() { 12 | if (events.length) { 13 | const tempEvents = events; 14 | 15 | events = []; 16 | 17 | console.groupCollapsed('performance'); 18 | for (let i = 0; i < tempEvents.length; i++) { 19 | console.log.apply(console, tempEvents[i]); 20 | } 21 | console.groupEnd(); 22 | } 23 | } 24 | 25 | export default { 26 | mark, 27 | report 28 | }; 29 | -------------------------------------------------------------------------------- /src/browser/services/redux-store.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import {createStore, applyMiddleware} from 'redux'; 3 | import thunk from 'redux-thunk'; 4 | import reactPerformance from './react-performance'; 5 | 6 | /** 7 | * @param {object} reducer 8 | * @param {object} [initialState] 9 | * @returns {*} 10 | */ 11 | function create(reducer, initialState) { 12 | const createStoreWithMiddleware = applyMiddleware(thunk)(createStore), 13 | store = createStoreWithMiddleware(reducer, initialState); 14 | 15 | // log every change to the store (this has performance implications, of course). 16 | store.subscribe(_.debounce(() => { 17 | reactPerformance.report(); 18 | console.log('store', store.getState()); 19 | }, 500)); 20 | 21 | return store; 22 | } 23 | 24 | export default { 25 | create 26 | }; 27 | -------------------------------------------------------------------------------- /src/browser/services/registration.js: -------------------------------------------------------------------------------- 1 | import {local} from './store'; 2 | 3 | const minute = 1000 * 60, 4 | day = minute * 60 * 24, 5 | hasRegisteredKey = 'hasRegistered', 6 | lastRegisterReminderKey = 'lastRegisterReminder'; 7 | 8 | function shouldShowDialog() { 9 | const hasRegistered = local.get(hasRegisteredKey), 10 | lastRegisterReminder = local.get(lastRegisterReminderKey), 11 | timeSince = !!lastRegisterReminder && (Date.now() - new Date(lastRegisterReminder).getTime()); 12 | 13 | return !hasRegistered && (!lastRegisterReminder || (timeSince > day)); 14 | } 15 | 16 | function rememberShowedDialog() { 17 | local.set(lastRegisterReminderKey, new Date().getTime()); 18 | } 19 | 20 | /** 21 | * @param {object} data 22 | * @returns {Promise} 23 | */ 24 | function register(data) { 25 | data['rodeoId'] = local.get('userId'); 26 | 27 | return fetch('https://www.yhat.com/rodeo/register', { 28 | method: 'POST', 29 | body: JSON.stringify(data), 30 | headers: {'Content-Type':'application/json'} 31 | }).then(function () { 32 | // Use a timestamp so we know _when_ they registered 33 | local.set(hasRegisteredKey, new Date().getTime()); 34 | }); 35 | } 36 | 37 | export default { 38 | register, 39 | shouldShowDialog, 40 | rememberShowedDialog 41 | }; 42 | -------------------------------------------------------------------------------- /src/browser/services/selection-util.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | /** 4 | * @param {Selection} selection 5 | * @returns {boolean} 6 | * @example 7 | * function onClick(event) { 8 | * const isClick = isSelectionClick(window.getSelection()); 9 | * } 10 | */ 11 | function isSelectionClick(selection) { 12 | return selection.anchorOffset === selection.focusOffset && selection.anchorNode === selection.focusNode; 13 | } 14 | 15 | function copy(el) { 16 | const range = document.createRange(), 17 | prevSelection = [], 18 | selection = window.getSelection(); 19 | 20 | for (let i = 0; i < selection.rangeCount; i++) { 21 | prevSelection[i] = selection.getRangeAt(i); 22 | } 23 | selection.removeAllRanges(); 24 | range.selectNode(el); 25 | selection.addRange(range); 26 | document.execCommand('copy'); 27 | _.defer(() => { 28 | window.getSelection().removeAllRanges(); 29 | for (let i = 0; i < prevSelection.length; i++) { 30 | window.getSelection().addRange(prevSelection[i]); 31 | } 32 | }); 33 | } 34 | 35 | function selectElement(el) { 36 | const range = document.createRange(), 37 | selection = window.getSelection(); 38 | 39 | selection.removeAllRanges(); 40 | range.selectNode(el); 41 | selection.addRange(range); 42 | } 43 | 44 | export default { 45 | copy, 46 | isSelectionClick, 47 | selectElement 48 | }; 49 | -------------------------------------------------------------------------------- /src/fonts/NotoMono-hinted/NotoMono-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/fonts/NotoMono-hinted/NotoMono-Regular.ttf -------------------------------------------------------------------------------- /src/fonts/NotoSans-unhinted/NotoSans-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/fonts/NotoSans-unhinted/NotoSans-Bold.ttf -------------------------------------------------------------------------------- /src/fonts/NotoSans-unhinted/NotoSans-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/fonts/NotoSans-unhinted/NotoSans-BoldItalic.ttf -------------------------------------------------------------------------------- /src/fonts/NotoSans-unhinted/NotoSans-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/fonts/NotoSans-unhinted/NotoSans-Italic.ttf -------------------------------------------------------------------------------- /src/fonts/NotoSans-unhinted/NotoSans-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/fonts/NotoSans-unhinted/NotoSans-Regular.ttf -------------------------------------------------------------------------------- /src/fonts/NotoSerif-unhinted/NotoSerif-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/fonts/NotoSerif-unhinted/NotoSerif-Bold.ttf -------------------------------------------------------------------------------- /src/fonts/NotoSerif-unhinted/NotoSerif-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/fonts/NotoSerif-unhinted/NotoSerif-BoldItalic.ttf -------------------------------------------------------------------------------- /src/fonts/NotoSerif-unhinted/NotoSerif-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/fonts/NotoSerif-unhinted/NotoSerif-Italic.ttf -------------------------------------------------------------------------------- /src/fonts/NotoSerif-unhinted/NotoSerif-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/fonts/NotoSerif-unhinted/NotoSerif-Regular.ttf -------------------------------------------------------------------------------- /src/fonts/fonts.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Lato-Regular'; 3 | src: url('Lato-Regular.ttf') format('truetype'); 4 | font-weight: normal; 5 | font-style: normal; 6 | } 7 | 8 | @font-face { 9 | font-family: 'NotoSans-Regular'; 10 | src: url('NotoSans-Regular.ttf') format('truetype'); 11 | font-weight: normal; 12 | font-style: normal; 13 | } 14 | 15 | @font-face { 16 | font-family: 'NotoSerif-Regular'; 17 | src: url('NotoSerif-Regular.ttf') format('truetype'); 18 | font-weight: normal; 19 | font-style: normal; 20 | } 21 | 22 | @font-face { 23 | font-family: 'NotoMono-Regular'; 24 | src: url('NotoMono-Regular.ttf') format('truetype'); 25 | font-weight: normal; 26 | font-style: normal; 27 | } 28 | 29 | @font-face { 30 | font-family: 'Roboto-Regular'; 31 | src: url('Roboto-Regular.ttf') format('truetype'); 32 | font-weight: normal; 33 | font-style: normal; 34 | } 35 | 36 | .font-heading { 37 | font-family: 'Lato-Regular', 'NotoSerif-Regular', 'Helvetica Neue', serif; 38 | } 39 | 40 | .font-monospaced { 41 | font-family: 'Menlo', 'Monaco', 'Consolas', 'NotoMono-Regular', 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace; 42 | } 43 | 44 | .font-serif { 45 | font-family: 'NotoSerif-Regular', serif; 46 | } 47 | 48 | .font-sans { 49 | font-family: 'Helvetica Neue', 'Roboto-Regular', 'NotoSans-Regular', 'Helvetica Neue', sans-serif; 50 | } 51 | -------------------------------------------------------------------------------- /src/fonts/lato/Lato-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/fonts/lato/Lato-Black.ttf -------------------------------------------------------------------------------- /src/fonts/lato/Lato-BlackItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/fonts/lato/Lato-BlackItalic.ttf -------------------------------------------------------------------------------- /src/fonts/lato/Lato-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/fonts/lato/Lato-Bold.ttf -------------------------------------------------------------------------------- /src/fonts/lato/Lato-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/fonts/lato/Lato-BoldItalic.ttf -------------------------------------------------------------------------------- /src/fonts/lato/Lato-Hairline.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/fonts/lato/Lato-Hairline.ttf -------------------------------------------------------------------------------- /src/fonts/lato/Lato-HairlineItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/fonts/lato/Lato-HairlineItalic.ttf -------------------------------------------------------------------------------- /src/fonts/lato/Lato-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/fonts/lato/Lato-Italic.ttf -------------------------------------------------------------------------------- /src/fonts/lato/Lato-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/fonts/lato/Lato-Light.ttf -------------------------------------------------------------------------------- /src/fonts/lato/Lato-LightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/fonts/lato/Lato-LightItalic.ttf -------------------------------------------------------------------------------- /src/fonts/lato/Lato-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/fonts/lato/Lato-Regular.ttf -------------------------------------------------------------------------------- /src/fonts/roboto/COPYRIGHT.txt: -------------------------------------------------------------------------------- 1 | Copyright 2011 Google Inc. All Rights Reserved. -------------------------------------------------------------------------------- /src/fonts/roboto/DESCRIPTION.en_us.html: -------------------------------------------------------------------------------- 1 |

    Roboto has a dual nature. It has a mechanical skeleton and the forms are 2 | largely geometric. At the same time, the font features friendly and open 3 | curves. While some grotesks distort their letterforms to force a rigid rhythm, 4 | Roboto doesn’t compromise, allowing letters to be settled into their natural 5 | width. This makes for a more natural reading rhythm more commonly found in 6 | humanist and serif types.

    7 | 8 |

    This is the normal family, which can be used alongside the 9 | Roboto Condensed family and the 10 | Roboto Slab family.

    11 | 12 |

    13 | Updated January 14 2015: 14 | Christian Robertson and the Material Design team unveiled the latest version of Roboto at Google I/O last year, and it is now available from Google Fonts. 15 | Existing websites using Roboto via Google Fonts will start using the latest version automatically. 16 | If you have installed the fonts on your computer, please download them again and re-install. 17 |

    -------------------------------------------------------------------------------- /src/fonts/roboto/Roboto-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/fonts/roboto/Roboto-Black.ttf -------------------------------------------------------------------------------- /src/fonts/roboto/Roboto-BlackItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/fonts/roboto/Roboto-BlackItalic.ttf -------------------------------------------------------------------------------- /src/fonts/roboto/Roboto-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/fonts/roboto/Roboto-Bold.ttf -------------------------------------------------------------------------------- /src/fonts/roboto/Roboto-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/fonts/roboto/Roboto-BoldItalic.ttf -------------------------------------------------------------------------------- /src/fonts/roboto/Roboto-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/fonts/roboto/Roboto-Italic.ttf -------------------------------------------------------------------------------- /src/fonts/roboto/Roboto-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/fonts/roboto/Roboto-Light.ttf -------------------------------------------------------------------------------- /src/fonts/roboto/Roboto-LightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/fonts/roboto/Roboto-LightItalic.ttf -------------------------------------------------------------------------------- /src/fonts/roboto/Roboto-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/fonts/roboto/Roboto-Medium.ttf -------------------------------------------------------------------------------- /src/fonts/roboto/Roboto-MediumItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/fonts/roboto/Roboto-MediumItalic.ttf -------------------------------------------------------------------------------- /src/fonts/roboto/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/fonts/roboto/Roboto-Regular.ttf -------------------------------------------------------------------------------- /src/fonts/roboto/Roboto-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/fonts/roboto/Roboto-Thin.ttf -------------------------------------------------------------------------------- /src/fonts/roboto/Roboto-ThinItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yhat/rodeo/aa1929b1596d1161cd81c930603636a929462ea3/src/fonts/roboto/Roboto-ThinItalic.ttf -------------------------------------------------------------------------------- /src/node/kernels/python/check.py: -------------------------------------------------------------------------------- 1 | # Gets information about a python instance, like packages installed and such 2 | import sys 3 | import json 4 | import os 5 | import pip 6 | 7 | try: 8 | import pip 9 | except: 10 | pip = None 11 | 12 | def get_packages(): 13 | if not pip: 14 | return [] 15 | installed_packages = pip.get_installed_distributions() 16 | packages = [{ "name": i.key, "version": i.version} for i in installed_packages] 17 | installed_packages_list = sorted(packages, key=lambda x: x['name']) 18 | return installed_packages_list 19 | 20 | # check for IPython kernel 21 | has_jupyter_kernel = True 22 | try: 23 | from jupyter_client import manager 24 | except: 25 | try: 26 | from IPython.kernel import manager 27 | except: 28 | #if pip: 29 | # try: 30 | # pip.main(['install', '--disable-pip-version-check', '-qq', 'jupyter']) 31 | # except: 32 | # has_jupyter_kernel = False 33 | #else: 34 | has_jupyter_kernel = False 35 | 36 | # may fail 37 | try: 38 | executable = sys.executable 39 | except: 40 | executable = None 41 | 42 | sys.stdout.write(json.dumps({ 43 | "hasJupyterKernel": has_jupyter_kernel, 44 | "cwd": os.getcwd(), 45 | "version": sys.version, 46 | "executable": executable, 47 | "argv": sys.argv, 48 | "packages": get_packages() 49 | })) 50 | -------------------------------------------------------------------------------- /src/node/kernels/python/language.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const sinon = require('sinon'), 4 | dirname = __dirname.split('/').pop(), 5 | filename = __filename.split('/').pop().split('.').shift(), 6 | lib = require('./' + filename); 7 | 8 | describe(dirname + '/' + filename, function () { 9 | let sandbox; 10 | 11 | beforeEach(function () { 12 | sandbox = sinon.sandbox.create(); 13 | }); 14 | 15 | afterEach(function () { 16 | sandbox.restore(); 17 | }); 18 | 19 | describe('toPythonArgs', function () { 20 | const fn = lib[this.title]; 21 | 22 | it('converts', function () { 23 | const data = {a: 'b', cD: 'e', fgHi: 'j'}, 24 | expectedResult = {a: 'b', c_d: 'e', fg_hi: 'j'}; 25 | 26 | expect(fn(data)).to.deep.equal(expectedResult); 27 | }); 28 | }); 29 | 30 | describe('setDefaultEnvVars', function () { 31 | const fn = lib[this.title]; 32 | 33 | it('removes buffering', function () { 34 | const data = {}; 35 | 36 | expect(fn(data)).to.have.property('PYTHONUNBUFFERED'); 37 | }); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /src/node/services/args.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import yargs from 'yargs'; 3 | 4 | function getArgv() { 5 | let sliceNum; 6 | 7 | if (_.endsWith(process.argv[0], 'Electron')) { 8 | sliceNum = 2; 9 | } else { 10 | sliceNum = 1; 11 | } 12 | 13 | return yargs 14 | .env('RODEO') 15 | .boolean('dev').default('dev', false) 16 | .option('startup', { 17 | default: true, 18 | type: 'boolean', 19 | describe: 'Show startup screen when not given file or path' 20 | }) 21 | .option('dev', { 22 | default: false, 23 | type: 'boolean', 24 | describe: 'Show development tools' 25 | }) 26 | .epilogue('RODEO_* environment variables work as well, i.e., RODEO_DEV=true') 27 | .help('h') 28 | .alias('h', 'help') 29 | .version() 30 | .wrap(null) 31 | .parse(process.argv.slice(sliceNum)); 32 | } 33 | 34 | export default { 35 | getArgv: _.memoize(getArgv) 36 | }; 37 | -------------------------------------------------------------------------------- /src/node/services/chromium-errors.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Common errors that might be encountered by users from loading a window 3 | IO_PENDING: 4 | id: -1 5 | FAILED: 6 | id: -2 7 | ABORTED: 8 | id: -3 9 | INVALID_ARGUMENT: 10 | id: -4 11 | INVALID_HANDLE: 12 | id: -5 13 | FILE_NOT_FOUND: 14 | id: -6 15 | TIMED_OUT: 16 | id: -7 17 | FILE_TOO_BIG: 18 | id: -8 19 | UNEXPECTED: 20 | id: -9 21 | ACCESS_DENIED: 22 | id: -10 23 | NOT_IMPLEMENTED: 24 | id: -11 25 | INSUFFICIENT_RESOURCES: 26 | id: -12 27 | OUT_OF_MEMORY: 28 | id: -13 -------------------------------------------------------------------------------- /src/node/services/clone.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | function toObject(source) { 4 | 5 | if (_.isError(source)) { 6 | const dest = {}, 7 | keys = _.filter(Object.getOwnPropertyNames(source), key => { 8 | // is not a function 9 | // does not start with an underscore 10 | return !_.isFunction(source[key]) && key[0] !== '_'; 11 | }); 12 | 13 | for (let i = 0; i < keys.length; i++) { 14 | const key = keys[i]; 15 | 16 | dest[key] = source[key]; 17 | } 18 | 19 | return dest; 20 | } 21 | 22 | return _.clone(source); 23 | } 24 | 25 | export default { 26 | toObject 27 | }; 28 | -------------------------------------------------------------------------------- /src/node/services/db/postgresql/get-schemas.sql: -------------------------------------------------------------------------------- 1 | select schema_name from information_schema.schemata 2 | -------------------------------------------------------------------------------- /src/node/services/db/postgresql/get-tables-by-schema.sql: -------------------------------------------------------------------------------- 1 | select tablename from pg_tables where schemaname = $1 2 | -------------------------------------------------------------------------------- /src/node/services/electron-winston-transport.js: -------------------------------------------------------------------------------- 1 | import util from 'util'; 2 | import winston from 'winston'; 3 | 4 | let ElectronLogger = function (options) { 5 | this.name = 'electronLogger'; 6 | this.level = options.level || 'info'; 7 | }; 8 | 9 | // 10 | // Inherit from `winston.Transport` so you can take advantage 11 | // of the base functionality and `.handleExceptions()`. 12 | // 13 | util.inherits(ElectronLogger, winston.Transport); 14 | 15 | ElectronLogger.prototype.log = function (level, msg, meta, callback) { 16 | const ipcRenderer = require('electron').ipcRenderer; 17 | 18 | if (ipcRenderer) { 19 | ipcRenderer.send('console-log', {level, msg, meta}); 20 | } 21 | 22 | // 23 | // Store this message and metadata, maybe use some custom logic 24 | // then callback indicating success. 25 | // 26 | callback(null, true); 27 | }; 28 | 29 | export default ElectronLogger; 30 | -------------------------------------------------------------------------------- /src/node/services/errors/process-error.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | /** 4 | * @param {string} message 5 | * @param {object} properties 6 | * @constructor 7 | */ 8 | function ProcessError(message, properties) { 9 | const error = Error.call(this, message); 10 | 11 | this.name = 'ProcessError'; 12 | this.message = error.message; 13 | this.stack = error.stack; 14 | _.assign(this, properties); 15 | } 16 | ProcessError.prototype = Object.create(Error.prototype); 17 | ProcessError.prototype.constructor = ProcessError; 18 | 19 | export default ProcessError; 20 | -------------------------------------------------------------------------------- /src/node/services/processes.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const expect = require('chai').expect, 4 | sinon = require('sinon'), 5 | childProcess = require('child_process'), 6 | MockChildProcess = require('../../../test/mocks/classes/child-process'), 7 | log = require('./log'), 8 | dirname = __dirname.split('/').pop(), 9 | filename = __filename.split('/').pop().split('.').shift(), 10 | lib = require('./' + filename); 11 | 12 | describe(dirname + '/' + filename, function () { 13 | let sandbox; 14 | 15 | beforeEach(function () { 16 | sandbox = sinon.sandbox.create(); 17 | sandbox.stub(log); 18 | sandbox.stub(childProcess); 19 | }); 20 | 21 | afterEach(function () { 22 | sandbox.restore(); 23 | }); 24 | 25 | describe('create', function () { 26 | const fn = lib[this.title]; 27 | 28 | it('creates', function () { 29 | const cmd = 'some command', 30 | mockChild = new MockChildProcess(); 31 | 32 | childProcess.spawn.returns(mockChild); 33 | 34 | expect(fn(cmd)).to.equal(mockChild); 35 | }); 36 | }); 37 | 38 | describe('kill', function () { 39 | const fn = lib[this.title]; 40 | 41 | it('kills', function () { 42 | const mockChild = new MockChildProcess(); 43 | 44 | return fn(mockChild).then(function (result) { 45 | expect(result).to.deep.equal({code: 'a', signal: 'b'}); 46 | }); 47 | }); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /src/node/services/rest.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports.get = require('node-fetch'); -------------------------------------------------------------------------------- /src/node/services/survey.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import bluebird from 'bluebird'; 3 | import browserWindows from './browser-windows'; 4 | 5 | const log = require('./log').asInternal(__filename); 6 | 7 | function getTabs() { 8 | const windowNames = browserWindows.getWindowNames(); 9 | 10 | return bluebird.all(_.map(windowNames, name => { 11 | return browserWindows.send(name, 'getTabs').catch(error => log('error', error)); 12 | })); 13 | } 14 | 15 | module.exports.getTabs = getTabs; 16 | -------------------------------------------------------------------------------- /src/node/services/win32/registry.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import path from 'path'; 4 | import processes from '../processes'; 5 | 6 | /** 7 | * @param {string} systemRoot 8 | * @returns {string} 9 | * @example setSystemRoot(process.env.SystemRoot); 10 | */ 11 | function getRegPath(systemRoot) { 12 | if (systemRoot) { 13 | return path.join(systemRoot, 'System32', 'reg.exe'); 14 | } 15 | 16 | return 'reg.exe'; 17 | } 18 | 19 | /** 20 | * Add item to registry 21 | * @param {[string]} args 22 | * @param {string} systemRoot 23 | * @returns {Promise.<{errors: Error[], stderr: string, stdout: string}>} 24 | */ 25 | function add(args, systemRoot) { 26 | args.unshift('add'); 27 | args.push('/f'); 28 | 29 | return processes.exec(getRegPath(systemRoot), args); 30 | } 31 | 32 | /** 33 | * Remove item from registry 34 | * @param {string} keyPath 35 | * @param {string} systemRoot 36 | * @returns {Promise.<{errors: Error[], stderr: string, stdout: string}>} 37 | */ 38 | function remove(keyPath, systemRoot) { 39 | const args = ['delete', keyPath, '/f']; 40 | 41 | return processes.exec(getRegPath(systemRoot), args); 42 | } 43 | 44 | module.exports.add = add; 45 | module.exports.remove = remove; 46 | -------------------------------------------------------------------------------- /src/readme.md: -------------------------------------------------------------------------------- 1 | Why two package.json? 2 | 3 | https://github.com/szwacz/electron-boilerplate#omg-but-seriously-why-there-are-two-packagejson 4 | 5 | https://github.com/electron-userland/electron-builder/issues/39 6 | 7 | https://github.com/electron-userland/electron-builder/issues/182 8 | 9 | https://github.com/electron-userland/electron-builder/issues/230 10 | -------------------------------------------------------------------------------- /src/shared/dateUtil.js: -------------------------------------------------------------------------------- 1 | function getCurrentTime() { 2 | return new Date().getTime(); 3 | } 4 | 5 | export default { 6 | getCurrentTime 7 | }; 8 | -------------------------------------------------------------------------------- /src/shared/env.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | export function splitList(list) { 4 | if (process.platform === 'win32') { 5 | return list.split(';'); 6 | } else { 7 | return list.split(':'); 8 | } 9 | } 10 | 11 | export function joinList(list) { 12 | if (process.platform === 'win32') { 13 | return list.join(';'); 14 | } else { 15 | return list.join(':'); 16 | } 17 | } 18 | 19 | export function getKeyMap(source) { 20 | return _.reduce(source, (obj, value, key) => { 21 | obj[key.toUpperCase()] = key; 22 | 23 | return obj; 24 | }, {}); 25 | } 26 | 27 | /** 28 | * @param {object} env 29 | * @param {string} [keyName='PATH'] 30 | * @returns {Array} 31 | */ 32 | export function getPath(env, keyName) { 33 | keyName = keyName && keyName.toUpperCase() || 'PATH'; 34 | const keyMap = getKeyMap(env), 35 | path = env[keyMap[keyName]]; 36 | 37 | return path ? splitList(path) : []; 38 | } 39 | 40 | /** 41 | * @param {object} env 42 | * @param {Array} newPath 43 | * @param {string} [keyName='PATH'] 44 | * @returns {object} 45 | * @example setPath(process.env, '/usr/local/bin', 'MANPATH') 46 | */ 47 | export function setPath(env, newPath, keyName) { 48 | keyName = keyName && keyName.toUpperCase() || 'PATH'; 49 | const keyMap = getKeyMap(env); 50 | 51 | if (_.isArray(newPath)) { 52 | let key = keyMap[keyName] || keyName; 53 | 54 | env[key] = joinList(newPath); 55 | } 56 | 57 | return env; 58 | } 59 | -------------------------------------------------------------------------------- /src/themes/cobalt.less: -------------------------------------------------------------------------------- 1 | // dark theme 2 | @import "default.less"; 3 | @import "imported/cobalt.less"; 4 | -------------------------------------------------------------------------------- /src/themes/dark.less: -------------------------------------------------------------------------------- 1 | // presentation theme. this is still light, but looks better on a projector 2 | @import "default.less"; 3 | @import "imported/dark.less"; 4 | -------------------------------------------------------------------------------- /src/themes/default.less: -------------------------------------------------------------------------------- 1 | // Core variables and mixins 2 | @import "imported/default.less"; 3 | @import "../../node_modules/bootstrap/less/bootstrap.less"; 4 | @import "../../node_modules/font-awesome/less/font-awesome.less"; 5 | 6 | // structure 7 | @import "structure/global.less"; 8 | @import "structure/fixed-data-table.less"; 9 | @import "structure/jqconsole.less"; 10 | @import "structure/forms.less"; 11 | @import "lib/jquery.dataTables.less"; 12 | 13 | // misc stuff 14 | @import "lib/misc.less"; 15 | 16 | // bootswatch. this overrides certain things w/ default bootstrap 17 | @import "lib/bootswatch.less"; 18 | -------------------------------------------------------------------------------- /src/themes/lib/misc.less: -------------------------------------------------------------------------------- 1 | #bottom-left { 2 | padding: 0 0 0 0; 3 | } 4 | 5 | a { 6 | cursor: pointer; 7 | } 8 | 9 | .editor { 10 | height: 100%; 11 | position: absolute; 12 | } 13 | 14 | .tab-pane { 15 | width: 100%; 16 | overflow-y: scroll; 17 | } 18 | 19 | .navbar { 20 | margin-bottom: 0; 21 | } 22 | 23 | .hat { 24 | position: absolute; 25 | left: 2px; 26 | top: 10px; 27 | width: 35px; 28 | height: auto; 29 | z-index: 100000; 30 | } 31 | .big-hat { 32 | position: relative; 33 | left: 295px; 34 | top: 165px; 35 | width: 200px; 36 | height: auto; 37 | } 38 | 39 | #help-content { 40 | background-color: @body-bg; 41 | color: @text-color; 42 | } 43 | 44 | .selected { 45 | font-size: 20px; 46 | } 47 | 48 | .filename { 49 | text-decoration: none; 50 | } 51 | 52 | .selected:hover { 53 | background-color: @brand-primary; 54 | color: @gray-lighter; 55 | } 56 | 57 | .selected > a:hover { 58 | background-color: @brand-primary; 59 | color: @gray-lighter; 60 | } 61 | 62 | #plots-minimap > .active { 63 | border: medium solid skyblue; 64 | } 65 | 66 | 67 | #history-trail { 68 | > p:nth-child(odd) { 69 | background: @table-bg-accent; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/themes/presentation.less: -------------------------------------------------------------------------------- 1 | // presentation theme. this is still light, but looks better on a projector 2 | @import "default.less"; 3 | @import "imported/presentation.less"; 4 | -------------------------------------------------------------------------------- /src/themes/structure/fixed-data-table.less: -------------------------------------------------------------------------------- 1 | .rodeo .public_fixedDataTable_main, 2 | .rodeo .public_fixedDataTable_header, 3 | .rodeo .public_fixedDataTable_hasBottomBorder { 4 | border-color: @table-header-border; 5 | } 6 | 7 | .rodeo .fixedDataTableLayout_main { 8 | border-style: solid; 9 | border-width: 0; 10 | } 11 | 12 | .rodeo .public_fixedDataTableColumnResizerLine_main { 13 | border-color: @action-drag-border; 14 | } 15 | 16 | .rodeo .public_fixedDataTableCell_columnResizerKnob { 17 | background-color: @action-drag-border; 18 | } 19 | 20 | .rodeo .public_fixedDataTableRow_main { 21 | background-color: @body-bg; 22 | } 23 | 24 | .rodeo .public_fixedDataTable_header, 25 | .rodeo .public_fixedDataTable_header .public_fixedDataTableCell_main { 26 | background-image: none; 27 | } 28 | 29 | .rodeo .public_fixedDataTableCell_cellContent { 30 | padding: 4px; 31 | } 32 | -------------------------------------------------------------------------------- /src/themes/structure/global.less: -------------------------------------------------------------------------------- 1 | html { 2 | height: 100%; 3 | } 4 | 5 | * { 6 | outline: none; 7 | } 8 | 9 | *:focus { 10 | outline: Highlight auto 1px; 11 | transition: outline-offset 0.2s, outline-width 0.2s; 12 | } 13 | 14 | *:focus:hover { 15 | outline: Highlight auto 2px; 16 | } 17 | 18 | body { 19 | height: 100%; 20 | } 21 | 22 | main { 23 | height: 100%; 24 | } 25 | 26 | /* override bootstrap :( to move the tabs tightly together*/ 27 | .nav > li > a[data-toggle="tab"] { 28 | padding: 10px 29 | } 30 | 31 | /* override bootstrap :( to stop adding an underline for non-tabs */ 32 | .nav-tabs > li > a.not-tab, 33 | .nav-tabs > li > a.not-tab:hover, 34 | .nav-tabs > li > a.not-tab:focus:hover { 35 | box-shadow: none; 36 | } 37 | 38 | /* override bootstrap because negative margins are evil */ 39 | main .form-horizontal .form-group { 40 | margin-left: 0; 41 | margin-right: 0; 42 | } 43 | 44 | /* override bootstrap because negative margins are evil (and cause scrollbars in split panes) */ 45 | main .row { 46 | margin-left: 0; 47 | margin-right: 0; 48 | } 49 | 50 | -------------------------------------------------------------------------------- /src/themes/structure/jqconsole.less: -------------------------------------------------------------------------------- 1 | /* The console container element */ 2 | #console { 3 | position: relative; 4 | width: 100%; 5 | background-color: @body-bg; 6 | } 7 | 8 | /* The inner console element. */ 9 | pre.jqconsole { 10 | background-color: @body-bg; 11 | border: 0; 12 | color: @text-color; 13 | /* Allow us to override the font from the user preferences */ 14 | font-size: inherit; 15 | } 16 | 17 | /* The cursor. */ 18 | .jqconsole-cursor { 19 | background-color: @text-color; 20 | } 21 | 22 | /* The cursor color when the console looses focus. */ 23 | .jqconsole-blurred .jqconsole-cursor { 24 | background-color: #666; 25 | } 26 | 27 | /* The current prompt text color */ 28 | .jqconsole-prompt { 29 | color: @text-color; 30 | } 31 | 32 | /* The command history */ 33 | .jqconsole-old-prompt { 34 | color: @text-color; 35 | font-weight: normal; 36 | } 37 | 38 | /* The text color when in input mode. */ 39 | .jqconsole-input { 40 | color: @text-color; 41 | } 42 | 43 | /* Previously entered input. */ 44 | .jqconsole-old-input { 45 | color: @text-color; 46 | font-weight: normal; 47 | } 48 | 49 | /* The text color of the output. */ 50 | .jqconsole-output { 51 | color: @text-color; 52 | } 53 | 54 | .jqconsole-error { 55 | color: red; 56 | } 57 | 58 | .jqconsole-header { 59 | color: @text-color; 60 | } 61 | -------------------------------------------------------------------------------- /test/browser/mocks/ace.js: -------------------------------------------------------------------------------- 1 | export default {}; 2 | -------------------------------------------------------------------------------- /test/browser/mocks/ipc.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | export default { 4 | send: _.noop 5 | }; 6 | -------------------------------------------------------------------------------- /test/browser/mocks/storage.js: -------------------------------------------------------------------------------- 1 | class MockStorage { 2 | constructor() { 3 | this.store = {}; 4 | } 5 | 6 | getItem(key) { 7 | return this.store[key] || null; 8 | } 9 | 10 | setItem(key, value) { 11 | this.store[key] = value.toString(); 12 | } 13 | 14 | clear() { 15 | this.store = {}; 16 | } 17 | 18 | setStore(value) { 19 | this.store = value; 20 | } 21 | 22 | getStore() { 23 | return this.store; 24 | } 25 | } 26 | 27 | export default MockStorage; 28 | -------------------------------------------------------------------------------- /test/fixtures/windows-registry-commands/uninstall-context-menu.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - 3 | - reg.exe 4 | - 5 | - delete 6 | - HKCU\Software\Classes\.py\shell\Rodeo 7 | - "/f" 8 | - 9 | - reg.exe 10 | - 11 | - delete 12 | - HKCU\Software\Classes\directory\shell\Rodeo 13 | - "/f" 14 | - 15 | - reg.exe 16 | - 17 | - delete 18 | - HKCU\Software\Classes\directory\background\shell\Rodeo 19 | - "/f" 20 | - 21 | - reg.exe 22 | - 23 | - delete 24 | - HKCU\Software\Classes\Applications\rodeo.exe 25 | - "/f" 26 | -------------------------------------------------------------------------------- /test/mocks/classes/child-process.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const EventEmitter = require('events'), 4 | stream = require('stream'); 5 | 6 | class MockChildProcess extends EventEmitter { 7 | constructor(options) { 8 | options = options || {}; 9 | super(); 10 | this.pid = options.pid || '123'; 11 | this.stdout = new stream.PassThrough(); 12 | this.stderr = new stream.PassThrough(); 13 | } 14 | kill() { 15 | this.emit('close', 'a', 'b'); 16 | } 17 | } 18 | 19 | module.exports = MockChildProcess; 20 | -------------------------------------------------------------------------------- /test/mocks/jupyter_examples/create_svg_1.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | 4 | plt.figure(figsize=[6,6]) 5 | x = np.arange(0,100,0.00001) 6 | y = x*np.sin(2*pi*x) 7 | plt.plot(y) 8 | plt.axis('off') 9 | plt.gca().set_position([0, 0, 1, 1]) 10 | plt.savefig("test.svg") 11 | -------------------------------------------------------------------------------- /test/mocks/jupyter_examples/create_svg_2.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import numpy as np 3 | x = np.arange(0,100,0.00001) 4 | y = x*np.sin(2*np.pi*x) 5 | plt.plot(y) 6 | plt.savefig("test.svg", format="svg") 7 | 8 | 9 | -------------------------------------------------------------------------------- /test/mocks/jupyter_examples/example_1.py: -------------------------------------------------------------------------------- 1 | %matplotlib inline 2 | import matplotlib.pyplot as plt 3 | from numpy import pi, exp, real, imag, linspace 4 | from ipywidgets import interact 5 | 6 | def f(t,a=1,b=6,c=-14,d=0): 7 | return exp(a*1j*t) - exp(b*1j*t)/2 + 1j*exp(c*1j*t)/3 + exp(d*1j*t)/4 8 | 9 | def plot_swirly(a=1,b=6,c=-14,d=0): 10 | t = linspace(0, 2*pi, 1000) 11 | ft = f(t,a,b,c,d) 12 | plt.plot(real(ft), imag(ft)) 13 | 14 | # These two lines make the aspect ratio square 15 | fig = plt.gcf() 16 | fig.set_size_inches(6, 6, forward='True') 17 | 18 | interact(plot_swirly,a=(-20,20),b=(-20,20),c=(-20,20),d=(-20,20)); 19 | -------------------------------------------------------------------------------- /test/mocks/jupyter_examples/example_2.py: -------------------------------------------------------------------------------- 1 | import numpy 2 | import toyplot 3 | 4 | x = numpy.linspace(0, 10) 5 | y = x ** 2 6 | 7 | canvas = toyplot.Canvas(width=300, height=300) 8 | axes = canvas.axes() 9 | mark = axes.plot(x, y) 10 | -------------------------------------------------------------------------------- /test/mocks/jupyter_examples/example_3.py: -------------------------------------------------------------------------------- 1 | import plotly 2 | import plotly.plotly as py 3 | import plotly.graph_objs as go 4 | from plotly.offline import download_plotlyjs, init_notebook_mode, iplot 5 | 6 | # Create random data with numpy 7 | import numpy as np 8 | 9 | init_notebook_mode() 10 | 11 | N = 1000 12 | random_x = np.random.randn(N) 13 | random_y = np.random.randn(N) 14 | 15 | # Create a trace 16 | trace = go.Scatter( 17 | x = random_x, 18 | y = random_y, 19 | mode = 'markers' 20 | ) 21 | 22 | data = [trace] 23 | iplot(data) -------------------------------------------------------------------------------- /test/mocks/jupyter_examples/example_4.py: -------------------------------------------------------------------------------- 1 | x = raw_input("heeey") 2 | print(x) # should print whatever you input 3 | -------------------------------------------------------------------------------- /test/mocks/jupyter_examples/example_5.py: -------------------------------------------------------------------------------- 1 | # This should cause a name error 2 | import numpy 3 | import toyplot 4 | 5 | x = numpy.linspace(0, 10) 6 | y = x ** 2 7 | 8 | mark = asdf.plot(x, y) -------------------------------------------------------------------------------- /test/mocks/jupyter_examples/example_6.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | ggplot(mtcars, aes(x='mpg')) + geom_histogram() + xlab("ㅍKorean!") -------------------------------------------------------------------------------- /test/mocks/jupyter_examples/example_7.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas 3 | columns = ['some', 'column', 'headers'] 4 | index = np.arange(103) # array of numbers for the number of samples 5 | df = pandas.DataFrame(columns=columns, index = index) -------------------------------------------------------------------------------- /test/mocks/jupyter_examples/example_8.py: -------------------------------------------------------------------------------- 1 | import pandas 2 | data = {'height' : [5.6, 7.0, 4.9, 6.7, 5.2, 5.5, 6.1, 5.4], 3 | 'age' : [15, 21, 15, 20, 22, 41, 18, 38]} 4 | z = pandas.DataFrame(data) 5 | 6 | data = {'what' : [5.6, 5.2, 5.5, 6.1, 5.4], 7 | 'where' : [15, 21, 15, 18, 38]} 8 | y = pandas.DataFrame(data) 9 | -------------------------------------------------------------------------------- /test/node/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const bluebird = require('bluebird'), 4 | chai = require('chai'), 5 | electron = require('electron'), 6 | ipcMainRemote = electron.remote.ipcMain; 7 | 8 | // output the logs to the console when running tests (in karma) 9 | ipcMainRemote.on('console-log', function (event, msg) { 10 | console.log(msg); 11 | }); 12 | 13 | bluebird.config({ 14 | warnings: true, 15 | longStackTraces: true, 16 | cancellation: true, 17 | monitoring: true 18 | }); 19 | 20 | // defaults for chai 21 | chai.config.showDiff = true; 22 | chai.config.truncateThreshold = 0; 23 | 24 | // jquery sees module and thinks it's not a browser 25 | window.$ = window.jQuery = require('../../node_modules/jquery/dist/jquery'); 26 | -------------------------------------------------------------------------------- /watch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | while [ 1 ] 4 | do 5 | # Every half second attempt to recompile the static assets. 6 | # make will only trigger if something has changed. 7 | sleep '0.5' 8 | make | grep -v 'Nothing to be done for `all.' 9 | done 10 | --------------------------------------------------------------------------------