├── .babelrc
├── .editorconfig
├── .eslintrc.js
├── .gitignore
├── .npmignore
├── .travis.yml
├── LICENSE
├── README.md
├── URLS.md
├── bin
├── hpc-cloud-cli.js
└── version-check.js
├── config
├── rules-hpccloud.js
├── rules-linter.js
├── rules-pvw.js
├── rules-simput.js
├── rules-visualizer.js
├── rules-vtkjs.js
└── rules-wslink.js
├── dist
├── 118340a95a86407d4fc9e909b4aca2a1.png
├── 375c2c36fbb31174fc0897d0a8d91d75.png
├── 5643cfd73c91bbeb1c64bde05cff8810.png
├── 674f50d287a8c48dc19ba404d20fe713.eot
├── 75b02d961c524e7c1a1634b6872d077b.png
├── 761f4850551f3c31781ca807a568c978.png
├── 89889688147bd7575d6327160d64e760.svg
├── 912ec66d7572ff821749319396470bde.svg
├── HPCCloud.js
├── af7ae505a9eed503f8b8e6982036873e.woff2
├── b06871f281fee6b241d60582ae9369b9.ttf
├── cbc255c4c8c2e98ecff13777f0a853e8.png
├── clusters-presets.json
├── e850e8c7537a93920bc7417f443b5931.png
├── ec2_instance_types.json
├── favicon.ico
├── fee66e712a8a08eef5805a46892932ad.woff
├── index.html
├── simput-nwchem-neb.js
├── simput-nwchem.js
├── simput-openfoam-tutorials.js
├── simput-openfoam-windtunnel.js
└── simput-pyfr.js
├── docs
├── .gitignore
├── config.js
├── content
│ ├── api
│ │ └── index.md
│ ├── docs
│ │ ├── development__dev-intro.md
│ │ ├── development__images
│ │ │ └── form-panels.png
│ │ ├── development__panels.md
│ │ ├── development__redux.md
│ │ ├── development__tools.md
│ │ ├── general__getting-started.md
│ │ ├── general__glossary.md
│ │ ├── general__troubleshooting.md
│ │ ├── index.md
│ │ ├── usage__aws-profiles.md
│ │ ├── usage__create-account.md
│ │ ├── usage__creating.md
│ │ ├── usage__ebs-volumes.md
│ │ ├── usage__images
│ │ │ ├── custom-consts.png
│ │ │ ├── prefs-aws.png
│ │ │ ├── prefs-trad.png
│ │ │ ├── sharing_groups.png
│ │ │ ├── sharing_project.png
│ │ │ ├── simput-complete.png
│ │ │ ├── simulation-create.png
│ │ │ ├── simulation-run.png
│ │ │ ├── simulation-view.png
│ │ │ └── simulation-viz.png
│ │ ├── usage__running.md
│ │ ├── usage__sharing.md
│ │ ├── usage__simput.md
│ │ ├── usage__trad-cluster.md
│ │ ├── vagrant__introduction.md
│ │ ├── workflows__adding.md
│ │ ├── workflows__introduction.md
│ │ └── workflows__pages.md
│ ├── icon
│ │ ├── favicon-160x160.png
│ │ ├── favicon-16x16.png
│ │ ├── favicon-196x196.png
│ │ ├── favicon-32x32.png
│ │ └── favicon-96x96.png
│ ├── index.jade
│ ├── logo.png
│ └── logo.svg
├── data
│ └── menu.yml
└── tpl
│ ├── __en__
│ └── __sidebar__
├── ec2_instance_types.py
├── package-lock.json
├── package.json
├── prettier.config.js
├── pvw-dependencies
├── pv-flow
│ ├── flow
│ │ ├── __init__.py
│ │ ├── api.py
│ │ ├── configs
│ │ │ ├── __init__.py
│ │ │ └── colorMaps.py
│ │ ├── plugins
│ │ │ ├── __init__.py
│ │ │ └── parflow.py
│ │ └── processing
│ │ │ ├── __init__.py
│ │ │ ├── engine.py
│ │ │ └── utils.py
│ └── pvw-flow.py
├── pv-lite
│ ├── lite_protocols.py
│ ├── proxies.json
│ └── pvw-lite.py
└── pvw-visualizer.py
├── requirements.txt
├── server
├── hpccloud
│ ├── hpccloud_plugin
│ │ ├── __init__.py
│ │ ├── constants.py
│ │ ├── file.py
│ │ ├── models
│ │ │ ├── __init__.py
│ │ │ ├── definitions.json
│ │ │ ├── project.json
│ │ │ ├── project.py
│ │ │ ├── schema.py
│ │ │ ├── simulation.json
│ │ │ └── simulation.py
│ │ ├── projects.py
│ │ ├── simulations.py
│ │ └── utility
│ │ │ └── __init__.py
│ ├── plugin.cmake
│ ├── plugin_tests
│ │ ├── __init__.py
│ │ ├── base.py
│ │ ├── file_test.py
│ │ ├── projects_test.py
│ │ ├── simulations_test.py
│ │ └── utility_test.py
│ └── setup.py
├── pvwproxy
│ ├── plugin.cmake
│ ├── plugin_tests
│ │ ├── __init__.py
│ │ └── proxy_test.py
│ ├── pvwproxy_plugin
│ │ ├── __init__.py
│ │ ├── constants.py
│ │ └── proxy.py
│ └── setup.py
└── taskflows
│ ├── hpccloud
│ ├── __init__.py
│ └── taskflow
│ │ ├── __init__.py
│ │ ├── nwchem
│ │ ├── __init__.py
│ │ └── neb.py
│ │ ├── openfoam
│ │ ├── __init__.py
│ │ ├── tutorial.py
│ │ └── windtunnel.py
│ │ ├── paraview
│ │ ├── __init__.py
│ │ ├── pv_flow.py
│ │ ├── pv_lite.py
│ │ ├── pvw.sh
│ │ └── visualizer.py
│ │ ├── pyfr
│ │ └── __init__.py
│ │ └── utility
│ │ └── __init__.py
│ ├── pyfr_params.json
│ └── runner.py
├── src
├── StateTransitionBehavior.js
├── app.js
├── config
│ └── routes.js
├── network
│ ├── helpers
│ │ ├── clusters.js
│ │ ├── notifications.js
│ │ ├── projects.js
│ │ └── simulations.js
│ ├── index.js
│ └── remote
│ │ ├── GirderClient.js
│ │ ├── assetstore.js
│ │ ├── aws.js
│ │ ├── clusters.js
│ │ ├── collection.js
│ │ ├── file.js
│ │ ├── folder.js
│ │ ├── group.js
│ │ ├── item.js
│ │ ├── jobs.js
│ │ ├── projects.js
│ │ ├── resource.js
│ │ ├── simulations.js
│ │ ├── system.js
│ │ ├── taskflows.js
│ │ ├── tasks.js
│ │ ├── user.js
│ │ ├── utils.js
│ │ └── volumes.js
├── pages
│ ├── AuthContent
│ │ └── index.js
│ ├── Forgot
│ │ └── index.js
│ ├── HPCCloud
│ │ └── index.js
│ ├── Landing
│ │ └── index.js
│ ├── Login
│ │ └── index.js
│ ├── Logout
│ │ └── index.js
│ ├── Preferences
│ │ ├── AWS
│ │ │ ├── AWSForm.js
│ │ │ └── index.js
│ │ ├── Cluster
│ │ │ ├── ClusterForm.js
│ │ │ └── index.js
│ │ ├── Groups
│ │ │ ├── GroupForm.js
│ │ │ └── index.js
│ │ ├── Network
│ │ │ └── index.js
│ │ ├── PresetSelector.js
│ │ ├── ServerStatus
│ │ │ ├── ClusterStatus.js
│ │ │ └── index.js
│ │ ├── User
│ │ │ ├── ChangeInfo.js
│ │ │ ├── ChangePassword.js
│ │ │ └── index.js
│ │ ├── Volumes
│ │ │ ├── VolumeForm.js
│ │ │ └── index.js
│ │ └── index.js
│ ├── Project
│ │ ├── All
│ │ │ └── index.js
│ │ ├── Edit
│ │ │ └── index.js
│ │ ├── New
│ │ │ └── index.js
│ │ └── View
│ │ │ └── index.js
│ ├── Register
│ │ └── index.js
│ └── Simulation
│ │ ├── Edit
│ │ └── index.js
│ │ ├── New
│ │ └── index.js
│ │ └── View
│ │ └── index.js
├── panels
│ ├── ActiveList
│ │ └── index.js
│ ├── AuthRoute
│ │ └── index.js
│ ├── Breadcrumb
│ │ └── index.js
│ ├── ButtonBar
│ │ └── index.js
│ ├── EmptyPlaceholder
│ │ └── index.js
│ ├── FileListing
│ │ ├── FilePreview.js
│ │ └── index.js
│ ├── FormPanel
│ │ ├── CheckboxInput.js
│ │ ├── EnumInput.js
│ │ ├── ProfileInput.js
│ │ ├── TextInput.js
│ │ └── index.js
│ ├── IconActionList
│ │ └── index.js
│ ├── ImageIcon
│ │ └── index.js
│ ├── ItemEditor
│ │ └── index.js
│ ├── JobMonitor
│ │ ├── ExecutionUnit.js
│ │ ├── LogFold.js
│ │ └── index.js
│ ├── LinkIcon
│ │ └── index.js
│ ├── LoadingPanel
│ │ └── index.js
│ ├── OutputPanel
│ │ └── index.js
│ ├── SchedulerConfig
│ │ ├── PBS.js
│ │ ├── SGE.js
│ │ ├── SLURM.js
│ │ └── index.js
│ ├── SharePanel
│ │ ├── PermissionPanel.js
│ │ └── index.js
│ ├── Switch
│ │ └── index.js
│ ├── TableListing
│ │ └── index.js
│ ├── Toaster
│ │ └── index.js
│ ├── Toolbar
│ │ └── index.js
│ └── run
│ │ ├── RunCluster.js
│ │ ├── RunEC2.js
│ │ ├── defaults.js
│ │ └── index.js
├── redux
│ ├── README.md
│ ├── actions
│ │ ├── aws.js
│ │ ├── clusters.js
│ │ ├── fs.js
│ │ ├── groups.js
│ │ ├── history.js
│ │ ├── network.js
│ │ ├── progress.js
│ │ ├── projects.js
│ │ ├── statuses.js
│ │ ├── taskflows.js
│ │ ├── user.js
│ │ └── volumes.js
│ ├── index.js
│ └── reducers
│ │ ├── ListActiveMapByIdHelper.js
│ │ ├── auth.js
│ │ ├── aws.js
│ │ ├── clusters.js
│ │ ├── fs.js
│ │ ├── groups.js
│ │ ├── index.js
│ │ ├── network.js
│ │ ├── preferences.js
│ │ ├── progress.js
│ │ ├── projects.js
│ │ ├── simulations.js
│ │ ├── statuses.js
│ │ ├── taskflows.js
│ │ └── volumes.js
├── tools
│ ├── index.js
│ └── visualizer
│ │ └── index.js
├── utils
│ ├── AccessHelper.js
│ ├── ClusterPayload.js
│ ├── Constants.js
│ ├── Filters.js
│ ├── Format.js
│ ├── Helper.js
│ ├── get.js
│ ├── getDisabledButtons.js
│ ├── getNetworkError.js
│ └── logSort.js
└── workflows
│ ├── generic
│ └── components
│ │ ├── root
│ │ ├── AttachedFileListing.js
│ │ ├── EditProjectWithFileListing.js
│ │ ├── EditSimulationWithFileListing.js
│ │ └── ViewSimulation.js
│ │ └── steps
│ │ ├── DocumentationHTML.js
│ │ ├── JobMonitoring.js
│ │ ├── JobSubmission.js
│ │ └── SimputReact.js
│ ├── index.js
│ ├── nwchem
│ ├── common
│ │ └── steps
│ │ │ ├── Introduction
│ │ │ ├── content.html
│ │ │ └── index.js
│ │ │ └── Simulation
│ │ │ ├── Start.js
│ │ │ └── View.js
│ ├── nwchem-exec
│ │ ├── components
│ │ │ └── root
│ │ │ │ └── NewSimulation.js
│ │ ├── index.js
│ │ └── logo.png
│ ├── nwchem-neb
│ │ ├── components
│ │ │ ├── root
│ │ │ │ └── NewProject.js
│ │ │ └── steps
│ │ │ │ ├── Input.js
│ │ │ │ ├── SimulationView.js
│ │ │ │ └── Visualization.js
│ │ ├── index.js
│ │ └── logo.png
│ └── nwchem-simput
│ │ ├── components
│ │ ├── root
│ │ │ └── NewProject.js
│ │ └── steps
│ │ │ └── Input.js
│ │ ├── index.js
│ │ └── logo.png
│ ├── openfoam
│ ├── tutorials
│ │ ├── components
│ │ │ └── steps
│ │ │ │ ├── Input
│ │ │ │ └── index.js
│ │ │ │ ├── Introduction
│ │ │ │ ├── content.html
│ │ │ │ └── index.js
│ │ │ │ ├── Simulation
│ │ │ │ ├── Start.js
│ │ │ │ └── View.js
│ │ │ │ └── Visualization
│ │ │ │ ├── Start.js
│ │ │ │ └── View.js
│ │ ├── index.js
│ │ └── logo.png
│ └── windtunnel
│ │ ├── components
│ │ ├── root
│ │ │ └── NewProject.js
│ │ └── steps
│ │ │ ├── Geometry
│ │ │ ├── Geometry.mcss
│ │ │ └── index.js
│ │ │ ├── Input
│ │ │ └── index.js
│ │ │ ├── Introduction
│ │ │ ├── content.html
│ │ │ └── index.js
│ │ │ ├── Simulation
│ │ │ ├── Start.js
│ │ │ └── View.js
│ │ │ └── Visualization
│ │ │ ├── Start.js
│ │ │ └── View.js
│ │ ├── index.js
│ │ └── logo.png
│ ├── pyfr
│ ├── components
│ │ ├── panels
│ │ │ └── RuntimeBackend.js
│ │ ├── root
│ │ │ ├── NewProject.js
│ │ │ └── NewSimulation.js
│ │ └── steps
│ │ │ ├── Input
│ │ │ └── index.js
│ │ │ ├── Introduction
│ │ │ ├── content.html
│ │ │ └── index.js
│ │ │ ├── Simulation
│ │ │ ├── Start.js
│ │ │ └── View.js
│ │ │ └── Visualization
│ │ │ ├── Start.js
│ │ │ └── View.js
│ ├── index.js
│ └── logo.png
│ └── visualizer
│ ├── components
│ ├── root
│ │ └── NewSimulation.js
│ └── steps
│ │ ├── Introduction
│ │ ├── content.html
│ │ └── index.js
│ │ └── Visualization
│ │ ├── Start.js
│ │ └── View.js
│ ├── index.js
│ └── logo.png
├── style
├── ActiveList.mcss
├── ItemEditor.mcss
├── JobMonitor.mcss
├── Layout.mcss
├── Login.mcss
├── Modal.mcss
├── PageWithMenu.mcss
├── Preferences.mcss
├── Profile.mcss
├── States.mcss
├── TableListing.mcss
├── Theme.mcss
├── Toaster.mcss
├── Toolbar.mcss
├── Visualizer.mcss
├── global.mcss
├── logo-mono.png
└── logo.svg
├── test
├── README.md
├── components
│ ├── AccessHelper.js
│ ├── ButtonBar.js
│ ├── ExecutionUnit.js
│ ├── Format.js
│ ├── RunForm.js
│ └── get.js
├── config
│ ├── karma.base.js
│ └── webpack.test.js
├── contexts
│ ├── tests.all.js
│ ├── tests.components.js
│ └── tests.redux.js
├── helpers
│ ├── complete.js
│ ├── deepFreeze.js
│ └── workflowNames.js
├── karma.all.js
├── karma.component.js
├── karma.redux.js
├── redux
│ ├── StateTransitionBehavior.js
│ ├── aws.js
│ ├── clusters.js
│ ├── fs.js
│ ├── groups.js
│ ├── network.js
│ ├── projects.js
│ ├── statuses.js
│ ├── taskflows.js
│ ├── users.js
│ └── volumes.js
└── sampleData
│ ├── awsClusters.js
│ ├── awsState.js
│ ├── basicFullState.js
│ ├── basicTaskflowState.js
│ ├── machines.js
│ ├── projectsData.js
│ ├── runFormState.js
│ └── simulationsForProj1.js
└── webpack.config.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | presets: [
3 | 'react',
4 | ['env', {
5 | targets: {
6 | browsers: ['last 2 versions'],
7 | },
8 | }],
9 | ],
10 | }
11 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 | root = true
3 |
4 | [*]
5 | trim_trailing_whitespace = true
6 | indent_size = 2
7 | indent_style = space
8 |
9 | [*.js]
10 | indent_style = space
11 | indent_size = 2
12 | end_of_line = lf
13 | charset = utf-8
14 | trim_trailing_whitespace = true
15 | insert_final_newline = true
16 |
17 | [*.py]
18 | indent_style = space
19 | indent_size = 4
20 | charset = utf-8
21 | trim_trailing_whitespace = true
22 | insert_final_newline = true
23 | max_line_length = 80
24 |
25 | [*.md]
26 | trim_trailing_whitespace = false
27 | indent_size = 2
28 | indent_style = space
29 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | var prettierConf = require('./prettier.config.js');
2 |
3 | module.exports = {
4 | extends: ['airbnb', 'prettier'],
5 | rules: {
6 | 'prettier/prettier': ['error', prettierConf],
7 |
8 | // But we want the following
9 | 'no-multi-spaces': ["error", { exceptions: { "ImportDeclaration": true } }],
10 | 'no-param-reassign': ["error", { props: false }],
11 | 'no-unused-vars': ["error", { args: 'none' }],
12 | 'prefer-destructuring': ["error", { VariableDeclarator: { array: false, object: true }, AssignmentExpression: { array: false, object: false } }, { enforceForRenamedProperties: false }],
13 | 'import/no-extraneous-dependencies': 0, // Needed for tests
14 | // 'no-mixed-operators': 'error', // Wish we can put it back with prettier
15 |
16 | // Not for us
17 | 'jsx-a11y/label-has-for': 0,
18 | 'no-console': 0,
19 | 'no-plusplus': 0,
20 | 'import/no-named-as-default': 0,
21 | 'import/no-named-as-default-member': 0,
22 | 'prefer-destructuring': 0, // Can have unwanted side effect
23 | 'react/jsx-filename-extension': 0,
24 | 'jsx-a11y/no-static-element-interactions': 0,
25 | 'jsx-a11y/click-events-have-key-events': 0,
26 | 'jsx-a11y/no-noninteractive-element-interactions': 0,
27 | 'jsx-a11y/no-autofocus': 0,
28 | 'jsx-a11y/anchor-is-valid': 0,
29 |
30 | // Introduced with new eslint
31 | // and no time to fix them...
32 | // [...]
33 | 'linebreak-style': 0,
34 | 'no-useless-escape': 0,
35 | 'no-nested-ternary': 0,
36 | 'react/forbid-prop-types': 0,
37 | 'react/no-array-index-key': 0,
38 | 'no-underscore-dangle': 0,
39 | 'import/prefer-default-export': 0,
40 | 'prefer-promise-reject-errors': 0,
41 | },
42 | plugins: [
43 | 'prettier'
44 | ],
45 | globals: {
46 | __BASE_PATH__: false,
47 | VRFrameData: true,
48 | },
49 | 'settings': {
50 | 'import/resolver': 'webpack'
51 | },
52 | env: {
53 | es6: true,
54 | browser: true,
55 | },
56 | };
57 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .npmrc
3 | .sass-cache
4 | bundles
5 | node_modules/
6 | npm-debug.log
7 | *.pyc
8 | .project
9 | .pydevproject
10 | .settings/
11 | coverage/
12 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | docs
2 | .travis.yml
3 | .gitmodule
4 | .npmrc
5 | site.config.js
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # HPCCloud
2 |
3 | [](https://codecov.io/github/Kitware/HPCCloud?branch=master)
4 | [](https://travis-ci.org/Kitware/HPCCloud)
5 | [](https://david-dm.org/kitware/hpc-cloud)
6 | [](https://github.com/semantic-release/semantic-release)
7 | 
8 | 
9 | 
10 |
11 | ### Goal
12 |
13 | Web interface to the HPCCloud infrastructure that abstract simulation
14 | environment and resources on which you can run those simulations.
15 |
16 | ## Installation
17 |
18 | Observe the instructions for [HPCCloud deploy](https://github.com/Kitware/HPCCloud-deploy);
19 |
20 | ## Development
21 |
22 | ```sh
23 | $ git clone https://github.com/Kitware/HPCCloud.git
24 | $ cd HPCCloud
25 | $ npm install
26 | $ npm start
27 | ```
28 |
29 | ## Troubleshooting
30 |
31 | (With the vm running from HPCCloud-Deploy)
32 | ```sh
33 | $ vagrant ssh
34 | $ sudo -iu hpccloud
35 | ```
36 |
37 | ### Fixing celery Girder URL
38 |
39 | ```sh
40 | $ vi /opt/hpccloud/cumulus/cumulus/conf/config.json
41 | +-> Fix host to be localhost
42 | +-> baseUrl: "http://localhost:8080/api/v1",
43 | $ sudo service celeryd restart
44 | ```
45 |
46 | ## Documentation
47 |
48 | See the [documentation](docs/README.md) in this repository for a
49 | getting started guide, advanced documentation, and workflow descriptions.
50 |
51 | ## Licensing
52 |
53 | **HPCCloud** is licensed under [Apache 2](LICENSE).
54 |
55 | ## Getting Involved
56 |
57 | Fork our repository and do great things. At [Kitware](http://www.kitware.com),
58 | we've been contributing to open-source software for 15 years and counting, and we
59 | want to make **hpc-cloud** useful to as many people as possible.
60 |
--------------------------------------------------------------------------------
/URLS.md:
--------------------------------------------------------------------------------
1 | # HPCCloud urls
2 |
3 | ## Unauthenticated
4 |
5 | - / : Welcome page explaing what HPCCloud is and giving access to /login and /register
6 | - /Login : Login page
7 | - /Register : SignIn page
8 |
9 | ## Authenticated
10 |
11 | ### Path /
12 |
13 | List user projects with possible filter query like (filter=type:pyfr&txt=blabla)
14 |
15 | ### Path /New
16 |
17 | Page for creating a new project.
18 |
19 | ### Path /Edit/:type/:projectId[/:simulationId]
20 |
21 | Edit pages for project or simulation
22 |
23 | ### Path /View/:type/:projectId
24 |
25 | List simulation associated to a given project. Possible filtering via query.
26 |
27 | ### Path /View/:type/:projectId/:simulationId/:currentStep
28 |
29 | View a given simulation at its current step. If currentStep not provided, then
30 | we assume currentStep=0 which could be an introduction page.
31 |
32 | Additional 'heavy view' could be selected from the URL via query like the
33 | following set of examples:
34 |
35 | - /pyfr/2346efw45ytwef/drh5r6hwe345twre/3?view=MeshTagger
36 | - /pyfr/2346efw45ytwef/drh5r6hwe345twre/3?view=Visualizer
37 |
38 | ### Path /Preferences
39 |
40 | Should show the set of configurations we can perform such as:
41 |
42 | - User
43 | - Clusters
44 | - AWS
45 | - OpenStack
46 |
47 | ### Path /Preferences/:type
48 |
49 | Type can be one of [ User, Clusters, AWS, OpenStack ].
50 |
51 |
52 | ### Path /Preferences/Clusters/:activeName/:activeProfile
53 |
54 |
55 | ## Sharing work and data
56 |
57 | ### Sharing a project
58 |
59 | Sharing a project means that each simulation within that project is visible to
60 | the set of users we shared with but those simulations can only be cloned.
61 |
62 | Only owned simulation can be edited, ran, exported or visualized.
63 |
64 | ### Exporting data
65 |
66 | A simulation can be exported which means exported the input desk with any other input data such as a mesh. This should allow the creation of a new project with a pre-filled simulation that could be re-run.
67 |
68 | Exporting a simulation
69 |
70 | - Project data ( such as a mesh )
71 | - Input configuration ( such as mesh tagging and input deck )
72 | - Results
73 |
74 |
--------------------------------------------------------------------------------
/bin/hpc-cloud-cli.js:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env node
2 |
3 | var fs = require('fs'),
4 | path = require('path'),
5 | program = require('commander'),
6 | paraview = process.env.PARAVIEW_HOME;
7 |
8 | require('shelljs/global');
9 |
10 | program
11 | .version('1.0.0')
12 | .option('-p, --port [8080]', 'Start web server with given port', 8080)
13 | .option('-s, --server-only', 'Do not open the web browser\n')
14 |
15 | .parse(process.argv);
16 |
17 | if (!process.argv.slice(2).length) {
18 | program.outputHelp();
19 | process.exit(0);
20 | }
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/bin/version-check.js:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env node
2 |
3 | var version = process.versions.node.split('.').map(Number);
4 | if (version[0] > 0 || version[0] === 0 && version[1] >= 12) {
5 | process.exit(0);
6 | }
7 |
8 | console.log('incompatible version, HPC-Cloud requires >=0.12.0 ');
9 | process.exit(1);
10 |
--------------------------------------------------------------------------------
/config/rules-hpccloud.js:
--------------------------------------------------------------------------------
1 | const autoprefixer = require('autoprefixer');
2 |
3 | module.exports = [
4 | {
5 | test: /\.js$/,
6 | exclude: /node_modules/,
7 | use: [
8 | {
9 | loader: 'babel-loader',
10 | options: {
11 | presets: ['env', 'react'],
12 | },
13 | },
14 | ],
15 | },
16 | {
17 | test: /\.mcss$/,
18 | use: [
19 | { loader: 'style-loader' },
20 | {
21 | loader: 'css-loader',
22 | options: {
23 | localIdentName: '[name]-[local]_[sha512:hash:base32:5]',
24 | modules: true,
25 | },
26 | },
27 | {
28 | loader: 'postcss-loader',
29 | options: {
30 | plugins: () => [autoprefixer('last 2 version', 'ie >= 10')],
31 | },
32 | },
33 | ],
34 | },
35 | {
36 | test: /\.html$/,
37 | loader: 'html-loader',
38 | },
39 | {
40 | test: /\.isvg$/,
41 | loader: 'html-loader?attrs=false',
42 | },
43 | {
44 | test: /\.svg$/,
45 | loader: 'svg-sprite-loader',
46 | exclude: /fonts/,
47 | },
48 | {
49 | test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
50 | loader: 'url-loader?limit=60000&mimetype=application/font-woff',
51 | },
52 | {
53 | test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
54 | loader: 'url-loader?limit=60000',
55 | include: /fonts/,
56 | },
57 | {
58 | test: /\.(png|jpg)$/,
59 | loader: 'url-loader?limit=8192',
60 | },
61 | {
62 | test: /\.css$/,
63 | use: [
64 | { loader: 'style-loader' },
65 | { loader: 'css-loader' },
66 | {
67 | loader: 'postcss-loader',
68 | options: {
69 | plugins: () => [autoprefixer('last 2 version', 'ie >= 10')],
70 | },
71 | },
72 | ],
73 | },
74 | ];
75 |
--------------------------------------------------------------------------------
/config/rules-linter.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | const eslintrcPath = path.join(__dirname, '../.eslintrc.js');
4 |
5 | module.exports = [
6 | {
7 | test: /\.js$/,
8 | exclude: /node_modules/,
9 | loader: 'eslint-loader',
10 | enforce: 'pre',
11 | options: { configFile: eslintrcPath },
12 | },
13 | ];
14 |
--------------------------------------------------------------------------------
/config/rules-pvw.js:
--------------------------------------------------------------------------------
1 | const autoprefixer = require('autoprefixer');
2 |
3 | module.exports = [
4 | {
5 | test: /\.js$/,
6 | include: /node_modules(\/|\\)paraviewweb(\/|\\)/,
7 | use: [
8 | {
9 | loader: 'babel-loader',
10 | options: {
11 | presets: ['env', 'react'],
12 | },
13 | },
14 | ],
15 | },
16 | {
17 | test: /\.c$/i,
18 | include: /node_modules(\/|\\)paraviewweb(\/|\\)/,
19 | loader: 'shader-loader',
20 | },
21 | ];
22 |
--------------------------------------------------------------------------------
/config/rules-simput.js:
--------------------------------------------------------------------------------
1 | module.exports = [
2 | {
3 | test: /\.js$/,
4 | include: /node_modules(\/|\\)simput(\/|\\)/,
5 | use: [
6 | {
7 | loader: 'babel-loader',
8 | options: {
9 | presets: ['env', 'react'],
10 | },
11 | },
12 | ],
13 | },
14 | ];
15 |
--------------------------------------------------------------------------------
/config/rules-visualizer.js:
--------------------------------------------------------------------------------
1 | module.exports = [
2 | {
3 | test: /\.js$/,
4 | include: /node_modules(\/|\\)pvw-visualizer(\/|\\)/,
5 | use: [
6 | {
7 | loader: 'babel-loader',
8 | options: {
9 | presets: ['env', 'react'],
10 | },
11 | },
12 | ],
13 | },
14 | ];
15 |
--------------------------------------------------------------------------------
/config/rules-vtkjs.js:
--------------------------------------------------------------------------------
1 | module.exports = [
2 | {
3 | test: /\.glsl$/i,
4 | include: /node_modules(\/|\\)vtk.js(\/|\\)/,
5 | loader: 'shader-loader',
6 | },
7 | {
8 | test: /\.js$/,
9 | include: /node_modules(\/|\\)vtk.js(\/|\\)/,
10 | use: [
11 | {
12 | loader: 'babel-loader',
13 | options: {
14 | presets: ['env'],
15 | },
16 | },
17 | ],
18 | },
19 | ];
20 |
--------------------------------------------------------------------------------
/config/rules-wslink.js:
--------------------------------------------------------------------------------
1 | module.exports = [
2 | {
3 | test: /\.js$/,
4 | include: /node_modules(\/|\\)wslink(\/|\\)/,
5 | use: [
6 | {
7 | loader: 'babel-loader',
8 | options: {
9 | presets: ['env'],
10 | },
11 | },
12 | ],
13 | },
14 | ];
15 |
--------------------------------------------------------------------------------
/dist/118340a95a86407d4fc9e909b4aca2a1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/dist/118340a95a86407d4fc9e909b4aca2a1.png
--------------------------------------------------------------------------------
/dist/375c2c36fbb31174fc0897d0a8d91d75.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/dist/375c2c36fbb31174fc0897d0a8d91d75.png
--------------------------------------------------------------------------------
/dist/5643cfd73c91bbeb1c64bde05cff8810.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/dist/5643cfd73c91bbeb1c64bde05cff8810.png
--------------------------------------------------------------------------------
/dist/674f50d287a8c48dc19ba404d20fe713.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/dist/674f50d287a8c48dc19ba404d20fe713.eot
--------------------------------------------------------------------------------
/dist/75b02d961c524e7c1a1634b6872d077b.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/dist/75b02d961c524e7c1a1634b6872d077b.png
--------------------------------------------------------------------------------
/dist/761f4850551f3c31781ca807a568c978.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/dist/761f4850551f3c31781ca807a568c978.png
--------------------------------------------------------------------------------
/dist/af7ae505a9eed503f8b8e6982036873e.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/dist/af7ae505a9eed503f8b8e6982036873e.woff2
--------------------------------------------------------------------------------
/dist/b06871f281fee6b241d60582ae9369b9.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/dist/b06871f281fee6b241d60582ae9369b9.ttf
--------------------------------------------------------------------------------
/dist/cbc255c4c8c2e98ecff13777f0a853e8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/dist/cbc255c4c8c2e98ecff13777f0a853e8.png
--------------------------------------------------------------------------------
/dist/e850e8c7537a93920bc7417f443b5931.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/dist/e850e8c7537a93920bc7417f443b5931.png
--------------------------------------------------------------------------------
/dist/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/dist/favicon.ico
--------------------------------------------------------------------------------
/dist/fee66e712a8a08eef5805a46892932ad.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/dist/fee66e712a8a08eef5805a46892932ad.woff
--------------------------------------------------------------------------------
/dist/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | HPCCloud
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/docs/.gitignore:
--------------------------------------------------------------------------------
1 | build-tmp
2 |
--------------------------------------------------------------------------------
/docs/config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | cname: 'kitware.github.io',
3 | baseUrl: '/HPCCloud',
4 | work: './build-tmp',
5 | api: ['../src'],
6 | examples: [],
7 | config: {
8 | title: 'HPCCloud',
9 | description: '"Run your simulation workflow in the Web"',
10 | subtitle: '"Enable HPC resources via Web interactions."',
11 | author: 'Kitware Inc.',
12 | timezone: 'UTC',
13 | url: 'https://kitware.github.io/HPCCloud',
14 | root: '/HPCCloud/',
15 | github: 'kitware/HPCCloud',
16 | google_analytics: 'UA-90338862-3',
17 | },
18 | copy: [],
19 | };
20 |
--------------------------------------------------------------------------------
/docs/content/api/index.md:
--------------------------------------------------------------------------------
1 | title: API
2 | ---
3 |
4 | NO API
5 |
--------------------------------------------------------------------------------
/docs/content/docs/development__images/form-panels.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/docs/content/docs/development__images/form-panels.png
--------------------------------------------------------------------------------
/docs/content/docs/development__tools.md:
--------------------------------------------------------------------------------
1 | # Tools
2 |
3 | Tools are external . They are shown from the `simulation/view` page with this line:
4 |
5 | ```js
6 | const ChildComponent = tools[viewName] ? tools[viewName].view : wfModule.components.ViewSimulation;
7 | ```
8 |
9 | Tools are bundled in `src/tools/index.js` each tool has a `view` which is the primary view container for the tool and `providesToolbar` a boolean which prevents displaying a double toolbar. Feel free to add other properties to make your tool more accessible, such properties could include `requiresFullscreen` or `openInNewWindow`
10 |
11 | ## View container
12 |
13 | While the tool itself does not need to be integrated with the Redux store, the container does. To pass the necessary information to your tool you'll want to include the important information in the step metadata. We do this with the [`sessionId`](https://github.com/Kitware/HPCCloud/blob/master/src/workflows/pyfr/common/steps/Visualization/Start/index.js#L74-L86) for steps that use the Paraview Web Visualizer.
14 |
15 | ## Redux
16 |
17 | It is not necessary for your tool to use Redux. However if it does you'll need to provide accessor methods to override which state it operates on, see the [Paraview Web Visualizer repository](https://github.com/Kitware/visualizer) for an example how to do this. You'll also need to combine the reducers with HPCCloud's reducers.
--------------------------------------------------------------------------------
/docs/content/docs/general__glossary.md:
--------------------------------------------------------------------------------
1 | # Terminology
2 |
3 | ### Jobs
4 |
5 | Jobs, or Primary Jobs, are special types of tasks running on an HPC resource.
6 |
7 | ### Tasks
8 |
9 | Tasks are any thing run within simulations.
10 |
11 | ### Taskflow
12 |
13 | Taskflows are collections of tasks run to orchestrate a given simulation workflow.
14 |
15 | ### Workflow
16 |
17 | Workflows are collections of steps which define some pattern for executing a process.
18 |
19 | ### Projects
20 |
21 | Projects are collections of simulations.
22 |
23 | ### Simulations
24 |
25 | Simulations are collections of taskflows.
26 |
27 | ### Clusters
28 |
29 | Clusters are any machine that you can run jobs on.
30 |
31 | ### Traditional Clusters
32 |
33 | Traditional cluster are dedicated HPC resources, usually based on physical hardware.
34 |
35 | ### AWS Profile
36 |
37 | AWS (Amazon Web Services) profiles consist of a Access key and a Secret key with which a user can provision EC2 instances.
38 |
39 | ### EC2 Instances
40 |
41 | EC2 Instances are virtual machines running on [Amazon's EC2](https://aws.amazon.com/ec2/).
42 |
43 | ### ParaViewWeb
44 |
45 | ParaViewWeb is a tool in Paraview which allows a user to use ParaView through a web browser.
46 |
47 | ### Simput
48 |
49 | A simulation deck input tool. Consult the [Simput GitHub repository](https://github.com/Kitware/simput) for more.
50 |
51 | ### Simulation step
52 |
53 | Simulation steps symbolize different taskflows within a simulation. They can have different states aswell. For example many steps have the substeps "Start" which starts a taskflow and "View" which views logs and statuses for the taskflow.
54 |
--------------------------------------------------------------------------------
/docs/content/docs/general__troubleshooting.md:
--------------------------------------------------------------------------------
1 | # Troubleshooting
2 |
3 | ## Development
4 |
5 | ### A front-end feature I added is not showing up
6 |
7 | Make sure that `npm start` is running and are you visiting the right address: `localhost:9999`. `localhost:8888` is the server version on the VM.
8 |
9 | ### A workflow I added is not showing up in the project options
10 |
11 | Make sure that you're importing your workflow description to `src/workflows/index.js` and exporting as a property of the variable `Workflows`. If this has not fixed it, make sure that the environment variable `NODE_ENV` is __not__ set to `test` the workflows directory will be ignored if it is.
12 |
13 | ### Cannot login
14 |
15 | Make sure that girder is running on the target server. If it is running and you still cannot login, try restarting girder with `sudo service girder restart`. If you still cannot login, make sure your login exists and the `vagrant up` in HPCCloud-deploy ran successfully.
16 |
17 | ### Cannot connect to the Visualizer tool
18 |
19 | Make sure that in `cumulus/cumulus/conf/config.json` the parameter `girder.baseUrl` matches the IP of the machine you're accessing the task from. User and group should be "cumulus".
20 |
--------------------------------------------------------------------------------
/docs/content/docs/index.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | HPCCloud is a web-based simulation environment platform that utilizes web technologies to deliver an innovative, interactive SaaS advanced modeling and simulation environment.
4 |
5 | It allows simulation workflows to be developed that leverage HPC resources. The workflows are presented through a simple intuitive UI, shielding the user from much of the complexity associated with using a HPC resource.
6 |
7 | HPCCloud supports both "traditional" HPC resources (that can be accessed using ssh key-based authentication) as well as the creation of on demand clusters in Amazon's Elastic Compute Cloud (EC2). See the [white paper](http://ieeexplore.ieee.org/xpl/login.jsp?tp=&arnumber=7396134&url=http%3A%2F%2Fieeexplore.ieee.org%2Fxpls%2Fabs_all.jsp%3Farnumber%3D7396134) for more.
8 |
9 | We currently have support for a couple of workflows:
10 |
11 | - [PyFR](http://www.pyfr.org) is an open-source simulation code for solving advection-diffusion type problems. Our workflow includes input desk generation, executing PyFR and post-processing using [ParaViewWeb](http://www.paraview.org/web/). See [Running simulation workflows](usage__running.html) for same usage using PyFR.
12 | - [ParaViewWeb](http://www.paraview.org/web/) is an open-source visualization application. ParaView can be used to quickly build visualizations using qualitative and quantitative techniques. ParaView can be exposed to the Web using ParaViewWeb. Our worflow allows a data file to be uploaded and then visualized using the full power of ParaView.
13 |
--------------------------------------------------------------------------------
/docs/content/docs/usage__create-account.md:
--------------------------------------------------------------------------------
1 | # Account Creation & Login
2 |
3 | ## Registration
4 |
5 | With HPCCloud up and running:
6 |
7 | 1. Click on 'Register' link in the top right.
8 | 2. Fill out the form. If you wish, you can change your first name, last name, and password on the preferences page.
9 | 3. Click the register button, if successful you'll be redirected to the login page.
10 |
11 | ## Login
12 |
13 | 1. Click on the 'Login' link on the top right.
14 | 2. Fill in your credentials
15 | 3. Click login, if successful you'll be redirected to the projects page.
16 |
17 | ## Logout
18 |
19 | When logged in, from any page:
20 |
21 | 1. Click on the Logout icon on the top right of the page.
22 |
--------------------------------------------------------------------------------
/docs/content/docs/usage__creating.md:
--------------------------------------------------------------------------------
1 | # Creating Projects and Simulations
2 |
3 | ## Projects
4 |
5 | Projects contain simulations of a certain type. Go to `/` or click on the HPC-Cloud logo to go to the projects page.
6 |
7 | ### Creating
8 |
9 | Click on the "+" icon on the top right in the toolbar, this will take you to a new page. Name and describe your project on this page. Depending on the project type, you may also need to upload some files required for simulations. Name your project and add a description if desired. Click "Create Project" and after your file(s) upload you'll be taken to the simulations page for your new project.
10 |
11 | ### Editing
12 | If you named or described your project incorrectly click on the pen icon on the homepage and modify these attributes. You cannot reupload files if the project required any.
13 |
14 | ### Deleting
15 |
16 | You can only delete projects which have no simulations associated with them. Click on the pen icon for a project and you'll be taken to the edit page. Clicking the "Delete project" button will delete the project, you will be prompted beforehand.
17 |
18 | ## Simulations
19 |
20 | Simulations represent collections of taskflows depending on the type of parent project.
21 |
22 | ### Creating
23 |
24 | Again click on the "+" icon in the toolbar, it's in the same place as the "+" you clicked to create a project. As with projects, you'll be taken to a new page where you can name and describe your simulation as well as upload any files that may be required. Click "Create Simulation" and you'll be taken to your simulation's introduction page.
25 |
26 | ### Editing
27 |
28 | If you named or described your simulation incorrectly click on the pen icon on the `view/projects/{projectId}` page and modify these attributes. You cannot reupload files if the simulation required any.
29 |
30 | ### Deleting
31 |
32 | You can only delete simulations which are not running. On `view/projects/{projectId}` page, the click on the pen icon for a simulation and you'll be taken to the edit page. Clicking on the "Delete simulation" will delete the simulation, you will be prompted beforehand.
33 |
--------------------------------------------------------------------------------
/docs/content/docs/usage__ebs-volumes.md:
--------------------------------------------------------------------------------
1 | # EBS Volumes
2 |
3 | Complementing the ability to create and run simulations on AWS EC2 instances, HPCCloud also supports mounting of AWS Elastic Block Store (EBS) volumes to provide input and to store output for these simulations. Volumes can also be reused between EC2 instances. For example, you could run a resource intensive simulation on a large expensive cluster and map its output to a EBS volume. You could then use that same volume as input for a visualization job on a smaller cluster which is not as expensive.
4 |
5 | ## Creating New Volumes
6 |
7 | There are two methods to create new volumes. Through the preference panel and a taskflow run:
8 |
9 | ### Preferences Panel
10 |
11 | Volumes created here are not instantiated on AWS but are available to select when starting a new taskflow. To create one you need a valid AWS profile already created and available.
12 |
13 | ### Taskflow Run
14 |
15 | On a run panel there are three fields for volumes, these fields are only available on the with EC2 server type is selected. You can either select an existing volume or you can create a new one by specifying the name and the size. Existing volumes have either been used in previous taskflows or were created from the Preference panel, they must be in the detached or available state. If you provide a volume name and size a volume will be created and attached to the cluster.
16 |
17 | ## Removing Volumes
18 |
19 | To remove a volume the volume needs to be in either the detached or available state. You do so from the volume preference page with the delete button.
--------------------------------------------------------------------------------
/docs/content/docs/usage__images/custom-consts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/docs/content/docs/usage__images/custom-consts.png
--------------------------------------------------------------------------------
/docs/content/docs/usage__images/prefs-aws.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/docs/content/docs/usage__images/prefs-aws.png
--------------------------------------------------------------------------------
/docs/content/docs/usage__images/prefs-trad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/docs/content/docs/usage__images/prefs-trad.png
--------------------------------------------------------------------------------
/docs/content/docs/usage__images/sharing_groups.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/docs/content/docs/usage__images/sharing_groups.png
--------------------------------------------------------------------------------
/docs/content/docs/usage__images/sharing_project.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/docs/content/docs/usage__images/sharing_project.png
--------------------------------------------------------------------------------
/docs/content/docs/usage__images/simput-complete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/docs/content/docs/usage__images/simput-complete.png
--------------------------------------------------------------------------------
/docs/content/docs/usage__images/simulation-create.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/docs/content/docs/usage__images/simulation-create.png
--------------------------------------------------------------------------------
/docs/content/docs/usage__images/simulation-run.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/docs/content/docs/usage__images/simulation-run.png
--------------------------------------------------------------------------------
/docs/content/docs/usage__images/simulation-view.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/docs/content/docs/usage__images/simulation-view.png
--------------------------------------------------------------------------------
/docs/content/docs/usage__images/simulation-viz.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/docs/content/docs/usage__images/simulation-viz.png
--------------------------------------------------------------------------------
/docs/content/docs/usage__sharing.md:
--------------------------------------------------------------------------------
1 | # Groups and Project Sharing
2 |
3 | ## Groups
4 |
5 | Groups are collections of users that can have their own permissions assigned. Only admin users can create and manage groups. This is done through the Groups panel on the Preferences page.
6 |
7 | 
8 |
9 | ## Project Sharing
10 |
11 | Only a project owner can share projects and the corresponding simulations with groups and individual users. The sharing panel can be reached by going to the Edit panel for each project or simulation.
12 |
13 | 
14 |
15 | Sharing a project with users or groups also shares the simulations and the corresponding taskflows within. You can share individual simulations with users and groups as well, doing so will share the parent project but only the shared simulation will be visible to the sharees.
16 |
17 | Level of access per project and simulation can also be set. The possible values are Read, Write, and Admin. Beware setting admin permissions to groups and users on the project level as they will have access to all containing simulations and files.
18 |
--------------------------------------------------------------------------------
/docs/content/docs/usage__trad-cluster.md:
--------------------------------------------------------------------------------
1 | # Traditional Clusters
2 |
3 | Traditional clusters, or simply "clusters" in this document typically involve physical hardware dedicated to running simulations within the host operating system. To get to the page for Traditional Clusters go to the preferences page -by clicking on the username in the top right- and click "Cluster."
4 |
5 | ## Creating
6 |
7 | Click the "+" icon in the toolbar. You'll be presented a blank form in which you can fill out details of your cluster. A cluster name, username and hostname of the machine is required. When you have the necessary fields filled out click "Save." A "Test" button and a form field with an shell command containing an ssh key will soon appear.
8 |
9 | 
10 |
11 | ### Testing
12 |
13 | Copy the shell command from the form field and paste it in a terminal. The command tries to connect to your cluster and if successful adds an ssh key to the cluster's key chain. This permits HPC-Cloud's backend (Cumulus) to connect to your cluster and run jobs and simulations. Click the "Test" button when the command is run and the key is saved on your cluster. If the test is successful cluster is ready to use in simulations.
14 |
15 | ## Editing
16 | You can only edit the name of a cluster. If you need to change another detail delete and recreate the cluster.
17 |
18 | ## Deleting
19 |
20 | You cannot delete clusters which are running simulations. With the cluster you want to delete selected, click "Delete cluster." You will be prompted before the cluster is deleted. You can always re-add a deleted cluster, however the files generated from simulations will not be available through HPC-Cloud.
21 |
--------------------------------------------------------------------------------
/docs/content/docs/workflows__introduction.md:
--------------------------------------------------------------------------------
1 | # Introduction
2 |
3 | Workflows are the meat of HPCCloud. They are the means and ways which the application provides interfaces for creating and monitoring simulations and jobs. On a more abstract level, workflows are steps which define some pattern for executing a process. Before developing workflows consult the development introduction.
--------------------------------------------------------------------------------
/docs/content/icon/favicon-160x160.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/docs/content/icon/favicon-160x160.png
--------------------------------------------------------------------------------
/docs/content/icon/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/docs/content/icon/favicon-16x16.png
--------------------------------------------------------------------------------
/docs/content/icon/favicon-196x196.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/docs/content/icon/favicon-196x196.png
--------------------------------------------------------------------------------
/docs/content/icon/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/docs/content/icon/favicon-32x32.png
--------------------------------------------------------------------------------
/docs/content/icon/favicon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/docs/content/icon/favicon-96x96.png
--------------------------------------------------------------------------------
/docs/content/index.jade:
--------------------------------------------------------------------------------
1 | layout: index
2 | description: HPC simulations from your browser
3 | subtitle: Simplify HPC workflows and infrastructure management
4 | comments: false
5 | ---
6 |
7 | ul#intro-feature-list
8 | li.intro-feature-wrap
9 | .intro-feature
10 | .intro-feature-icon
11 | i.fa.fa-cloud-download
12 | h3.intro-feature-title
13 | a(href="http://www.kitware.com/products/support.html").link Releases
14 | p.intro-feature-desc HPCCloud can be deployed on your infrastructure or leverage EC2 hardwares.
15 |
16 | li.intro-feature-wrap
17 | .intro-feature
18 | .intro-feature-icon
19 | i.fa.fa-life-ring
20 | h3.intro-feature-title
21 | a(href="http://www.kitware.com/products/support.html").link Support and Services
22 | p.intro-feature-desc Kitware offers advanced software R&D solutions and services. Find out how we can help with your next project.
23 |
--------------------------------------------------------------------------------
/docs/content/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/docs/content/logo.png
--------------------------------------------------------------------------------
/docs/content/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
10 |
11 |
12 |
14 |
16 |
17 |
22 |
23 |
--------------------------------------------------------------------------------
/docs/data/menu.yml:
--------------------------------------------------------------------------------
1 | docs: /docs/
2 |
--------------------------------------------------------------------------------
/docs/tpl/__en__:
--------------------------------------------------------------------------------
1 | menu:
2 | docs: Docs
3 | api: API
4 | examples: Examples
5 | news: News
6 | search: Search
7 |
8 | index:
9 | get_started: Get started
10 |
11 | page:
12 | contents: Contents
13 | back_to_top: Back to Top
14 | improve: Improve this doc
15 | prev: Prev
16 | next: Next
17 | last_updated: "Last updated: %s"
18 |
19 | sidebar:
20 | docs:
21 | general: Basics
22 | general__introduction: Introduction
23 | general__getting-started: Getting Started
24 | general__glossary: Glossary
25 | general__troubleshooting: Troubleshooting
26 | usage: Usage
27 | usage__create-account: Signing up
28 | usage__trad-cluster: Adding traditional clusters
29 | usage__aws-profiles: Adding AWS profiles
30 | usage__ebs-volumes: Adding EBS volumes
31 | usage__creating: Projects and simulations
32 | usage__simput: Simput
33 | usage__running: Running workflows
34 | usage__sharing: Groups and project sharing
35 | development: Development
36 | development__dev-intro: Introduction
37 | development__panels: Panels
38 | development__redux: Redux data model
39 | development__tools: Available tools
40 | vagrant__introduction: Vagrant - How to...
41 | workflows: Workflows
42 | workflows__introduction: Introduction
43 | workflows__adding: Workflow definition
44 | workflows__pages: Workflow pages
45 |
--------------------------------------------------------------------------------
/docs/tpl/__sidebar__:
--------------------------------------------------------------------------------
1 | docs:
2 | general:
3 | general__introduction: index.html
4 | general__getting-started: general__getting-started.html
5 | general__troubleshooting: general__troubleshooting.html
6 | general__glossary: general__glossary.html
7 | usage:
8 | usage__create-account: usage__create-account.html
9 | usage__trad-cluster: usage__trad-cluster.html
10 | usage__aws-profiles: usage__aws-profiles.html
11 | usage__ebs-volumes: usage__ebs-volumes.html
12 | usage__creating: usage__creating.html
13 | usage__simput: usage__simput.html
14 | usage__running: usage__running.html
15 | usage__sharing: usage__sharing.html
16 | development:
17 | development__dev-intro: development__dev-intro.html
18 | development__panels: development__panels.html
19 | development__redux: development__redux.html
20 | development__tools: development__tools.html
21 | vagrant__introduction: vagrant__introduction.html
22 | workflows:
23 | workflows__introduction: workflows__introduction.html
24 | workflows__adding: workflows__adding.html
25 | workflows__pages: workflows__pages.html
26 |
--------------------------------------------------------------------------------
/prettier.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | printWidth: 80,
3 | singleQuote: true,
4 | trailingComma: 'es5',
5 | arrowParens: 'always',
6 | };
7 |
--------------------------------------------------------------------------------
/pvw-dependencies/pv-flow/flow/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/pvw-dependencies/pv-flow/flow/__init__.py
--------------------------------------------------------------------------------
/pvw-dependencies/pv-flow/flow/configs/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/pvw-dependencies/pv-flow/flow/configs/__init__.py
--------------------------------------------------------------------------------
/pvw-dependencies/pv-flow/flow/plugins/__init__.py:
--------------------------------------------------------------------------------
1 | import os
2 | from paraview import simple
3 |
4 | # -----------------------------------------------------------------------------
5 |
6 | MODULE_PATH = os.path.dirname(os.path.abspath(__file__))
7 |
8 | PLUGINS = [
9 | 'parflow.py'
10 | ]
11 |
12 | FULL_PATHS = [
13 | '/Applications/ParaView-5.6.0-1626-g52acf2f741.app/Contents/Plugins/ParFlow.so',
14 | ]
15 |
16 | # -----------------------------------------------------------------------------
17 | # Load the plugins
18 | # -----------------------------------------------------------------------------
19 |
20 | for plugin in PLUGINS:
21 | simple.LoadPlugin(os.path.join(MODULE_PATH, plugin))
22 |
23 | for plugin in FULL_PATHS:
24 | simple.LoadPlugin(plugin)
25 |
--------------------------------------------------------------------------------
/pvw-dependencies/pv-flow/flow/processing/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/pvw-dependencies/pv-flow/flow/processing/__init__.py
--------------------------------------------------------------------------------
/pvw-dependencies/pv-flow/flow/processing/utils.py:
--------------------------------------------------------------------------------
1 | # =============================================================================
2 | # Helper methods
3 | # =============================================================================
4 |
5 | def histToArray(histogramFilter, field, dataRange, nbBins):
6 | binSpan = (dataRange[1] - dataRange[0]) / nbBins
7 | bins = []
8 | histogramFilter.BinCount = nbBins + 2
9 | histogramFilter.SelectInputArray = ['POINTS', field]
10 | histogramFilter.CustomBinRanges = [dataRange[0] - binSpan, dataRange[1] + binSpan]
11 | histogramFilter.UpdatePipeline()
12 |
13 | ds = histogramFilter.GetClientSideObject().GetOutput()
14 | array = ds.GetColumn(1) # 'bin_values'
15 |
16 | if array:
17 | for i in range(1, nbBins + 1, 1):
18 | bins.append(array.GetValue(i))
19 |
20 | return bins
21 |
--------------------------------------------------------------------------------
/pvw-dependencies/pv-lite/proxies.json:
--------------------------------------------------------------------------------
1 | {
2 | "sources": [
3 | { "name": "AnnotateTime", "label": "Annotate Time" },
4 | { "name": "Cone" },
5 | { "name": "Sphere" },
6 | { "name": "Text" },
7 | { "name": "Wavelet" },
8 | { "name": "Box" },
9 | { "name": "Cylinder" }
10 | ],
11 |
12 | "filters": [
13 | { "name": "Calculator" },
14 | { "name": "CellDatatoPointData", "label": "Cell Data To Point Data" },
15 | { "name": "Clip" },
16 | { "name": "Contour" },
17 | { "name": "D3" },
18 | { "name": "ExtractCTHParts" },
19 | { "name": "ProcessIdScalars" },
20 | { "name": "Reflect" },
21 | { "name": "Slice" },
22 | { "name": "StreamTracer" },
23 | { "name": "Threshold" },
24 | { "name": "Transform" },
25 | { "name": "Tube" },
26 | { "name": "Ribbon" },
27 | { "name": "WarpByScalar", "label": "Warp By Scalar" },
28 | { "name": "WarpByVector", "label": "Warp By Vector" },
29 | { "name": "ExtractBlock", "label": "Extract Blocks" }
30 | ],
31 |
32 | "readers": [
33 | { "name": "LegacyVTKReader", "extensions": [ "vtk" ], "method": "FileNames" },
34 | { "name": "VERAOUTReader", "extensions": [ "h5" ], "method": "FileName" }
35 | ]
36 | }
37 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | jsonschema==2.4.0
2 | jsonpath-rw==1.4.0
3 | jsonpath-rw-ext==1.2.0
4 | lockfile==0.10.2
5 | requests==2.21.0
6 |
--------------------------------------------------------------------------------
/server/hpccloud/hpccloud_plugin/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | ###############################################################################
5 | # Copyright 2015 Kitware Inc.
6 | #
7 | # Licensed under the Apache License, Version 2.0 ( the "License" );
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 | ###############################################################################
19 |
20 | from girder.plugin import GirderPlugin
21 | from girder.utility.model_importer import ModelImporter
22 |
23 | from .projects import Projects
24 | from .simulations import Simulations
25 | from . import file
26 |
27 | from .models.project import Project as ProjectModel
28 | from .models.simulation import Simulation as SimulationModel
29 |
30 | class HPCCloudPlugin(GirderPlugin):
31 | DISPLAY_NAME = 'HPCCloud plugin for Girder'
32 |
33 | def load(self, info):
34 | ModelImporter.registerModel('project', ProjectModel, 'hpccloud')
35 | ModelImporter.registerModel('simulation', SimulationModel, 'hpccloud')
36 |
37 | info['apiRoot'].projects = Projects()
38 | info['apiRoot'].simulations = Simulations()
39 | file.load(info['apiRoot'])
40 |
--------------------------------------------------------------------------------
/server/hpccloud/hpccloud_plugin/constants.py:
--------------------------------------------------------------------------------
1 | SIMULATIONS_FOLDER = '_simulations'
2 |
--------------------------------------------------------------------------------
/server/hpccloud/hpccloud_plugin/models/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/server/hpccloud/hpccloud_plugin/models/__init__.py
--------------------------------------------------------------------------------
/server/hpccloud/hpccloud_plugin/models/definitions.json:
--------------------------------------------------------------------------------
1 | {
2 | "objectId": {
3 | "type": "string",
4 | "pattern": "^[a-f\\d]{24}$"
5 | },
6 | "arrayOfIds": {
7 | "type": "array",
8 | "items": {
9 | "$ref": "#/objectId"
10 | }
11 | },
12 | "step": {
13 | "type": "object",
14 | "required": ["type"],
15 | "additionalProperties": false,
16 | "properties": {
17 | "type": {
18 | "enum": ["input", "output", "information"]
19 | },
20 | "status": {
21 | "$ref": "#/stepStatus"
22 | },
23 | "view": {
24 | "type": "string"
25 | },
26 | "folderId": {
27 | },
28 | "metadata": {
29 | "type": "object"
30 | },
31 | "export": {
32 | "type": "array",
33 | "item": {
34 | "$ref": "#/objectId"
35 | }
36 | }
37 | }
38 | },
39 | "stepUpdate": {
40 | "type": "object",
41 | "additionalProperties": false,
42 | "properties": {
43 | "status": {
44 | "$ref": "#/stepStatus"
45 | },
46 | "metadata": {
47 | "type": "object"
48 | },
49 | "export": {
50 | "type": "array",
51 | "items": {
52 | "$ref": "#/objectId"
53 | }
54 | },
55 | "view": {
56 | "type": "string"
57 | }
58 | }
59 | },
60 | "stepStatus": {
61 | "enum": ["created", "complete"]
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/server/hpccloud/hpccloud_plugin/models/project.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json-schema.org/draft-04/schema#",
3 | "type": "object",
4 | "id":"#project",
5 | "required": ["name", "type", "steps"],
6 | "additionalProperties": false,
7 | "properties": {
8 | "name": {
9 | "type": "string"
10 | },
11 | "description": {
12 | "type": "string"
13 | },
14 | "type": {
15 | "type": "string"
16 | },
17 | "steps": {
18 | "type": "array",
19 | "items": {
20 | "type": "string"
21 | },
22 | "minItems": 1,
23 | "uniqueItems": true
24 | },
25 | "metadata": {
26 | "type": "object"
27 | },
28 | "folderId": {
29 |
30 | },
31 | "access": {
32 |
33 | },
34 | "userId": {
35 |
36 | },
37 | "_id": {
38 |
39 | },
40 | "created": {
41 |
42 | },
43 | "updated": {
44 |
45 | }
46 | },
47 | "definitions": {
48 | "share": {
49 | "type": "object",
50 | "properties": {
51 | "users": {
52 | "$ref": "#/arrayOfIds"
53 | },
54 | "groups": {
55 | "$ref": "#/arrayOfIds"
56 | },
57 | "level": {
58 | "type": "number",
59 | "minimum": -1,
60 | "maximum": 2,
61 | "default": 0
62 | },
63 | "flags": {
64 | "type": "array",
65 | "items": {
66 | "type": "string",
67 | "minItems": 0
68 | },
69 | "default": []
70 | }
71 | },
72 | "additionalProperties": false
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/server/hpccloud/hpccloud_plugin/models/schema.py:
--------------------------------------------------------------------------------
1 | import json
2 | import os
3 |
4 |
5 | project_schema_filepath = os.path.join(
6 | os.path.dirname(__file__), 'project.json')
7 | simulation_schema_filepath = os.path.join(
8 | os.path.dirname(__file__), 'simulation.json')
9 | definitions_schema_filepath = os.path.join(
10 | os.path.dirname(__file__), 'definitions.json')
11 |
12 | with open(project_schema_filepath) as fp:
13 | project = json.load(fp)
14 |
15 | with open(simulation_schema_filepath) as fp:
16 | simulation = json.load(fp)
17 |
18 | with open(definitions_schema_filepath) as fp:
19 | definitions = json.load(fp)
20 |
--------------------------------------------------------------------------------
/server/hpccloud/plugin.cmake:
--------------------------------------------------------------------------------
1 | add_python_test(file PLUGIN hpccloud)
2 | add_python_test(projects PLUGIN hpccloud)
3 | add_python_test(simulations PLUGIN hpccloud)
4 | add_python_test(utility PLUGIN hpccloud)
5 | add_python_style_test(python_static_analysis_hpccloud "${PROJECT_SOURCE_DIR}/plugins/hpccloud/server")
6 |
--------------------------------------------------------------------------------
/server/hpccloud/plugin_tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/server/hpccloud/plugin_tests/__init__.py
--------------------------------------------------------------------------------
/server/hpccloud/plugin_tests/base.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | ###############################################################################
5 | # Copyright 2016 Kitware Inc.
6 | #
7 | # Licensed under the Apache License, Version 2.0 ( the "License" );
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 | ###############################################################################
19 |
20 | from tests import base
21 |
22 |
23 | class TestCase(base.TestCase):
24 |
25 | def create_file(self, user, item, name, contents, assetstoreId=None):
26 | params = {
27 | 'parentType': 'item',
28 | 'parentId': item['_id'],
29 | 'name': name,
30 | 'size': len(contents),
31 | 'mimeType': 'application/octet-stream',
32 | }
33 | if (assetstoreId is not None):
34 | params['assetstoreId'] = assetstoreId
35 | r = self.request(
36 | path='/file', method='POST', user=user, params=params)
37 | self.assertStatusOk(r)
38 | upload = r.json
39 |
40 | # Upload some content
41 | fields = [('offset', 0), ('uploadId', upload['_id'])]
42 | files = [('chunk', name, contents)]
43 | r = self.multipartRequest(
44 | path='/file/chunk', user=user, fields=fields, files=files)
45 | self.assertStatusOk(r)
46 |
47 | return r.json
48 |
49 |
50 |
--------------------------------------------------------------------------------
/server/hpccloud/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup, find_packages
2 |
3 | setup(
4 | name='hpccloud-plugin',
5 | version='1.0.0',
6 | description='Girder plugin to support HPCCloud projects and simulations',
7 | packages=find_packages(),
8 | install_requires=[
9 | 'girder>=3.0.0a5'
10 | ],
11 | entry_points={
12 | 'girder.plugin': [
13 | 'hpccloud_plugin = hpccloud_plugin:HPCCloudPlugin'
14 | ]
15 | }
16 | )
17 |
--------------------------------------------------------------------------------
/server/pvwproxy/plugin.cmake:
--------------------------------------------------------------------------------
1 | add_python_test(proxy PLUGIN pvwproxy)
2 | add_python_style_test(python_static_analysis_pvwproxy "${PROJECT_SOURCE_DIR}/plugins/pvwproxy/server")
3 |
4 |
--------------------------------------------------------------------------------
/server/pvwproxy/plugin_tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/server/pvwproxy/plugin_tests/__init__.py
--------------------------------------------------------------------------------
/server/pvwproxy/pvwproxy_plugin/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | ###############################################################################
5 | # Copyright 2015 Kitware Inc.
6 | #
7 | # Licensed under the Apache License, Version 2.0 ( the "License" );
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 | ###############################################################################
19 |
20 |
21 | from girder import events
22 | from girder.plugin import GirderPlugin
23 | from .proxy import Proxy
24 |
25 | from . import constants
26 |
27 |
28 | def validate_settings(event):
29 | key = event.info['key']
30 |
31 | if key == constants.PluginSettings.PROXY_FILE_PATH:
32 | event.preventDefault().stopPropagation()
33 |
34 | class PVWProxyPlugin(GirderPlugin):
35 | DISPLAY_NAME = 'PVWProxyPlugin plugin for Girder'
36 |
37 | def load(self, info):
38 | events.bind('model.setting.validate', 'pvwproxy', validate_settings)
39 | info['apiRoot'].proxy = Proxy()
40 |
--------------------------------------------------------------------------------
/server/pvwproxy/pvwproxy_plugin/constants.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | ###############################################################################
5 | # Copyright 2015 Kitware Inc.
6 | #
7 | # Licensed under the Apache License, Version 2.0 ( the "License" );
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 | ###############################################################################
19 |
20 |
21 | class PluginSettings:
22 | PROXY_FILE_PATH = 'pvwproxy.proxy_file_path'
23 |
--------------------------------------------------------------------------------
/server/pvwproxy/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup, find_packages
2 |
3 | setup(
4 | name='pvwproxy-plugin',
5 | version='1.0.0',
6 | description='Exposes REST api to add entries to ParaViewWebs proxy file',
7 | packages=find_packages(),
8 | install_requires=[
9 | 'girder>=3.0.0a5'
10 | ],
11 | entry_points={
12 | 'girder.plugin': [
13 | 'pvwproxy_plugin = pvwproxy_plugin:PVWProxyPlugin'
14 | ]
15 | }
16 | )
17 |
--------------------------------------------------------------------------------
/server/taskflows/hpccloud/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/server/taskflows/hpccloud/__init__.py
--------------------------------------------------------------------------------
/server/taskflows/hpccloud/taskflow/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/server/taskflows/hpccloud/taskflow/__init__.py
--------------------------------------------------------------------------------
/server/taskflows/hpccloud/taskflow/nwchem/neb.py:
--------------------------------------------------------------------------------
1 | import cumulus.taskflow.cluster
2 | from cumulus.taskflow.cluster import create_girder_client
3 | from cumulus.tasks.job import submit_job, _monitor_jobs
4 | from cumulus.tasks.job import download_job_input_folders
5 | from cumulus.tasks.job import upload_job_output_to_folder, job_directory
6 | from cumulus.transport import get_connection
7 | from . import setup_input, create_job, submit, submit_nwchem_job, \
8 | monitor_nwchem_job, upload_output
9 |
10 |
11 | from hpccloud.taskflow.utility import *
12 |
13 | import sys
14 |
15 | class NWChemTaskFlow(cumulus.taskflow.cluster.ClusterProvisioningTaskFlow):
16 | """
17 | {
18 | "input": {
19 | "folder": {
20 | "id":
21 | }
22 | "nwFile":
23 | {
24 | "id":
25 | }
26 | },
27 | "output": {
28 | "folder": {
29 | "id":
30 | }
31 | },
32 | "cluster": {
33 | "_id":
34 | },
35 | "numberOfSlots":
36 | }
37 | """
38 | NWCHEM_IMAGE = {
39 | 'name': 'NWChem_ParaView-5.0.1',
40 | 'owner': '695977956746'
41 | }
42 |
43 | def start(self, *args, **kwargs):
44 | kwargs['image_spec'] = self.NWCHEM_IMAGE
45 |
46 | kwargs['next'] = (
47 | setup_input.s() | \
48 | create_job.s() | \
49 | submit.s() | \
50 | submit_nwchem_job.s() | \
51 | monitor_nwchem_job.s().set(queue='monitor') | \
52 | upload_output.s() )
53 |
54 | super(NWChemTaskFlow, self).start(self, *args, **kwargs)
55 |
--------------------------------------------------------------------------------
/server/taskflows/hpccloud/taskflow/openfoam/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/server/taskflows/hpccloud/taskflow/openfoam/__init__.py
--------------------------------------------------------------------------------
/server/taskflows/hpccloud/taskflow/paraview/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/server/taskflows/hpccloud/taskflow/paraview/__init__.py
--------------------------------------------------------------------------------
/server/taskflows/hpccloud/taskflow/utility/__init__.py:
--------------------------------------------------------------------------------
1 | import json
2 | from jsonpath_rw import parse
3 |
4 | import cumulus
5 |
6 | def get_cluster_job_output_dir(cluster):
7 | job_output_dir \
8 | = parse('config.jobOutputDir').find(cluster)
9 | if job_output_dir:
10 | job_output_dir = job_output_dir[0].value
11 | else:
12 | job_output_dir = None
13 |
14 | return job_output_dir
15 |
16 | def has_gpus(cluster):
17 | """
18 | :param cluster: The cluster passed by the client. Either an created cluster
19 | contain a _id or one contain a machine field specify the machine
20 | type.
21 | :type cluster: dict
22 | :returns: True is cluster nodes have GPUs, false otherwise.
23 | """
24 |
25 | # First check machine spec
26 | gpu = parse('machine.gpu').find(cluster)
27 |
28 | if not gpu:
29 | # Check launch parameters
30 | gpu = parse('config.launch.params.gpu').find(cluster)
31 |
32 | return gpu and int(gpu[0].value) > 0
33 |
--------------------------------------------------------------------------------
/server/taskflows/pyfr_params.json:
--------------------------------------------------------------------------------
1 | {
2 | "input": {
3 | "folder": {
4 | "id": "56bddb500640fd3957f7493c"
5 | },
6 | "meshFile": {
7 | "id": "56bddbf30640fd3957f74943"
8 | }
9 | },
10 | "output": {
11 | "folder": {
12 | "id": "56bddb550640fd3957f7493d"
13 | }
14 | },
15 | "cluster": {
16 | "_id": "56bddafb0640fd3957f74937"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/network/helpers/clusters.js:
--------------------------------------------------------------------------------
1 | import girder from '../';
2 |
3 | export function saveCluster(cluster) {
4 | if (cluster._id) {
5 | return girder.updateCluster(cluster);
6 | }
7 | return girder.createCluster(cluster);
8 | }
9 |
--------------------------------------------------------------------------------
/src/network/helpers/notifications.js:
--------------------------------------------------------------------------------
1 | import Monologue from 'monologue.js';
2 |
3 | class Observable {}
4 | Monologue.mixInto(Observable);
5 |
6 | const notification = new Observable();
7 | const SIMULATION_CHANGE = 'data.simulation.change';
8 | const PROJECT_CHANGE = 'data.project.change';
9 |
10 | export function invalidateSimulation(simulation) {
11 | notification.emit(SIMULATION_CHANGE, simulation);
12 | }
13 |
14 | export function onSimulationChange(cb) {
15 | return notification.on(SIMULATION_CHANGE, cb);
16 | }
17 |
18 | export function invalidateProject(project) {
19 | notification.emit(PROJECT_CHANGE, project);
20 | }
21 |
22 | export function onProjectChange(cb) {
23 | return notification.on(PROJECT_CHANGE, cb);
24 | }
25 |
--------------------------------------------------------------------------------
/src/network/index.js:
--------------------------------------------------------------------------------
1 | import assetstore from './remote/assetstore';
2 | import aws from './remote/aws';
3 | import clusters from './remote/clusters';
4 | import collection from './remote/collection';
5 | import file from './remote/file';
6 | import folder from './remote/folder';
7 | import group from './remote/group';
8 | import item from './remote/item';
9 | import jobs from './remote/jobs';
10 | import projects from './remote/projects';
11 | import resource from './remote/resource';
12 | import simulations from './remote/simulations';
13 | import system from './remote/system';
14 | import taskflows from './remote/taskflows';
15 | import tasks from './remote/tasks';
16 | import user from './remote/user';
17 | import volumes from './remote/volumes';
18 |
19 | import ClientBuilder from './remote/GirderClient';
20 |
21 | const endpoints = [
22 | assetstore,
23 | aws,
24 | clusters,
25 | collection,
26 | file,
27 | folder,
28 | group,
29 | item,
30 | jobs,
31 | projects,
32 | resource,
33 | simulations,
34 | system,
35 | taskflows,
36 | tasks,
37 | user,
38 | volumes,
39 | ];
40 |
41 | let url;
42 | if (process.env.NODE_ENV === 'test') {
43 | url = {
44 | protocol: 'http:',
45 | hostname: 'test',
46 | port: 80,
47 | };
48 | } else {
49 | url = window.location;
50 | }
51 |
52 | const girderClient = ClientBuilder.build(url, endpoints);
53 |
54 | export default girderClient;
55 |
--------------------------------------------------------------------------------
/src/network/remote/assetstore.js:
--------------------------------------------------------------------------------
1 | export default function({
2 | client,
3 | filterQuery,
4 | mustContain,
5 | busy,
6 | encodeQueryAsString,
7 | }) {
8 | return {
9 | listAssetStores(query = {}) {
10 | const expected = ['limit', 'offset', 'sort', 'sortdir'];
11 | const params = filterQuery(query, ...expected);
12 |
13 | return client._.get('/assetstore', { params });
14 | },
15 |
16 | createAssetStore(assetstore) {
17 | const required = ['name', 'type'];
18 | const possible = [
19 | 'root',
20 | 'db',
21 | 'bucket',
22 | 'prefix',
23 | 'accessKeyId',
24 | 'secretKey',
25 | 'service',
26 | ];
27 | const params = filterQuery(assetstore, ...[].concat(required, possible));
28 | const { missingKeys, promise } = mustContain(assetstore, ...required);
29 |
30 | return missingKeys
31 | ? promise
32 | : busy(client._.post(`/assetstore${encodeQueryAsString(params)}`));
33 | },
34 |
35 | updateAssetStore(assetstore) {
36 | const expected = ['name', 'root', 'db', 'current', '_id'];
37 | const params = filterQuery(
38 | assetstore,
39 | expected.slice(0, expected.length - 1)
40 | ); // Remove 'id'
41 |
42 | return client._.put(`/assetstore/${assetstore._id}`, { params });
43 | },
44 |
45 | deleteAssetStore(id) {
46 | return client._.delete(`/assetstore/${id}`);
47 | },
48 | };
49 | }
50 |
--------------------------------------------------------------------------------
/src/network/remote/collection.js:
--------------------------------------------------------------------------------
1 | export default function({
2 | client,
3 | filterQuery,
4 | mustContain,
5 | busy,
6 | encodeQueryAsString,
7 | }) {
8 | return {
9 | listCollections(query = {}) {
10 | const expected = ['text', 'limit', 'offset', 'sort', 'sortdir'];
11 | const params = filterQuery(query, ...expected);
12 |
13 | return client._.get('/collection', { params });
14 | },
15 |
16 | createCollection(collection) {
17 | const expected = ['name', 'description', 'public'];
18 | const params = filterQuery(collection, ...expected);
19 | const { missingKeys, promise } = mustContain(params, ...expected);
20 |
21 | return missingKeys
22 | ? promise
23 | : busy(client._.post(`/collection${encodeQueryAsString(params)}`));
24 | },
25 |
26 | deleteCollection(id) {
27 | return busy(client._.delete(`/collection/${id}`));
28 | },
29 |
30 | getCollection(id) {
31 | return busy(client._.get(`/collection/${id}`));
32 | },
33 |
34 | editCollection(collection = {}) {
35 | const expected = ['name', 'description'];
36 | const params = filterQuery(collection, ...expected);
37 | const { missingKeys, promise } = mustContain(collection, '_id');
38 |
39 | return missingKeys
40 | ? promise
41 | : busy(
42 | client._.put(
43 | `/collection/${collection._id}${encodeQueryAsString(params)}`
44 | )
45 | );
46 | },
47 |
48 | getCollectionAccess(id) {
49 | return busy(client._.get(`/collection/${id}/access`));
50 | },
51 |
52 | editCollectionAccess(collection) {
53 | const expected = ['access', 'public'];
54 | const params = filterQuery(collection, ...expected);
55 | const { missingKeys, promise } = mustContain(collection, '_id');
56 |
57 | return missingKeys
58 | ? promise
59 | : busy(
60 | client._.put(
61 | `/collection/${collection._id}/access${encodeQueryAsString(
62 | params
63 | )}`
64 | )
65 | );
66 | },
67 | };
68 | }
69 |
--------------------------------------------------------------------------------
/src/network/remote/jobs.js:
--------------------------------------------------------------------------------
1 | export default function({ client, filterQuery, mustContain, busy }) {
2 | return {
3 | // GET /jobs List all jobs for a given user
4 | getJobs(offset, limit) {
5 | if (offset && limit) {
6 | return busy(client._.get(`/jobs?offset=${offset}&limit=${limit}`));
7 | } else if (offset) {
8 | return busy(client._.get(`/jobs?offset=${offset}`));
9 | } else if (limit) {
10 | return busy(client._.get(`/jobs?limit=${limit}`));
11 | }
12 |
13 | return busy(client._.get('/jobs'));
14 | },
15 |
16 | // POST /jobs Create a new job
17 | createJob(params) {
18 | return busy(client._.post('/jobs', params));
19 | },
20 |
21 | // GET /jobs/{id} Get a job
22 | getJob(id) {
23 | return busy(client._.post(`/jobs/${id}`));
24 | },
25 |
26 | // PATCH /jobs/{id} Update the job
27 | updateJob(id, params) {
28 | return busy(client._.patch(`/jobs/${id}`, params));
29 | },
30 |
31 | // DELETE /jobs/{id} Delete a job
32 | deleteJob(id) {
33 | return busy(client._.delete(`/jobs/${id}`));
34 | },
35 |
36 | // GET /jobs/{id}/log Get log entries for job
37 | getJobLog(id, offset) {
38 | if (offset) {
39 | return busy(client._.get(`/jobs/${id}/log?offset=${offset}`));
40 | }
41 | return busy(client._.get(`/jobs/${id}/log`));
42 | },
43 |
44 | // GET /jobs/{id}/output Get output entries for job
45 | getJobOutput(id, path, offset) {
46 | if (offset) {
47 | return busy(
48 | client._.get(`/jobs/${id}/output?path=${path}&offset=${offset}`)
49 | );
50 | }
51 | return busy(client._.get(`/jobs/${id}/output?path=${path}`));
52 | },
53 |
54 | // GET /jobs/{id}/status Get the status of a job
55 | getJobStatus(id) {
56 | return busy(client._.get(`/jobs/${id}/status`));
57 | },
58 |
59 | // PUT /jobs/{id}/terminate Terminate a job
60 | terminateJob(id) {
61 | return busy(client._.put(`/jobs/${id}/terminate`));
62 | },
63 | };
64 | }
65 |
--------------------------------------------------------------------------------
/src/network/remote/resource.js:
--------------------------------------------------------------------------------
1 | export default function({
2 | client,
3 | filterQuery,
4 | mustContain,
5 | busy,
6 | encodeQueryAsString,
7 | }) {
8 | return {
9 | downloadResources(resourceList, withMetadata = false) {
10 | const params = {
11 | resourceList: JSON.toString(resourceList),
12 | withMetadata,
13 | };
14 |
15 | return busy(client._.get('/resource/download', { params }));
16 | },
17 |
18 | searchResources(query, types) {
19 | const params = {
20 | q: JSON.toString(query),
21 | types: JSON.toString(types),
22 | };
23 | return busy(client._.get('/resource/search', { params }));
24 | },
25 |
26 | deleteResources(resourceList) {
27 | const params = { resources: JSON.toString(resourceList) };
28 | return busy(client._.delete('/resource', { params }));
29 | },
30 | };
31 | }
32 |
--------------------------------------------------------------------------------
/src/network/remote/system.js:
--------------------------------------------------------------------------------
1 | export default function({
2 | client,
3 | filterQuery,
4 | mustContain,
5 | busy,
6 | encodeQueryAsString,
7 | }) {
8 | return {
9 | deleteSetting(key) {
10 | return busy(
11 | client._.delete(`/system/setting${encodeQueryAsString({ key })}`)
12 | );
13 | },
14 |
15 | getSettings(settings) {
16 | const expected = ['key', 'list', 'default'];
17 | const params = filterQuery(settings, ...expected);
18 |
19 | return busy(client._.get('/system/setting', { params }));
20 | },
21 |
22 | setSettings(keyValueMap) {
23 | const list = Object.keys(keyValueMap).map((key) => {
24 | const value = keyValueMap[key];
25 | return { key, value };
26 | });
27 |
28 | return busy(
29 | client._.put(`/system/setting${encodeQueryAsString({ list })}`)
30 | );
31 | },
32 |
33 | getServerVersion() {
34 | return busy(client._.get('/system/version'));
35 | },
36 |
37 | listUnfinishedUpload(query = {}) {
38 | const allowed = [
39 | 'uploadId',
40 | 'userId',
41 | 'parentId',
42 | 'assetstoreId',
43 | 'minimumAge',
44 | 'includeUntracked',
45 | 'limit',
46 | 'offset',
47 | 'sort',
48 | 'sortdir',
49 | ];
50 | const params = filterQuery(query, ...allowed);
51 |
52 | return busy(client._.get('/system/uploads', { params }));
53 | },
54 |
55 | removeUnfinishedUpload(query = {}) {
56 | const allowed = [
57 | 'uploadId',
58 | 'userId',
59 | 'parentId',
60 | 'assetstoreId',
61 | 'minimumAge',
62 | 'includeUntracked',
63 | ];
64 | const params = filterQuery(query, ...allowed);
65 |
66 | return busy(
67 | client._.delete(`/system/uploads${encodeQueryAsString(params)}`)
68 | );
69 | },
70 |
71 | listPlugins() {
72 | return busy(client._.get('/system/plugins'));
73 | },
74 |
75 | setActivePlugins(plugins) {
76 | return busy(
77 | client._.put(`/system/plugins${encodeQueryAsString({ plugins })}`)
78 | );
79 | },
80 | };
81 | }
82 |
--------------------------------------------------------------------------------
/src/network/remote/tasks.js:
--------------------------------------------------------------------------------
1 | export default function({ client, busy }) {
2 | return {
3 | getTask(id) {
4 | return busy(client._.get(`/tasks/${id}`));
5 | },
6 | updateTask(id, updates) {
7 | return busy(client._.patch(`/tasks/${id}`, updates));
8 | },
9 | getTaskLog(id) {
10 | return busy(client._.get(`/tasks/${id}/log`));
11 | },
12 | getTaskStatus(id) {
13 | return busy(client._.get(`/tasks/${id}/status`));
14 | },
15 | };
16 | }
17 |
--------------------------------------------------------------------------------
/src/network/remote/user.js:
--------------------------------------------------------------------------------
1 | export default function({
2 | client,
3 | filterQuery,
4 | mustContain,
5 | busy,
6 | encodeQueryAsString,
7 | }) {
8 | return {
9 | listUsers(query = {}) {
10 | const params = filterQuery(
11 | query,
12 | 'text',
13 | 'limit',
14 | 'offset',
15 | 'sort',
16 | 'sortdir'
17 | );
18 | return busy(client._.get('/user', { params }));
19 | },
20 |
21 | createUser(user) {
22 | const expected = [
23 | 'login',
24 | 'email',
25 | 'firstName',
26 | 'lastName',
27 | 'password',
28 | 'admin',
29 | ];
30 | const params = filterQuery(user, ...expected);
31 | const { missingKeys, promise } = mustContain(user, ...expected);
32 |
33 | return missingKeys
34 | ? promise
35 | : busy(client._.post(`/user${encodeQueryAsString(params)}`));
36 | },
37 |
38 | changePassword(old, newPassword) {
39 | const params = { old, new: newPassword };
40 | return busy(client._.put(`/user/password${encodeQueryAsString(params)}`));
41 | },
42 |
43 | resetPassword(email) {
44 | const params = { email };
45 | return busy(client._.delete('/user/password', { params }));
46 | },
47 |
48 | deleteUser(id) {
49 | return busy(client._.delete(`/user/${id}`));
50 | },
51 |
52 | getUser(id) {
53 | return busy(client._.get(`/user/${id}`));
54 | },
55 |
56 | updateUser(user) {
57 | const expected = ['email', 'firstName', 'lastName', '_id'];
58 | const params = filterQuery(user, ...expected.slice(0, 3)); // Remove '_id'
59 | const { missingKeys, promise } = mustContain(user, ...expected);
60 |
61 | return missingKeys
62 | ? promise
63 | : busy(client._.put(`/user/${user._id}${encodeQueryAsString(params)}`));
64 | },
65 | };
66 | }
67 |
--------------------------------------------------------------------------------
/src/network/remote/utils.js:
--------------------------------------------------------------------------------
1 | export function getJSON(url) {
2 | return new Promise((resolve, reject) => {
3 | const xhr = new XMLHttpRequest();
4 |
5 | function extractResponse(ctx) {
6 | return {
7 | ctx,
8 | data: JSON.parse(xhr.responseText),
9 | status: xhr.status,
10 | statusText: xhr.statusText,
11 | headers: {},
12 | config: {},
13 | };
14 | }
15 |
16 | xhr.addEventListener('load', (event) => {
17 | resolve(extractResponse('load'));
18 | });
19 | xhr.addEventListener('error', (event) => {
20 | console.log('Get JSON request failed', event);
21 | reject(extractResponse('error'));
22 | });
23 | xhr.addEventListener('abort', (event) => {
24 | console.log('Get JSON request has been canceled', event);
25 | reject(extractResponse('abort'));
26 | });
27 |
28 | xhr.open('GET', url, true);
29 | xhr.responseType = 'text';
30 | xhr.setRequestHeader('Accept', 'application/json, text/plain, */*');
31 | xhr.send();
32 | });
33 | }
34 |
35 | export function transformRequest(data) {
36 | return JSON.stringify(data);
37 | }
38 |
--------------------------------------------------------------------------------
/src/network/remote/volumes.js:
--------------------------------------------------------------------------------
1 | import { transformRequest } from './utils';
2 |
3 | const headers = {
4 | 'Content-Type': 'application/json',
5 | };
6 |
7 | export default function({
8 | client,
9 | filterQuery,
10 | mustContain,
11 | encodeQueryAsString,
12 | busy,
13 | }) {
14 | return {
15 | // get /volumes
16 | // List available volumes.
17 | listVolumes(limit = null) {
18 | if (limit) {
19 | return busy(client._.get(`/volumes?limit=${limit}`));
20 | }
21 | return busy(client._.get('/volumes'));
22 | },
23 |
24 | // post /volumes
25 | // Create a volume
26 | createVolume(volume) {
27 | return busy(
28 | client._.post('/volumes', volume, {
29 | transformRequest,
30 | headers,
31 | })
32 | );
33 | },
34 |
35 | // get /volumes/{id}
36 | // Get a volume
37 | getVolume(id) {
38 | return busy(client._.get(`/volumes/${id}`));
39 | },
40 |
41 | // delete /volumes/{id}
42 | // Delete a volume
43 | deleteVolume(id) {
44 | return busy(client._.delete(`/volumes/${id}`));
45 | },
46 |
47 | // get /volumes/{id}/log
48 | // Get log entries for volume
49 | getVolumeLog(volumeId, offset = 0) {
50 | if (offset) {
51 | return busy(client._.get(`/volumes/${volumeId}/log?offset=${offset}`));
52 | }
53 | return busy(client._.get(`/volumes/${volumeId}/log`));
54 | },
55 |
56 | // get /volumes/{id}/status
57 | // Get the volume's current state
58 | getVolumeStatus(id) {
59 | return busy(client._.get(`/volumes/${id}/status`));
60 | },
61 |
62 | // put /volumes/{id}/attach/{cluster}
63 | // Attach a volume to a cluster
64 | attachVolume(id, cluster) {
65 | return busy(client._.put(`/volumes/${id}/attach/${cluster}`));
66 | },
67 |
68 | // put /volumes/{id}/attach/{cluster}
69 | // Detach a volume to a cluster
70 | detachVolume(id) {
71 | return busy(client._.put(`/volumes/${id}/detach`));
72 | },
73 | };
74 | }
75 |
--------------------------------------------------------------------------------
/src/pages/AuthContent/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | export default function HPCCloudAuthContent(props) {
5 | return {props.children}
;
6 | }
7 |
8 | HPCCloudAuthContent.propTypes = {
9 | children: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
10 | };
11 |
12 | HPCCloudAuthContent.defaultProps = {
13 | children: null,
14 | };
15 |
--------------------------------------------------------------------------------
/src/pages/Landing/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import { Link, withRouter } from 'react-router-dom';
5 |
6 | import style from 'HPCCloudStyle/Theme.mcss';
7 |
8 | import client from '../../network';
9 |
10 | export class LandingPage extends React.Component {
11 | componentWillMount() {
12 | this.subscription = client.onAuthChange((loggedIn) => {
13 | if (loggedIn) {
14 | this.props.history.push('/');
15 | }
16 | });
17 | }
18 |
19 | componentWillUnmount() {
20 | if (this.subscription) {
21 | this.subscription.unsubscribe();
22 | this.subscription = null;
23 | }
24 | }
25 |
26 | /* eslint-disable react/no-danger */
27 | render() {
28 | return (
29 |
30 |
31 |
32 |
33 | Welcome to HPCCloud
34 |
35 | Get started by registering or{' '}
36 | logging in
37 |
38 |
39 | );
40 | }
41 | /* eslint-enable react/no-danger */
42 | }
43 |
44 | LandingPage.propTypes = {
45 | history: PropTypes.object.isRequired,
46 | };
47 |
48 | export default withRouter(LandingPage);
49 |
--------------------------------------------------------------------------------
/src/pages/Logout/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import client from '../../network';
5 |
6 | export default class Logout extends React.Component {
7 | componentDidMount() {
8 | client
9 | .logout()
10 | .then(() => {
11 | this.props.history.push('/');
12 | })
13 | .catch(() => {
14 | this.props.history.push('/');
15 | });
16 | }
17 |
18 | render() {
19 | return null;
20 | }
21 | }
22 |
23 | Logout.propTypes = {
24 | history: PropTypes.object.isRequired,
25 | };
26 |
--------------------------------------------------------------------------------
/src/pages/Preferences/PresetSelector.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import editor from 'HPCCloudStyle/ItemEditor.mcss';
5 |
6 | export default class PresetSelector extends React.Component {
7 | constructor(props) {
8 | super(props);
9 | this.valueChange = this.valueChange.bind(this);
10 | }
11 |
12 | valueChange(e) {
13 | if (this.props.onChange) {
14 | this.props.onChange(e.target.value);
15 | }
16 | }
17 |
18 | render() {
19 | const optionsMapper = (preset, index) => (
20 |
21 | {preset}
22 |
23 | );
24 | return (
25 |
30 | Presets
31 | {this.props.contents.map(optionsMapper)}
32 |
33 | );
34 | }
35 | }
36 |
37 | PresetSelector.propTypes = {
38 | contents: PropTypes.array,
39 | onChange: PropTypes.func,
40 | value: PropTypes.string,
41 | };
42 |
43 | PresetSelector.defaultProps = {
44 | contents: [],
45 | onChange: () => {},
46 | value: '',
47 | };
48 |
--------------------------------------------------------------------------------
/src/pages/Preferences/User/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import { connect } from 'react-redux';
5 |
6 | import style from 'HPCCloudStyle/PageWithMenu.mcss';
7 |
8 | import ChangeInfo from './ChangeInfo';
9 | import ChangePassword from './ChangePassword';
10 | import ActiveList from '../../../panels/ActiveList';
11 | import Toolbar from '../../../panels/Toolbar';
12 |
13 | import { breadcrumb } from '..';
14 |
15 | class UserPref extends React.Component {
16 | constructor(props) {
17 | super(props);
18 | this.state = {
19 | active: 0,
20 | };
21 |
22 | this.activeChange = this.activeChange.bind(this);
23 | this.formAction = this.formAction.bind(this);
24 | }
25 |
26 | activeChange(active) {
27 | this.setState({ active });
28 | }
29 |
30 | formAction(actionName) {
31 | this[actionName]();
32 | }
33 |
34 | render() {
35 | const userBreadCrumb = breadcrumb(this.props.user, 'User');
36 | return (
37 |
38 |
39 |
40 |
46 | {React.createElement(this.props.menu[this.state.active].component, {
47 | className: style.content,
48 | })}
49 |
50 |
51 | );
52 | }
53 | }
54 |
55 | UserPref.propTypes = {
56 | menu: PropTypes.array,
57 | user: PropTypes.object,
58 | };
59 |
60 | UserPref.defaultProps = {
61 | menu: [
62 | {
63 | name: 'Change Password',
64 | component: ChangePassword,
65 | },
66 | {
67 | name: 'Change Info',
68 | component: ChangeInfo,
69 | },
70 | ],
71 | user: undefined,
72 | };
73 |
74 | export default connect(
75 | (state) => ({
76 | user: state.auth.user,
77 | }),
78 | () => ({})
79 | )(UserPref);
80 |
--------------------------------------------------------------------------------
/src/pages/Preferences/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import style from 'HPCCloudStyle/Preferences.mcss';
5 |
6 | export const breadcrumb = (user, page) => {
7 | const paths = [
8 | '/Preferences/User',
9 | '/Preferences/Cluster',
10 | '/Preferences/AWS',
11 | '/Preferences/Status',
12 | ]; // '/Preferences/Network', ];
13 | const icons = [
14 | style.userIcon,
15 | style.clusterIcon,
16 | style.ec2Icon,
17 | style.statusIcon,
18 | ]; // style.networkIcon, ],;
19 | const titles = ['User preferences', 'Cluster', 'EC2', 'Server status'];
20 | const labels = ['User', 'Cluster', 'EC2', 'Status'];
21 | if (user && user.admin) {
22 | paths.splice(1, 0, '/Preferences/Groups');
23 | icons.splice(1, 0, style.groupIcon);
24 | titles.splice(1, 0, 'Groups');
25 | labels.splice(1, 0, 'Groups');
26 | }
27 | return {
28 | paths,
29 | icons,
30 | titles,
31 | labels,
32 | active: labels.indexOf(page),
33 | };
34 | };
35 |
36 | export default function Preferences(props) {
37 | return {props.children}
;
38 | }
39 |
40 | Preferences.propTypes = {
41 | children: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
42 | };
43 |
44 | Preferences.defaultProps = {
45 | children: null,
46 | };
47 |
--------------------------------------------------------------------------------
/src/panels/ActiveList/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import style from 'HPCCloudStyle/ActiveList.mcss';
5 |
6 | // Expectations:
7 | // - style:
8 | // - (li) selectable
9 | // - (li) unselectable
10 | // - (li) active
11 | // - (ul) list
12 | // - properties:
13 | // - active: Active index in the list
14 | // - list: List of object to show
15 | // - item: name, label, disabled, classPrefix, classSufix
16 | // - onActiveChange: Callback(activeIdx, activeItem)
17 |
18 | export default class ActiveList extends React.Component {
19 | constructor(props) {
20 | super(props);
21 | this.changeActive = this.changeActive.bind(this);
22 | this.itemMapper = this.itemMapper.bind(this);
23 | }
24 |
25 | changeActive(event) {
26 | const el = event.currentTarget;
27 |
28 | if (this.props.onActiveChange) {
29 | const newIndex = parseInt(el.dataset.index, 10);
30 | if (!this.props.list[newIndex].disabled) {
31 | this.props.onActiveChange(newIndex, this.props.list[newIndex]);
32 | }
33 | }
34 | }
35 |
36 | itemMapper(el, index) {
37 | return (
38 |
48 |
49 | {el.name}
50 |
51 |
52 | );
53 | }
54 |
55 | render() {
56 | return (
57 |
58 | {this.props.list.map(this.itemMapper)}
59 |
60 | );
61 | }
62 | }
63 |
64 | ActiveList.propTypes = {
65 | active: PropTypes.number,
66 | className: PropTypes.string,
67 | list: PropTypes.array,
68 | onActiveChange: PropTypes.func,
69 | };
70 |
71 | ActiveList.defaultProps = {
72 | className: '',
73 | active: undefined,
74 | list: [],
75 | onActiveChange: () => {},
76 | };
77 |
--------------------------------------------------------------------------------
/src/panels/AuthRoute/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import { Route, Redirect } from 'react-router-dom';
5 |
6 | import client from '../../network';
7 |
8 | // ----------------------------------------------------------------------------
9 |
10 | function isLoggedIn() {
11 | return !!client.getLoggedInUser();
12 | }
13 |
14 | // ----------------------------------------------------------------------------
15 |
16 | function isAdmin() {
17 | if (isLoggedIn()) {
18 | const user = client.getLoggedInUser();
19 | return user.admin;
20 | }
21 | return false;
22 | }
23 |
24 | // ----------------------------------------------------------------------------
25 |
26 | export default function AuthRoute({
27 | component: Component,
28 | redirectTo,
29 | admin,
30 | path,
31 | exact,
32 | }) {
33 | return (
34 |
38 | (admin ? (
39 | isAdmin()
40 | ) : (
41 | isLoggedIn()
42 | )) ? (
43 |
44 | ) : (
45 |
46 | )
47 | }
48 | />
49 | );
50 | }
51 |
52 | AuthRoute.propTypes = {
53 | component: PropTypes.func.isRequired,
54 | admin: PropTypes.bool,
55 | redirectTo: PropTypes.string,
56 | path: PropTypes.string.isRequired,
57 | exact: PropTypes.bool,
58 | };
59 |
60 | AuthRoute.defaultProps = {
61 | admin: false,
62 | redirectTo: '/',
63 | exact: false,
64 | };
65 |
--------------------------------------------------------------------------------
/src/panels/EmptyPlaceholder/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import style from 'HPCCloudStyle/Layout.mcss';
4 |
5 | // used for empty placeholders on some pages
6 |
7 | const classes = [
8 | style.verticalFlexContainer,
9 | style.fullWidth,
10 | style.halfHeight,
11 | style.horizontalCenter,
12 | style.verticalCenter,
13 | style.textCenter,
14 | ].join(' ');
15 |
16 | const placeholder = (props) => {props.phrase}
;
17 |
18 | placeholder.displayName = 'EmptyPlaceholder';
19 |
20 | placeholder.propTypes = {
21 | phrase: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
22 | };
23 |
24 | placeholder.defaultProps = {
25 | phrase: '',
26 | };
27 |
28 | export default placeholder;
29 |
--------------------------------------------------------------------------------
/src/panels/FormPanel/CheckboxInput.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | export default class FormPanelCheckboxInput extends React.Component {
5 | constructor(props) {
6 | super(props);
7 | this.editField = this.editField.bind(this);
8 | }
9 |
10 | editField(event) {
11 | if (this.props.onChange) {
12 | this.props.onChange(this.props.id, !this.props.value);
13 | }
14 | }
15 |
16 | render() {
17 | const { style, item, value } = this.props;
18 | return (
19 |
30 | );
31 | }
32 | }
33 |
34 | FormPanelCheckboxInput.propTypes = {
35 | id: PropTypes.string,
36 | item: PropTypes.object,
37 | value: PropTypes.bool,
38 | style: PropTypes.object,
39 | onChange: PropTypes.func,
40 | };
41 |
42 | FormPanelCheckboxInput.defaultProps = {
43 | id: undefined,
44 | item: undefined,
45 | value: false,
46 | style: {},
47 | onChange: undefined,
48 | };
49 |
--------------------------------------------------------------------------------
/src/panels/FormPanel/EnumInput.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | export default class FormPanelEnumInput extends React.Component {
5 | constructor(props) {
6 | super(props);
7 | this.editField = this.editField.bind(this);
8 | }
9 |
10 | editField(event) {
11 | const value = event.target.value;
12 | if (this.props.onChange) {
13 | this.props.onChange(this.props.id, value);
14 | }
15 | }
16 |
17 | render() {
18 | const { style, item, value } = this.props;
19 | return (
20 |
21 |
22 | {item.label}
23 |
24 |
25 | {item.values.map((option, index) => (
26 |
27 | {option}
28 |
29 | ))}
30 |
31 |
32 | );
33 | }
34 | }
35 |
36 | FormPanelEnumInput.propTypes = {
37 | id: PropTypes.string,
38 | item: PropTypes.object,
39 | value: PropTypes.string,
40 | style: PropTypes.object,
41 | onChange: PropTypes.func,
42 | };
43 |
44 | FormPanelEnumInput.defaultProps = {
45 | id: undefined,
46 | item: undefined,
47 | value: '',
48 | style: {},
49 | onChange: undefined,
50 | };
51 |
--------------------------------------------------------------------------------
/src/panels/FormPanel/TextInput.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | export default class FormPanelTextInput extends React.Component {
5 | constructor(props) {
6 | super(props);
7 | this.editField = this.editField.bind(this);
8 | }
9 |
10 | editField(event) {
11 | const value = event.target.value;
12 | if (this.props.onChange) {
13 | this.props.onChange(this.props.id, value);
14 | }
15 | }
16 |
17 | render() {
18 | const { style, item, value } = this.props;
19 | return (
20 |
32 | );
33 | }
34 | }
35 |
36 | FormPanelTextInput.propTypes = {
37 | id: PropTypes.string,
38 | item: PropTypes.object,
39 | value: PropTypes.string,
40 | style: PropTypes.object,
41 | onChange: PropTypes.func,
42 | };
43 |
44 | FormPanelTextInput.defaultProps = {
45 | id: undefined,
46 | item: undefined,
47 | value: '',
48 | style: {},
49 | onChange: undefined,
50 | };
51 |
--------------------------------------------------------------------------------
/src/panels/IconActionList/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import style from 'HPCCloudStyle/Toolbar.mcss';
4 |
5 | export default class IconActionList extends React.Component {
6 | constructor(props) {
7 | super(props);
8 | this.onAction = this.onAction.bind(this);
9 | }
10 |
11 | onAction(event) {
12 | const action = event.target.dataset.action;
13 | if (this.props.onAction) {
14 | this.props.onAction(action);
15 | }
16 | }
17 |
18 | render() {
19 | return (
20 |
21 | {this.props.actions.map((action, index) => (
22 |
28 | ))}
29 |
30 | );
31 | }
32 | }
33 |
34 | IconActionList.propTypes = {
35 | actions: PropTypes.array,
36 | className: PropTypes.string,
37 | onAction: PropTypes.func,
38 | };
39 |
40 | IconActionList.defaultProps = {
41 | actions: [],
42 | className: '',
43 | onAction: undefined,
44 | };
45 |
--------------------------------------------------------------------------------
/src/panels/ImageIcon/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | export default function ImageIcon(props) {
5 | if (props.data && props.data.image) {
6 | return (
7 |
12 | );
13 | }
14 |
15 | if (props.data && props.data.icon) {
16 | return ;
17 | }
18 |
19 | return null;
20 | }
21 |
22 | ImageIcon.propTypes = {
23 | data: PropTypes.object.isRequired,
24 | height: PropTypes.string,
25 | };
26 |
27 | ImageIcon.defaultProps = {
28 | height: '1.5em',
29 | };
30 |
--------------------------------------------------------------------------------
/src/panels/JobMonitor/LogFold.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import style from 'HPCCloudStyle/JobMonitor.mcss';
5 | import state from 'HPCCloudStyle/States.mcss';
6 |
7 | export default class LogFold extends React.Component {
8 | constructor(props) {
9 | super(props);
10 | this.state = {
11 | open: false,
12 | };
13 | this.toggleOpen = this.toggleOpen.bind(this);
14 | }
15 |
16 | toggleOpen() {
17 | this.setState({ open: !this.state.open });
18 | }
19 |
20 | render() {
21 | return (
22 |
23 | {this.state.open ? (
24 |
25 | ) : (
26 |
27 | )}
28 | {this.props.header}
29 |
30 | {this.props.content}
31 |
32 |
33 | );
34 | }
35 | }
36 |
37 | LogFold.propTypes = {
38 | header: PropTypes.string.isRequired,
39 | content: PropTypes.string.isRequired,
40 | color: PropTypes.string,
41 | };
42 |
43 | LogFold.defaultProps = {
44 | color: '',
45 | };
46 |
--------------------------------------------------------------------------------
/src/panels/LinkIcon/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import { Link } from 'react-router-dom';
5 |
6 | export default function LinkIcon(props) {
7 | return (
8 |
9 |
10 |
11 | );
12 | }
13 |
14 | LinkIcon.propTypes = {
15 | className: PropTypes.string,
16 | icon: PropTypes.string.isRequired,
17 | to: PropTypes.string.isRequired,
18 | title: PropTypes.string,
19 | };
20 |
21 | LinkIcon.defaultProps = {
22 | className: '',
23 | title: null,
24 | };
25 |
--------------------------------------------------------------------------------
/src/panels/LoadingPanel/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import Theme from 'HPCCloudStyle/Theme.mcss';
5 | import Layout from 'HPCCloudStyle/Layout.mcss';
6 |
7 | export default function LoadingPanel(props) {
8 | const layoutClasses = [Layout.verticalFlexContainer];
9 |
10 | if (props.center) {
11 | layoutClasses.push(Layout.horizontalCenter);
12 | layoutClasses.push(Layout.verticalCenter);
13 | }
14 |
15 | if (props.large) {
16 | layoutClasses.push(Theme.largeText);
17 | }
18 |
19 | return (
20 |
24 |
25 | Loading...
26 |
27 |
28 | );
29 | }
30 |
31 | LoadingPanel.propTypes = {
32 | center: PropTypes.bool,
33 | large: PropTypes.bool,
34 | };
35 |
36 | LoadingPanel.defaultProps = {
37 | center: false,
38 | large: false,
39 | };
40 |
--------------------------------------------------------------------------------
/src/panels/Switch/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | export default function Switch(props) {
5 | const cleanProps = Object.assign({}, props);
6 | delete cleanProps.if;
7 | delete cleanProps.then;
8 | delete cleanProps.else;
9 | delete cleanProps.thenProps;
10 | delete cleanProps.elseProps;
11 |
12 | if (props.if()) {
13 | const C = props.then;
14 | return ;
15 | }
16 | const C = props.else;
17 | return ;
18 | }
19 |
20 | Switch.propTypes = {
21 | if: PropTypes.func.isRequired,
22 | then: PropTypes.func.isRequired,
23 | else: PropTypes.func.isRequired,
24 |
25 | thenProps: PropTypes.object,
26 | elseProps: PropTypes.object,
27 | };
28 |
29 | Switch.defaultProps = {
30 | thenProps: {},
31 | elseProps: {},
32 | };
33 |
--------------------------------------------------------------------------------
/src/panels/run/defaults.js:
--------------------------------------------------------------------------------
1 | export default {
2 | EC2: {
3 | profile: '',
4 | machine: '',
5 | clusterSize: 1,
6 | volume: '',
7 | volumeName: '',
8 | volumeSize: '',
9 | },
10 | Traditional: {
11 | profile: '',
12 | },
13 | };
14 |
--------------------------------------------------------------------------------
/src/panels/run/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import formStyle from 'HPCCloudStyle/ItemEditor.mcss';
5 |
6 | import RunCluster from './RunCluster';
7 | import RunEC2 from './RunEC2';
8 |
9 | export default function RunClusterForm(props) {
10 | let serverForm = null;
11 | switch (props.serverType) {
12 | case 'EC2':
13 | serverForm = (
14 |
19 | );
20 | break;
21 | case 'Traditional':
22 | serverForm = (
23 |
28 | );
29 | break;
30 | default:
31 | serverForm = no valid serverType: {props.serverType} ;
32 | }
33 |
34 | const optionMapper = (el, index) => (
35 |
36 | {el}
37 |
38 | );
39 |
40 | return (
41 |
42 |
43 | Server Type
44 |
49 | {Object.keys(props.profiles).map(optionMapper)}
50 |
51 |
52 |
53 |
54 | );
55 | }
56 |
57 | RunClusterForm.propTypes = {
58 | serverType: PropTypes.string,
59 | serverTypeChange: PropTypes.func,
60 | profiles: PropTypes.object,
61 | dataChange: PropTypes.func,
62 | clusterFilter: PropTypes.func,
63 | };
64 |
65 | RunClusterForm.defaultProps = {
66 | serverType: undefined,
67 | serverTypeChange: undefined,
68 | profiles: undefined,
69 | dataChange: undefined,
70 | clusterFilter: undefined,
71 | };
72 |
--------------------------------------------------------------------------------
/src/redux/actions/history.js:
--------------------------------------------------------------------------------
1 | let history = null;
2 |
3 | export function setHistory(h) {
4 | history = h;
5 | }
6 |
7 | export function getHistory() {
8 | return history;
9 | }
10 |
11 | export function push(path, state) {
12 | if (history) {
13 | history.push(path, state);
14 | }
15 | }
16 |
17 | export function replace(path, state) {
18 | if (history) {
19 | history.replace(path, state);
20 | }
21 | }
22 |
23 | export function go(n) {
24 | if (history) {
25 | history.go(n);
26 | }
27 | }
28 |
29 | export function goBack() {
30 | if (history) {
31 | history.goBack();
32 | }
33 | }
34 |
35 | export function goForward() {
36 | if (history) {
37 | history.goForward();
38 | }
39 | }
40 |
41 | export default {
42 | push,
43 | replace,
44 | go,
45 | goBack,
46 | goForward,
47 | };
48 |
--------------------------------------------------------------------------------
/src/redux/actions/network.js:
--------------------------------------------------------------------------------
1 | import client from '../../network';
2 | import { dispatch } from '../';
3 |
4 | export const ADD_NETWORK_CALL = 'ADD_NETWORK_CALL';
5 | export const SUCCESS_NETWORK_CALL = 'SUCCESS_NETWORK_CALL';
6 | export const ERROR_NETWORK_CALL = 'ERROR_NETWORK_CALL';
7 | export const INVALIDATE_ERROR = 'INVALIDATE_ERROR';
8 | export const INVALIDATE_ERRORS = 'INVALIDATE_ERRORS';
9 | export const PREPARE_UPLOAD = 'PREPARE_UPLOAD';
10 | export const RESET_UPLOAD_PROGRESS = 'RESET_UPLOAD_PROGRESS';
11 | export const ON_UPLOAD_PROGRESS = 'ON_UPLOAD_PROGRESS';
12 |
13 | /* eslint-disable no-shadow */
14 |
15 | export function addNetworkCall(id, label = '') {
16 | const ts = +new Date();
17 |
18 | return {
19 | type: ADD_NETWORK_CALL,
20 | id,
21 | label,
22 | ts,
23 | };
24 | }
25 |
26 | export function successNetworkCall(id, resp) {
27 | return { type: SUCCESS_NETWORK_CALL, id, resp };
28 | }
29 |
30 | export function invalidateError(id, errType = 'application') {
31 | return { type: INVALIDATE_ERROR, id, errType };
32 | }
33 |
34 | // takes an array of ids which the reducer then invalidates all of
35 | export function invalidateErrors(ids, errType = 'application') {
36 | return { type: INVALIDATE_ERRORS, ids, errType };
37 | }
38 |
39 | export function errorNetworkCall(id, resp, errType = 'application') {
40 | const errorTimeout = setTimeout(() => {
41 | dispatch(invalidateError(id));
42 | }, 5000);
43 | return { type: ERROR_NETWORK_CALL, id, resp, errorTimeout, errType };
44 | }
45 |
46 | export function prepareUpload(files) {
47 | return { type: PREPARE_UPLOAD, files };
48 | }
49 |
50 | export function resetProgress(val) {
51 | return { type: RESET_UPLOAD_PROGRESS, val };
52 | }
53 |
54 | export function onProgress(progressPacket) {
55 | dispatch({
56 | type: ON_UPLOAD_PROGRESS,
57 | progressPacket,
58 | });
59 | }
60 |
61 | client.onProgress(onProgress);
62 |
--------------------------------------------------------------------------------
/src/redux/actions/progress.js:
--------------------------------------------------------------------------------
1 | export const SETUP_PROGRESS = 'SETUP_PROGRESS';
2 | export const ON_SOME_PROGRESS = 'ON_PROGRESS';
3 | export const RESET_PROGRESS = 'RESET_PROGRESS';
4 |
5 | export function setupProgress(total) {
6 | return { type: SETUP_PROGRESS, total };
7 | }
8 |
9 | export function onProgress(current) {
10 | return { type: ON_SOME_PROGRESS, current };
11 | }
12 |
13 | export function resetProgress(val) {
14 | return { type: RESET_PROGRESS, val };
15 | }
16 |
--------------------------------------------------------------------------------
/src/redux/actions/statuses.js:
--------------------------------------------------------------------------------
1 | import * as netActions from './network';
2 | import client from '../../network';
3 |
4 | export const UPDATE_CLUSTERS_LIST = 'UPDATE_CLUSTERS_LIST';
5 | export const UPDATE_EC2_LIST = 'UPDATE_EC2_LIST';
6 | export const PENDING_CLUSTER_NETWORK = 'PENDING_CLUSTER_NETWORK';
7 |
8 | export function updateClusterList(list) {
9 | return { type: UPDATE_CLUSTERS_LIST, list };
10 | }
11 |
12 | export function updateEC2List(list) {
13 | return { type: UPDATE_EC2_LIST, list };
14 | }
15 |
16 | export function pendingNetworkCall(pending = true) {
17 | return { type: PENDING_CLUSTER_NETWORK, pending };
18 | }
19 |
20 | export function fetchServers() {
21 | return (dispatch) => {
22 | const action = netActions.addNetworkCall(
23 | 'fetch_servers',
24 | 'Retreive servers'
25 | );
26 |
27 | dispatch(pendingNetworkCall(true));
28 | client
29 | .listClusters()
30 | .then((resp) => {
31 | dispatch(netActions.successNetworkCall(action.id, resp));
32 | dispatch(updateClusterList(resp.data));
33 | return client.listAWSProfiles();
34 | })
35 | .then((resp) => {
36 | dispatch(updateEC2List(resp.data));
37 | dispatch(pendingNetworkCall(false));
38 | dispatch(netActions.successNetworkCall(action.id, resp));
39 | })
40 | .catch((err) => {
41 | dispatch(netActions.errorNetworkCall(action.id, err));
42 | dispatch(pendingNetworkCall(false));
43 | });
44 |
45 | return action;
46 | };
47 | }
48 |
--------------------------------------------------------------------------------
/src/redux/index.js:
--------------------------------------------------------------------------------
1 | import { createStore } from 'redux';
2 |
3 | import reducers from './reducers';
4 |
5 | const store = createStore(reducers);
6 |
7 | function dispatch(action) {
8 | let currentAction = action;
9 | while (typeof currentAction === 'function') {
10 | currentAction = action(dispatch);
11 | }
12 | return store.dispatch(currentAction);
13 | }
14 |
15 | export default store;
16 |
17 | export { store, dispatch };
18 |
--------------------------------------------------------------------------------
/src/redux/reducers/ListActiveMapByIdHelper.js:
--------------------------------------------------------------------------------
1 | export const initialState = {
2 | list: [],
3 | active: null,
4 | mapById: {},
5 | };
6 |
7 | export function updateList(state, itemList, idKey = '_id') {
8 | const list = [];
9 | const mapById = {};
10 | itemList.forEach((item) => {
11 | list.push(item[idKey]);
12 | mapById[item[idKey]] = item;
13 | });
14 |
15 | const active = mapById[state.active] ? state.active : null;
16 | return Object.assign({}, state, { list, mapById, active });
17 | }
18 |
19 | export function removeItem(state, id) {
20 | let mapById = state.mapById;
21 | if (mapById && mapById[id]) {
22 | mapById = Object.assign({}, state.mapById);
23 | delete mapById[id];
24 | }
25 | if (state.list.indexOf(id) !== -1) {
26 | const list = state.list.filter((item) => item !== id);
27 | const active = state.active === id ? null : state.active;
28 | if (mapById) {
29 | return Object.assign({}, state, { list, active, mapById });
30 | }
31 | return Object.assign({}, state, { list, active });
32 | }
33 | return state;
34 | }
35 |
36 | export function updateItem(state, item, idKey = '_id') {
37 | const itemId = item[idKey];
38 | const list =
39 | state.list.indexOf(itemId) === -1
40 | ? [itemId].concat(state.list)
41 | : state.list;
42 | const mapById = Object.assign({}, state.mapById, { [itemId]: item });
43 | return Object.assign({}, state, { list, mapById });
44 | }
45 |
46 | export function updateActive(state, id) {
47 | return Object.assign({}, state, { active: id });
48 | }
49 |
50 | export default {
51 | updateList,
52 | removeItem,
53 | updateItem,
54 | initialState,
55 | updateActive,
56 | };
57 |
--------------------------------------------------------------------------------
/src/redux/reducers/auth.js:
--------------------------------------------------------------------------------
1 | import * as Actions from '../actions/user';
2 |
3 | export const initialState = {
4 | pending: false,
5 | user: null,
6 | userMap: {},
7 | };
8 |
9 | export default function authReducer(state = initialState, action) {
10 | switch (action.type) {
11 | case Actions.LOGGED_IN: {
12 | return Object.assign({}, state, { user: action.user });
13 | }
14 |
15 | case Actions.AUTH_PENDING: {
16 | return Object.assign({}, state, { pending: action.pending });
17 | }
18 |
19 | case Actions.LOGOUT: {
20 | return initialState;
21 | }
22 |
23 | case Actions.GET_USERS: {
24 | const users = {};
25 | action.users.forEach((u) => {
26 | users[u._id] = u;
27 | });
28 | return Object.assign({}, state, { userMap: users });
29 | }
30 |
31 | default:
32 | return state;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/redux/reducers/index.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux';
2 |
3 | import visualizer from 'pvw-visualizer/src/redux/reducers';
4 |
5 | import auth from './auth';
6 | import fs from './fs';
7 | import groups from './groups';
8 | import network from './network';
9 | import preferences from './preferences';
10 | import progress from './progress';
11 | import projects from './projects';
12 | import simulations from './simulations';
13 | import taskflows from './taskflows';
14 |
15 | export default combineReducers({
16 | auth,
17 | fs,
18 | groups,
19 | network,
20 | preferences,
21 | progress,
22 | projects,
23 | simulations,
24 | taskflows,
25 | visualizer,
26 | });
27 |
--------------------------------------------------------------------------------
/src/redux/reducers/preferences.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux';
2 |
3 | import clusters from './clusters';
4 | import aws from './aws';
5 | import statuses from './statuses';
6 | import volumes from './volumes';
7 |
8 | export default combineReducers({
9 | clusters,
10 | aws,
11 | statuses,
12 | volumes,
13 | });
14 |
--------------------------------------------------------------------------------
/src/redux/reducers/progress.js:
--------------------------------------------------------------------------------
1 | import * as Actions from '../actions/progress';
2 |
3 | export const initialState = {
4 | current: 0,
5 | total: null,
6 | progressReset: false,
7 | };
8 |
9 | export default function progressReducer(state = initialState, action) {
10 | switch (action.type) {
11 | case Actions.SETUP_PROGRESS: {
12 | return { current: 0, total: action.total };
13 | }
14 | case Actions.ON_SOME_PROGRESS: {
15 | return Object.assign({}, state, { current: action.current });
16 | }
17 | case Actions.RESET_PROGRESS: {
18 | return { current: 0, total: null, progressReset: action.val };
19 | }
20 |
21 | default:
22 | return state;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/redux/reducers/simulations.js:
--------------------------------------------------------------------------------
1 | import * as Actions from '../actions/projects';
2 |
3 | export const simInitialState = {
4 | mapById: {},
5 | };
6 |
7 | export default function simulationsReducer(state = simInitialState, action) {
8 | switch (action.type) {
9 | case Actions.REMOVE_SIMULATION: {
10 | const mapById = Object.assign({}, state.mapById);
11 | delete mapById[action.simulation._id];
12 | return Object.assign({}, state, { mapById });
13 | }
14 |
15 | case Actions.UPDATE_SIMULATION: {
16 | const mapById = Object.assign({}, state.mapById);
17 | mapById[action.simulation._id] = action.simulation;
18 | return Object.assign({}, state, { mapById });
19 | }
20 |
21 | case Actions.UPDATE_PROJECT_SIMULATIONS: {
22 | const mapById = Object.assign({}, state.mapById);
23 | action.simulations.forEach((simulation) => {
24 | mapById[simulation._id] = simulation;
25 | });
26 | return Object.assign({}, state, { mapById });
27 | }
28 |
29 | default:
30 | return state;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/redux/reducers/statuses.js:
--------------------------------------------------------------------------------
1 | import * as Actions from '../actions/statuses';
2 |
3 | export const initialState = {
4 | ec2: [],
5 | clusters: [],
6 | };
7 |
8 | export default function statusesReducer(state = initialState, action) {
9 | switch (action.type) {
10 | case Actions.UPDATE_EC2_LIST: {
11 | return Object.assign({}, state, { ec2: action.list });
12 | }
13 | case Actions.UPDATE_CLUSTERS_LIST: {
14 | return Object.assign({}, state, { clusters: action.list });
15 | }
16 | default:
17 | return state;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/tools/index.js:
--------------------------------------------------------------------------------
1 | import visualizer from './visualizer';
2 |
3 | export default {
4 | visualizer: {
5 | providesToolbar: true,
6 | view: visualizer,
7 | },
8 | };
9 |
--------------------------------------------------------------------------------
/src/utils/ClusterPayload.js:
--------------------------------------------------------------------------------
1 | function tradClusterPayload(id) {
2 | if (!id) {
3 | throw Error('missing id in traditional cluster payload');
4 | }
5 | return {
6 | _id: id,
7 | };
8 | }
9 |
10 | function ec2ClusterPayload(
11 | name,
12 | machine,
13 | clusterSize = 1,
14 | profileId,
15 | clusterNames
16 | ) {
17 | if (typeof name === 'undefined') {
18 | throw Error('Missing required field: "name"');
19 | } else if (typeof machine === 'undefined') {
20 | throw Error('Missing required field: "machine"');
21 | } else if (typeof profileId === 'undefined') {
22 | throw Error('Missing required field: "profileId"');
23 | } else if (clusterNames.indexOf(name.trim()) !== -1) {
24 | throw Error('An EC2 instance with this name already exists');
25 | }
26 |
27 | let _clusterSize = Number(clusterSize);
28 | if (Number.isNaN(_clusterSize)) {
29 | _clusterSize = 1;
30 | } else if (clusterSize <= 0) {
31 | throw Error('Cluster must be greater than zero');
32 | }
33 |
34 | return {
35 | serverType: 'ec2',
36 | machine,
37 | name: name.trim(),
38 | clusterSize: _clusterSize,
39 | profileId,
40 | };
41 | }
42 |
43 | export default function getClusterPayload(type, options, clusterNames) {
44 | if (type === 'EC2') {
45 | const { name, machine, clusterSize, profile, cluster } = options;
46 | if (cluster) {
47 | return { _id: cluster };
48 | }
49 | return ec2ClusterPayload(name, machine, clusterSize, profile, clusterNames);
50 | }
51 | if (type === 'Traditional') {
52 | const { profile } = options;
53 | return tradClusterPayload(profile);
54 | }
55 | return null;
56 | }
57 |
--------------------------------------------------------------------------------
/src/utils/Constants.js:
--------------------------------------------------------------------------------
1 | import breadCrumbStyle from 'HPCCloudStyle/Theme.mcss';
2 |
3 | export const baseURL = '/api/v1';
4 |
5 | // name: action in component that this action runs
6 | // label: the button's label
7 | // icon: an fa icon, import styles here and include them if desired.
8 | export const taskflowActions = {
9 | deleteCluster: { name: 'onDeleteCluster', label: 'Delete Cluster', icon: '' },
10 | terminate: { name: 'onTerminate', label: 'Terminate', icon: '' },
11 | visualize: { name: 'onVisualize', label: 'Visualize', icon: '' },
12 | rerun: { name: 'onRerun', label: 'Rerun', icon: '' },
13 | terminateInstance: {
14 | name: 'onTerminateInstance',
15 | label: 'Terminate EC2 Instance',
16 | icon: '',
17 | },
18 | moveOffline: { name: 'moveOffline', label: 'Move Files Offline', icon: '' },
19 | };
20 |
21 | export const volumeTypes = {
22 | 'General Purpose SSD': 'GP2',
23 | 'Provisioned IOPS SSD': 'IO1',
24 | Magnetic: 'Magnetic',
25 | 'Throughput Optimized HDD': 'ST1',
26 | 'Cold HDD': 'SC1',
27 | };
28 |
29 | export function primaryBreadCrumbs(projectId = null, simulationId = null) {
30 | const ret = {
31 | paths: ['/'],
32 | icons: [breadCrumbStyle.breadCrumbRootIcon],
33 | titles: ['Home'],
34 | };
35 | if (projectId) {
36 | ret.paths.push(`/View/Project/${projectId}`);
37 | ret.icons.push(breadCrumbStyle.breadCrumbProjectIcon);
38 | ret.titles.push('Project');
39 | if (simulationId) {
40 | ret.paths.push(`/View/Simulation/${simulationId}`);
41 | ret.icons.push(breadCrumbStyle.breadCrumbSimulationIcon);
42 | ret.titles.push('Simulation');
43 | }
44 | }
45 | return ret;
46 | }
47 |
--------------------------------------------------------------------------------
/src/utils/Filters.js:
--------------------------------------------------------------------------------
1 | let query = {};
2 |
3 | const filterKeys = {
4 | 't:': 'type',
5 | 'n:': 'name',
6 | 'd:': 'description',
7 | };
8 |
9 | function findActiveKey(token) {
10 | let key = null;
11 | Object.keys(filterKeys).forEach((k) => {
12 | if (token.indexOf(k) === 0) {
13 | key = k;
14 | }
15 | });
16 | return key;
17 | }
18 |
19 | export function updateQuery(queryStr = '') {
20 | const tokens = queryStr.split(' ');
21 | let activeToken = null;
22 | let previousFilterKey = null;
23 | let activeFilterKey = null;
24 |
25 | // Reset query
26 | query = {};
27 |
28 | while (tokens.length) {
29 | activeToken = tokens.shift();
30 | activeFilterKey = findActiveKey(activeToken);
31 |
32 | if (!activeFilterKey) {
33 | activeFilterKey = previousFilterKey || 'n:';
34 | } else {
35 | activeToken = activeToken.substr(activeFilterKey.length);
36 | }
37 |
38 | previousFilterKey = activeFilterKey;
39 |
40 | if (!query[filterKeys[activeFilterKey]]) {
41 | query[filterKeys[activeFilterKey]] = [];
42 | }
43 |
44 | query[filterKeys[activeFilterKey]].push(activeToken.toLowerCase());
45 | }
46 |
47 | return query;
48 | }
49 |
50 | export function itemFilter(item, index, array) {
51 | let keep = true;
52 |
53 | Object.keys(query).forEach((key) => {
54 | query[key].forEach((token) => {
55 | keep = keep && item[key].toLowerCase().indexOf(token) !== -1;
56 | });
57 | });
58 |
59 | return keep;
60 | }
61 |
--------------------------------------------------------------------------------
/src/utils/Format.js:
--------------------------------------------------------------------------------
1 | // this formatter takes a decimal that represents time in unix seconds
2 | export function formatTime(time) {
3 | const date = new Date(time * 1000);
4 | let hours = date.getHours().toString();
5 | let minutes = date.getMinutes().toString();
6 | let seconds = date.getSeconds().toString();
7 | let ms = date.getMilliseconds().toString();
8 |
9 | hours = hours.length === 1 ? `0${hours}` : hours;
10 | minutes = minutes.length === 1 ? `0${minutes}` : minutes;
11 | seconds = seconds.length === 1 ? `0${seconds}` : seconds;
12 | while (ms.length < 3) {
13 | ms = `0${ms}`;
14 | }
15 |
16 | return `${hours}:${minutes}:${seconds}.${ms}`;
17 | }
18 |
19 | export function formatFileSize(bytes, precision = 1) {
20 | const nBytes = Number(bytes);
21 | if (Number.isNaN(nBytes) || !Number.isFinite(nBytes)) {
22 | return 'unknown size';
23 | } else if (nBytes === 0) {
24 | return '0 bytes';
25 | }
26 | const units = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB'];
27 | const number = Math.floor(Math.log(bytes) / Math.log(1024));
28 | return `${(bytes / 1024 ** Math.floor(number)).toFixed(precision)} ${
29 | units[number]
30 | }`;
31 | }
32 |
33 | export default {
34 | formatTime,
35 | };
36 |
--------------------------------------------------------------------------------
/src/utils/Helper.js:
--------------------------------------------------------------------------------
1 | export function setPathTo(object, path, value) {
2 | var currentContainer = object || {};
3 | var keyPath = path.split('.');
4 | const lastKey = keyPath.pop();
5 |
6 | while (keyPath.length) {
7 | const nextKey = keyPath.shift();
8 | if (!currentContainer[nextKey]) {
9 | currentContainer[nextKey] = {};
10 | }
11 | currentContainer = currentContainer[nextKey];
12 | }
13 |
14 | currentContainer[lastKey] = value;
15 | }
16 |
--------------------------------------------------------------------------------
/src/utils/get.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-cond-assign */
2 | export default function get(obj, prop) {
3 | let container = obj;
4 | let propName = prop;
5 | const parts = prop.split('.');
6 | const last = parts.pop();
7 | const falseyReturn = last === 'length' ? 0 : false;
8 |
9 | if (!container) {
10 | return falseyReturn;
11 | }
12 |
13 | while ((propName = parts.shift())) {
14 | container = container[propName];
15 | if (container == null) {
16 | return falseyReturn;
17 | }
18 | }
19 |
20 | // we don't want to return undefined
21 | if (container[last] == null) {
22 | return falseyReturn;
23 | }
24 |
25 | return container[last];
26 | }
27 |
28 | /* we use `get` a lot to check for objects' contents,
29 | * mout's `get` throws an error if we give it an undefined object
30 | * this addresses that use case */
31 |
--------------------------------------------------------------------------------
/src/utils/getDisabledButtons.js:
--------------------------------------------------------------------------------
1 | import Theme from 'HPCCloudStyle/Theme.mcss';
2 |
3 | import get from './get';
4 | import { taskflowActions } from './Constants';
5 |
6 | // actionsList is an array of strings,
7 | // disabled is an object for each action either undefined or with a boolean
8 | export function getActions(actionsList, disabled) {
9 | return actionsList.map((action) =>
10 | Object.assign({}, taskflowActions[action], {
11 | disabled: !!disabled[action],
12 | icon: disabled[action] ? Theme.loadingIcon : null,
13 | })
14 | );
15 | }
16 |
17 | export function getDisabledButtons(network, taskflow = {}) {
18 | const disabledButtons = {};
19 | const actions = get(taskflow, 'actions');
20 | const taskflowId = get(taskflow, 'flow._id');
21 | const clusterId = get(taskflow, 'flow.meta.cluster._id');
22 |
23 | if (!actions) {
24 | return disabledButtons;
25 | }
26 |
27 | actions.forEach((el) => {
28 | switch (el) {
29 | case 'terminate':
30 | disabledButtons.terminate =
31 | !!get(network, `pending.terminate_taskflow_${taskflowId}`) ||
32 | !!get(network, `success.terminate_taskflow_${taskflowId}`);
33 | break;
34 | case 'terminateInstance':
35 | disabledButtons.terminateInstance =
36 | !!get(network, `pending.terminate_cluster_${clusterId}`) ||
37 | !!get(network, `success.terminate_cluster_${clusterId}`);
38 | break;
39 | case 'moveOffline':
40 | disabledButtons.moveOffline = !!get(network, 'pending.move_offline');
41 | break;
42 | default:
43 | break;
44 | }
45 | });
46 |
47 | return disabledButtons;
48 | }
49 |
--------------------------------------------------------------------------------
/src/utils/getNetworkError.js:
--------------------------------------------------------------------------------
1 | import get from './get';
2 |
3 | // checks the network errors, if there is a valid one it returns the error's message,
4 | // if there's no message it returns the status code and the status text
5 | function getNetworkErrorWithId(state, id) {
6 | if (
7 | get(state, `network.error.${id}`) &&
8 | !get(state, `network.error.${id}.invalid`)
9 | ) {
10 | if (get(state, `network.error.${id}.resp.data.message`)) {
11 | // resp.data.message
12 | return get(state, `network.error.${id}.resp.data.message`);
13 | } else if (get(state, `network.error.${id}.resp.response.data.message`)) {
14 | // resp.response.data.message
15 | return get(state, `network.error.${id}.resp.response.data.message`);
16 | } else if (get(state, `network.error.${id}.resp.message`)) {
17 | // resp.message
18 | return get(state, `network.error.${id}.resp.message`);
19 | }
20 | return `Error ${state.network.error[id].resp.status} (${
21 | state.network.error[id].resp.statusText
22 | })`; // status text
23 | }
24 | return '';
25 | }
26 |
27 | function getNetworkErrorWithArray(state, ids) {
28 | for (let i = 0; i < ids.length; i++) {
29 | const message = getNetworkErrorWithId(state, ids[i]);
30 | if (message) {
31 | return message;
32 | }
33 | }
34 | return '';
35 | }
36 |
37 | export default function getNetworkError(state, id) {
38 | if (Array.isArray(id)) {
39 | return getNetworkErrorWithArray(state, id);
40 | }
41 | return getNetworkErrorWithId(state, id);
42 | }
43 |
--------------------------------------------------------------------------------
/src/utils/logSort.js:
--------------------------------------------------------------------------------
1 | export default function logSort(entryA, entryB) {
2 | return Date.parse(entryA.created) < Date.parse(entryB.created);
3 | }
4 |
--------------------------------------------------------------------------------
/src/workflows/generic/components/root/EditProjectWithFileListing.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import AttachedFileListing from './AttachedFileListing';
5 |
6 | // ----------------------------------------------------------------------------
7 |
8 | export default function editProjectWithFiles(props) {
9 | return (
10 |
15 | );
16 | }
17 |
18 | // ----------------------------------------------------------------------------
19 |
20 | editProjectWithFiles.propTypes = {
21 | owner: PropTypes.func,
22 | parentProps: PropTypes.object,
23 | };
24 |
25 | editProjectWithFiles.defaultProps = {
26 | owner: undefined,
27 | parentProps: undefined,
28 | };
29 |
--------------------------------------------------------------------------------
/src/workflows/generic/components/root/EditSimulationWithFileListing.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import AttachedFileListing from './AttachedFileListing';
5 |
6 | // ----------------------------------------------------------------------------
7 |
8 | export default function editSimulationWithFiles(props) {
9 | return (
10 |
15 | );
16 | }
17 |
18 | // ----------------------------------------------------------------------------
19 |
20 | editSimulationWithFiles.propTypes = {
21 | owner: PropTypes.func,
22 | parentProps: PropTypes.object,
23 | };
24 |
25 | editSimulationWithFiles.defaultProps = {
26 | owner: undefined,
27 | parentProps: undefined,
28 | };
29 |
--------------------------------------------------------------------------------
/src/workflows/generic/components/steps/DocumentationHTML.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | /* eslint-disable react/no-danger */
5 | export default function renderHTML(props) {
6 | return
;
7 | }
8 | /* eslint-enable react/no-danger */
9 |
10 | renderHTML.propTypes = {
11 | staticContent: PropTypes.string,
12 | };
13 |
14 | renderHTML.defaultProps = {
15 | staticContent: '',
16 | };
17 |
--------------------------------------------------------------------------------
/src/workflows/index.js:
--------------------------------------------------------------------------------
1 | import NWChem from './nwchem/nwchem-simput';
2 | import NWChemExec from './nwchem/nwchem-exec';
3 | import NWChemNeb from './nwchem/nwchem-neb';
4 | import OpenFOAMTutorial from './openfoam/tutorials';
5 | import OpenFOAMWindTunnel from './openfoam/windtunnel';
6 | import PyFr from './pyfr';
7 | import Visualizer from './visualizer';
8 |
9 | const Workflows = {
10 | NWChem,
11 | NWChemExec,
12 | NWChemNeb,
13 | OpenFOAMTutorial,
14 | OpenFOAMWindTunnel,
15 | PyFr,
16 | Visualizer,
17 | };
18 |
19 | export const workflowNames = Object.keys(Workflows).map((value) => {
20 | const label = Workflows[value].name;
21 | return { value, label };
22 | });
23 |
24 | export default Workflows;
25 |
--------------------------------------------------------------------------------
/src/workflows/nwchem/common/steps/Introduction/content.html:
--------------------------------------------------------------------------------
1 |
2 |
Introduction
3 |
NWChem aims to provide its users with computational chemistry tools that are scalable both in their ability to treat large scientific computational chemistry problems efficiently, and in their use of available parallel computing resources from high-performance parallel supercomputers to conventional workstation clusters. NWChem software can handle:
4 |
5 | Biomolecules, nanostructures, and solid-state
6 | From quantum to classical, and all combinations
7 | Ground and excited-states
8 | Gaussian basis functions or plane-waves
9 | Scaling from one to thousands of processors
10 | Properties and relativistic effects
11 |
12 |
Find out more
13 |
14 |
--------------------------------------------------------------------------------
/src/workflows/nwchem/common/steps/Introduction/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import DocumentationHTML from '../../../../generic/components/steps/DocumentationHTML';
3 | import staticContent from './content.html';
4 |
5 | export default (props) => ;
6 |
--------------------------------------------------------------------------------
/src/workflows/nwchem/common/steps/Simulation/Start.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import JobSubmission from '../../../../generic/components/steps/JobSubmission';
3 |
4 | // ----------------------------------------------------------------------------
5 |
6 | const actionList = [
7 | { name: 'prepareJob', label: 'Start Simulation', icon: '' },
8 | ];
9 |
10 | // ----------------------------------------------------------------------------
11 |
12 | function clusterFilter(cluster) {
13 | return (
14 | 'config' in cluster &&
15 | 'nwchem' in cluster.config &&
16 | (cluster.config.nwchem && cluster.config.nwchem.enable)
17 | );
18 | }
19 |
20 | // ----------------------------------------------------------------------------
21 |
22 | function getPayload(props) {
23 | const nwFile =
24 | props.simulation.metadata.inputFolder.files.nw ||
25 | props.project.metadata.inputFolder.files.nw;
26 |
27 | return {
28 | input: {
29 | folder: {
30 | id: props.simulation.metadata.inputFolder._id,
31 | },
32 | project: {
33 | folder: {
34 | id: props.project.metadata.inputFolder._id,
35 | },
36 | },
37 | nwFile: {
38 | id: nwFile,
39 | },
40 | },
41 | output: {
42 | folder: {
43 | id: props.simulation.metadata.outputFolder._id,
44 | },
45 | },
46 | };
47 | }
48 |
49 | // ----------------------------------------------------------------------------
50 |
51 | export default (props) => (
52 |
58 | );
59 |
--------------------------------------------------------------------------------
/src/workflows/nwchem/nwchem-exec/components/root/NewSimulation.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import { FileUploadEntry } from '../../../../../panels/ItemEditor';
5 |
6 | // ----------------------------------------------------------------------------
7 |
8 | export default function newSimulation(props) {
9 | return (
10 |
11 |
17 |
23 |
24 | );
25 | }
26 |
27 | // ----------------------------------------------------------------------------
28 |
29 | newSimulation.propTypes = {
30 | owner: PropTypes.func,
31 | };
32 |
33 | newSimulation.defaultProps = {
34 | owner: undefined,
35 | };
36 |
--------------------------------------------------------------------------------
/src/workflows/nwchem/nwchem-exec/index.js:
--------------------------------------------------------------------------------
1 | import rootNewSimulation from './components/root/NewSimulation';
2 | import rootViewSimulation from '../../generic/components/root/ViewSimulation';
3 |
4 | import stepIntroduction from '../common/steps/Introduction';
5 | import stepSimulationStart from '../common/steps/Simulation/Start';
6 | import stepSimulationView from '../common/steps/Simulation/View';
7 |
8 | import logo from './logo.png';
9 |
10 | export default {
11 | name: 'NWChem (Runtime)',
12 | logo,
13 | requiredAttachments: {
14 | project: [],
15 | simulation: ['geometry', 'nw'],
16 | },
17 | components: {
18 | NewSimulation: rootNewSimulation,
19 | ViewSimulation: rootViewSimulation,
20 | },
21 | config: {
22 | cluster: {
23 | 'config.nwchem.enable': {
24 | type: 'bool',
25 | label: 'NWChem enabled',
26 | description: 'Check if the cluster is able to run NWChem simulation',
27 | },
28 | },
29 | },
30 | steps: {
31 | _order: ['Introduction', 'Simulation'],
32 | _disabled: [],
33 | _active: 'Introduction',
34 | _initial_state: {
35 | Introduction: {
36 | type: 'information',
37 | metadata: {},
38 | },
39 | Simulation: {
40 | type: 'output',
41 | metadata: {},
42 | },
43 | Visualization: {
44 | type: 'output',
45 | metadata: {},
46 | },
47 | },
48 | Introduction: {
49 | default: stepIntroduction,
50 | },
51 | Simulation: {
52 | default: stepSimulationStart,
53 | run: stepSimulationView,
54 | },
55 | },
56 | taskFlows: {
57 | Simulation: 'hpccloud.taskflow.nwchem.NWChemTaskFlow',
58 | },
59 | primaryJobs: {
60 | Simulation: 'pyfr_run',
61 | },
62 | labels: {
63 | Introduction: {
64 | default: 'Introduction',
65 | },
66 | Simulation: {
67 | default: 'Simulation',
68 | run: 'Simulation (running)',
69 | },
70 | },
71 | };
72 |
--------------------------------------------------------------------------------
/src/workflows/nwchem/nwchem-exec/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/src/workflows/nwchem/nwchem-exec/logo.png
--------------------------------------------------------------------------------
/src/workflows/nwchem/nwchem-neb/components/root/NewProject.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import { FileUploadEntry } from '../../../../../panels/ItemEditor';
5 |
6 | function extractFileName(name) {
7 | return (file) =>
8 | new Promise((accept, reject) => {
9 | accept({ [name]: file.name });
10 | });
11 | }
12 |
13 | export default function newProject(props) {
14 | return (
15 |
16 |
23 |
30 |
31 | );
32 | }
33 |
34 | newProject.propTypes = {
35 | owner: PropTypes.func,
36 | };
37 |
38 | newProject.defaultProps = {
39 | owner: undefined,
40 | };
41 |
--------------------------------------------------------------------------------
/src/workflows/nwchem/nwchem-neb/components/steps/Input.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import SimputReact from '../../../../generic/components/steps/SimputReact';
3 |
4 | // ----------------------------------------------------------------------------
5 |
6 | function simputModelDecorator(model, props) {
7 | // Add external data from project mesh
8 | if (!model.external) {
9 | model.external = {};
10 | }
11 |
12 | // Add start geometry
13 | model.external.startGeometry = props.project.metadata.startGeometry || '';
14 | model.external.endGeometry = props.project.metadata.endGeometry || '';
15 |
16 | return model;
17 | }
18 |
19 | // ----------------------------------------------------------------------------
20 |
21 | export default (props) => (
22 |
33 | );
34 |
--------------------------------------------------------------------------------
/src/workflows/nwchem/nwchem-neb/components/steps/SimulationView.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import * as SimulationViewHelper from '../../../common/steps/Simulation/View';
3 |
4 | const SimulationView = SimulationViewHelper.default;
5 |
6 | export default (props) => (
7 |
8 | );
9 |
--------------------------------------------------------------------------------
/src/workflows/nwchem/nwchem-neb/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/src/workflows/nwchem/nwchem-neb/logo.png
--------------------------------------------------------------------------------
/src/workflows/nwchem/nwchem-simput/components/root/NewProject.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import { FileUploadEntry } from '../../../../../panels/ItemEditor';
5 |
6 | function extractFileName(file) {
7 | return new Promise((accept, reject) => {
8 | const geometry = file.name;
9 | accept({ geometry });
10 | });
11 | }
12 |
13 | export default function newProject(props) {
14 | return (
15 |
22 | );
23 | }
24 |
25 | newProject.propTypes = {
26 | owner: PropTypes.func,
27 | };
28 |
29 | newProject.defaultProps = {
30 | owner: undefined,
31 | };
32 |
--------------------------------------------------------------------------------
/src/workflows/nwchem/nwchem-simput/components/steps/Input.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import SimputReact from '../../../../generic/components/steps/SimputReact';
3 |
4 | // ----------------------------------------------------------------------------
5 |
6 | function simputModelDecorator(model, props) {
7 | // Add external data from project mesh
8 | if (!model.external) {
9 | model.external = {};
10 | }
11 |
12 | // Add external
13 | if (props.project.metadata.geometry) {
14 | model.external.input = props.project.metadata.geometry;
15 | }
16 |
17 | return model;
18 | }
19 |
20 | // ----------------------------------------------------------------------------
21 |
22 | export default (props) => (
23 |
34 | );
35 |
--------------------------------------------------------------------------------
/src/workflows/nwchem/nwchem-simput/index.js:
--------------------------------------------------------------------------------
1 | import rootNewProject from './components/root/NewProject';
2 | import rootViewSimulation from '../../generic/components/root/ViewSimulation';
3 |
4 | import stepIntroduction from '../common/steps/Introduction';
5 | import stepInput from './components/steps/Input';
6 | import stepSimulationStart from '../common/steps/Simulation/Start';
7 | import stepSimulationView from '../common/steps/Simulation/View';
8 |
9 | import logo from './logo.png';
10 |
11 | export default {
12 | name: 'NWChem',
13 | logo,
14 | requiredAttachments: {
15 | project: ['geometry'],
16 | simulation: [],
17 | },
18 | components: {
19 | NewProject: rootNewProject,
20 | ViewSimulation: rootViewSimulation,
21 | },
22 | config: {
23 | cluster: {
24 | 'config.nwchem.enable': {
25 | type: 'bool',
26 | label: 'NWChem enabled',
27 | description: 'Check if the cluster is able to run NWChem simulation',
28 | },
29 | },
30 | },
31 | steps: {
32 | _order: ['Introduction', 'Input', 'Simulation'],
33 | _disabled: ['Simulation'],
34 | _initial_state: {
35 | Introduction: {
36 | type: 'input',
37 | metadata: {
38 | alwaysAvailable: true,
39 | },
40 | },
41 | Input: {
42 | type: 'input',
43 | metadata: {},
44 | },
45 | Simulation: {
46 | type: 'output',
47 | metadata: {},
48 | },
49 | },
50 | Introduction: {
51 | default: stepIntroduction,
52 | },
53 | Input: {
54 | default: stepInput,
55 | },
56 | Simulation: {
57 | default: stepSimulationStart,
58 | run: stepSimulationView,
59 | },
60 | },
61 | taskFlows: {
62 | Simulation: 'hpccloud.taskflow.nwchem.NWChemTaskFlow',
63 | },
64 | primaryJobs: {
65 | Simulation: 'pyfr_run',
66 | },
67 | labels: {
68 | Introduction: {
69 | default: 'Introduction',
70 | },
71 | Input: {
72 | default: 'Input definition',
73 | },
74 | Simulation: {
75 | default: 'Simulation',
76 | run: 'Simulation (running)',
77 | },
78 | },
79 | };
80 |
--------------------------------------------------------------------------------
/src/workflows/nwchem/nwchem-simput/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/src/workflows/nwchem/nwchem-simput/logo.png
--------------------------------------------------------------------------------
/src/workflows/openfoam/tutorials/components/steps/Input/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import SimputReact from '../../../../../generic/components/steps/SimputReact';
3 |
4 | // ----------------------------------------------------------------------------
5 |
6 | export default (props) => (
7 |
17 | );
18 |
--------------------------------------------------------------------------------
/src/workflows/openfoam/tutorials/components/steps/Introduction/content.html:
--------------------------------------------------------------------------------
1 |
2 |
Introduction
3 |
OpenFOAM is a free, open source computational fluid dynamics (CFD) software package released by the OpenFOAM Foundation. It has a large user base across most areas of engineering and science, from both commercial and academic organisations. OpenFOAM has an extensive range of features to solve anything from complex fluid flows involving chemical reactions, turbulence and heat transfer, to solid dynamics and electromagnetics.
4 |
5 |
Find out more
6 |
7 |
--------------------------------------------------------------------------------
/src/workflows/openfoam/tutorials/components/steps/Introduction/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import DocumentationHTML from '../../../../../generic/components/steps/DocumentationHTML';
3 | import staticContent from './content.html';
4 |
5 | export default (props) => ;
6 |
--------------------------------------------------------------------------------
/src/workflows/openfoam/tutorials/components/steps/Simulation/Start.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import JobSubmission from '../../../../../generic/components/steps/JobSubmission';
3 |
4 | // ----------------------------------------------------------------------------
5 |
6 | const actionList = [
7 | { name: 'prepareJob', label: 'Start Simulation', icon: '' },
8 | ];
9 |
10 | // ----------------------------------------------------------------------------
11 |
12 | function clusterFilter(cluster) {
13 | return (
14 | 'config' in cluster &&
15 | 'openfoam' in cluster.config &&
16 | (cluster.config.openfoam && cluster.config.openfoam.enable)
17 | );
18 | }
19 |
20 | // ----------------------------------------------------------------------------
21 |
22 | function getPayload(props) {
23 | return {
24 | input: {
25 | folder: {
26 | id: props.simulation.metadata.inputFolder._id,
27 | },
28 | shFile: {
29 | id: props.simulation.metadata.inputFolder.files.sh,
30 | },
31 | },
32 | output: {
33 | folder: {
34 | id: props.simulation.metadata.outputFolder._id,
35 | },
36 | },
37 | };
38 | }
39 |
40 | // ----------------------------------------------------------------------------
41 |
42 | export default (props) => (
43 |
49 | );
50 |
--------------------------------------------------------------------------------
/src/workflows/openfoam/tutorials/components/steps/Visualization/Start.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import JobSubmission from '../../../../../generic/components/steps/JobSubmission';
3 |
4 | // ----------------------------------------------------------------------------
5 |
6 | const actionList = [
7 | { name: 'prepareJob', label: 'Start Visualization', icon: '' },
8 | ];
9 |
10 | // ----------------------------------------------------------------------------
11 |
12 | function clusterFilter(cluster) {
13 | return (
14 | 'config' in cluster &&
15 | 'paraview' in cluster.config &&
16 | 'installDir' in cluster.config.paraview &&
17 | cluster.config.paraview.installDir
18 | );
19 | }
20 |
21 | // ----------------------------------------------------------------------------
22 |
23 | function getTaskflowMetaData(props) {
24 | const dataDir = props.simulation.steps.Visualization.metadata.dataDir;
25 | const fileName = props.simulation.steps.Visualization.metadata.fileName;
26 | return {
27 | dataDir,
28 | fileName,
29 | sessionId: props.simulation.steps.Visualization.folderId,
30 | };
31 | }
32 |
33 | // ----------------------------------------------------------------------------
34 |
35 | function getPayload(props) {
36 | const sessionKey = props.simulation.steps.Visualization.folderId;
37 | const dataDir = props.simulation.steps.Visualization.metadata.dataDir;
38 | const fileName = props.simulation.steps.Visualization.metadata.fileName;
39 |
40 | return {
41 | dataDir, // where the output for the sim will be
42 | fileName, // the file to load
43 | sessionKey, // for pvw, we use this later for connecting,
44 | output: {
45 | folder: {
46 | id: props.simulation.steps.Visualization.folderId,
47 | },
48 | },
49 | };
50 | }
51 |
52 | // ----------------------------------------------------------------------------
53 |
54 | export default function openFoamStart(props) {
55 | return (
56 |
63 | );
64 | }
65 |
--------------------------------------------------------------------------------
/src/workflows/openfoam/tutorials/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/src/workflows/openfoam/tutorials/logo.png
--------------------------------------------------------------------------------
/src/workflows/openfoam/windtunnel/components/root/NewProject.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import { FileUploadEntry } from '../../../../../panels/ItemEditor';
5 |
6 | function extractFileName(name) {
7 | return (file) =>
8 | new Promise((accept, reject) => {
9 | accept({ [name]: file.name });
10 | });
11 | }
12 |
13 | export default function newProject(props) {
14 | return (
15 |
16 |
23 |
24 | );
25 | }
26 |
27 | newProject.propTypes = {
28 | owner: PropTypes.func,
29 | };
30 |
31 | newProject.defaultProps = {
32 | owner: undefined,
33 | };
34 |
--------------------------------------------------------------------------------
/src/workflows/openfoam/windtunnel/components/steps/Geometry/Geometry.mcss:
--------------------------------------------------------------------------------
1 | .controlPanel {
2 | flex: 1;
3 | display: flex;
4 | flex-direction: column;
5 | position: relative;
6 | width: 100%;
7 | height: 100px;
8 | }
9 |
10 | .line {
11 | flex: none;
12 | display: flex;
13 | align-items: center;
14 | }
15 |
16 | .section {
17 | flex: 1;
18 | display: flex;
19 | align-items: center;
20 | margin: 0 5px;
21 | }
22 |
23 | .label {
24 | flex: none;
25 | font-weight: bold;
26 | line-height: 30px;
27 | height: 30px;
28 | }
29 |
30 | .clickLabel {
31 | composes: label;
32 | cursor: pointer;
33 | }
34 |
35 | .view {
36 | display: flex;
37 | }
38 |
39 | .input {
40 | flex: 1;
41 | height: 26px;
42 | margin: 2px 5px;
43 | min-width: 5px;
44 | }
45 |
46 | .vertical {
47 | flex: 1;
48 | display: flex;
49 | flex-direction: column;
50 | align-items: stretch;
51 | }
--------------------------------------------------------------------------------
/src/workflows/openfoam/windtunnel/components/steps/Input/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import SimputReact from '../../../../../generic/components/steps/SimputReact';
3 |
4 | // ----------------------------------------------------------------------------
5 |
6 | function simputModelDecorator(model, props) {
7 | // Add external data from project mesh
8 | if (!model.external) {
9 | model.external = {};
10 | }
11 | if (!model.external.geometryName) {
12 | model.external.geometryName = props.project.metadata.mesh.split('.')[0];
13 | }
14 | if (!model.external.groupName && model.external.geometryName) {
15 | model.external.groupName = `${model.external.geometryName}Group`;
16 | }
17 |
18 | // Push Geometry step data to simput...
19 | if (props.simulation.steps.Geometry.metadata.assign) {
20 | const assign = JSON.parse(props.simulation.steps.Geometry.metadata.assign);
21 | while (assign.length) {
22 | const item = assign.pop();
23 | let container = model.data;
24 | item.path.forEach((key, idx, array) => {
25 | if (!container[key]) {
26 | if (Number.isInteger(array[idx + 1])) {
27 | container[key] = [];
28 | } else {
29 | container[key] = {};
30 | }
31 | }
32 | container = container[key];
33 | });
34 | container.value = item.value;
35 | }
36 | }
37 |
38 | console.log(JSON.stringify(model, null, 2));
39 |
40 | return model;
41 | }
42 |
43 | // ----------------------------------------------------------------------------
44 |
45 | export default (props) => (
46 |
59 | );
60 |
--------------------------------------------------------------------------------
/src/workflows/openfoam/windtunnel/components/steps/Introduction/content.html:
--------------------------------------------------------------------------------
1 |
2 |
Introduction
3 |
OpenFOAM is a free, open source computational fluid dynamics (CFD) software package released by the OpenFOAM Foundation. It has a large user base across most areas of engineering and science, from both commercial and academic organisations. OpenFOAM has an extensive range of features to solve anything from complex fluid flows involving chemical reactions, turbulence and heat transfer, to solid dynamics and electromagnetics.
4 |
5 |
Find out more
6 |
7 |
--------------------------------------------------------------------------------
/src/workflows/openfoam/windtunnel/components/steps/Introduction/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import DocumentationHTML from '../../../../../generic/components/steps/DocumentationHTML';
3 | import staticContent from './content.html';
4 |
5 | export default (props) => ;
6 |
--------------------------------------------------------------------------------
/src/workflows/openfoam/windtunnel/components/steps/Simulation/Start.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import JobSubmission from '../../../../../generic/components/steps/JobSubmission';
3 |
4 | // ----------------------------------------------------------------------------
5 |
6 | const actionList = [
7 | { name: 'prepareJob', label: 'Start Simulation', icon: '' },
8 | ];
9 |
10 | // ----------------------------------------------------------------------------
11 |
12 | function clusterFilter(cluster) {
13 | return (
14 | 'config' in cluster &&
15 | 'openfoam' in cluster.config &&
16 | (cluster.config.openfoam && cluster.config.openfoam.enable)
17 | );
18 | }
19 |
20 | // ----------------------------------------------------------------------------
21 |
22 | function getPayload(props) {
23 | return {
24 | input: {
25 | folder: {
26 | id: props.simulation.metadata.inputFolder._id,
27 | },
28 | __export__: {
29 | id: props.simulation.metadata.inputFolder.files.__export__,
30 | },
31 | project: {
32 | folder: {
33 | id: props.project.metadata.inputFolder._id,
34 | },
35 | },
36 | },
37 | output: {
38 | folder: {
39 | id: props.simulation.metadata.outputFolder._id,
40 | },
41 | },
42 | };
43 | }
44 |
45 | // ----------------------------------------------------------------------------
46 |
47 | export default (props) => (
48 |
54 | );
55 |
--------------------------------------------------------------------------------
/src/workflows/openfoam/windtunnel/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/src/workflows/openfoam/windtunnel/logo.png
--------------------------------------------------------------------------------
/src/workflows/pyfr/components/root/NewSimulation.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | /* eslint-disable import/extensions */
5 | import Simput from 'Simput';
6 | /* eslint-enable import/extensions */
7 |
8 | import { FileUploadEntry } from '../../../../panels/ItemEditor';
9 | import { dispatch } from '../../../../redux';
10 | import * as NetActions from '../../../../redux/actions/network';
11 |
12 | // ----------------------------------------------------------------------------
13 |
14 | function onParseError(message) {
15 | dispatch(NetActions.errorNetworkCall('New Simulation', { message }));
16 | }
17 |
18 | // ----------------------------------------------------------------------------
19 |
20 | function parseAndValidate(file, owner) {
21 | return new Promise((accept, reject) => {
22 | const reader = new FileReader();
23 | reader.onloadend = () => {
24 | if (reader.readyState !== FileReader.DONE) {
25 | onParseError('Ini file is invalid');
26 | reject();
27 | }
28 | try {
29 | Simput.types.pyfr.parse('pyfr', { 'pyfr.ini': reader.result });
30 | } catch (e) {
31 | onParseError(`Error parsing file:\n${e}`);
32 | owner().removeMetadata('ini');
33 | reject();
34 | }
35 | accept({});
36 | };
37 |
38 | reader.readAsText(file);
39 | });
40 | }
41 |
42 | // ----------------------------------------------------------------------------
43 |
44 | export default function pyFrNewSimulation(props) {
45 | return (
46 |
47 |
54 |
55 | * will override project ini, not required
56 |
57 |
58 | );
59 | }
60 |
61 | // ----------------------------------------------------------------------------
62 |
63 | pyFrNewSimulation.propTypes = {
64 | owner: PropTypes.func,
65 | };
66 |
67 | pyFrNewSimulation.defaultProps = {
68 | owner: undefined,
69 | };
70 |
--------------------------------------------------------------------------------
/src/workflows/pyfr/components/steps/Input/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import SimputReact from '../../../../generic/components/steps/SimputReact';
3 |
4 | // ----------------------------------------------------------------------------
5 |
6 | function simputModelDecorator(model, props) {
7 | // Add external data from project mesh
8 | if (!model.external) {
9 | model.external = {};
10 | }
11 | if (!model.external['boundary-names']) {
12 | model.external['boundary-names'] = {};
13 | }
14 | if (props.project.metadata.boundaries) {
15 | model.external['boundary-names'] = {};
16 | props.project.metadata.boundaries.forEach((name) => {
17 | model.external['boundary-names'][name] = name;
18 | });
19 | }
20 |
21 | // Ensure we will never see the backend view
22 | if (!model.hideViews) {
23 | model.hideViews = ['backend'];
24 | }
25 | if (model.hideViews && model.hideViews.indexOf('backend') === -1) {
26 | model.hideViews.push('backend');
27 | }
28 | return model;
29 | }
30 |
31 | // ----------------------------------------------------------------------------
32 |
33 | export default (props) => (
34 |
45 | );
46 |
--------------------------------------------------------------------------------
/src/workflows/pyfr/components/steps/Introduction/content.html:
--------------------------------------------------------------------------------
1 |
2 |
Introduction
3 |
PyFR is an open-source Python based framework for solving advection-diffusion type problems on streaming architectures using the Flux Reconstruction approach of Huynh. The framework is designed to solve a range of governing systems on mixed unstructured grids containing various element types. It is also designed to target a range of hardware platforms via use of an in-built domain specific language derived from the Mako templating engine. The current release (PyFR 1.2.0) has the following capabilities:
4 |
5 | Governing Equations - Euler, Navier Stokes
6 | Dimensionality - 2D, 3D
7 | Element Types - Triangles, Quadrilaterals, Hexahedra, Prisms, Tetrahedra, Pyramids
8 | Platforms - CPU Clusters, Nvidia GPU Clusters, AMD GPU Clusters
9 | Spatial Discretisation - High-Order Flux Reconstruction
10 | Temporal Discretisation - Explicit Runge-Kutta
11 | Precision - Single, Double
12 | Mesh Files Imported - Gmsh (.msh)
13 | Solution Files Exported - Unstructured VTK (.vtu, .pvtu)
14 |
15 |
Find out more
16 |
17 |
--------------------------------------------------------------------------------
/src/workflows/pyfr/components/steps/Introduction/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import DocumentationHTML from '../../../../generic/components/steps/DocumentationHTML';
3 | import staticContent from './content.html';
4 |
5 | export default (props) => ;
6 |
--------------------------------------------------------------------------------
/src/workflows/pyfr/components/steps/Visualization/Start.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import JobSubmission from '../../../../generic/components/steps/JobSubmission';
3 |
4 | // ----------------------------------------------------------------------------
5 |
6 | const actionList = [
7 | { name: 'prepareJob', label: 'Start Visualization', icon: '' },
8 | ];
9 |
10 | // ----------------------------------------------------------------------------
11 |
12 | function clusterFilter(cluster) {
13 | return (
14 | 'config' in cluster &&
15 | 'paraview' in cluster.config &&
16 | 'installDir' in cluster.config.paraview &&
17 | cluster.config.paraview.installDir
18 | );
19 | }
20 |
21 | // ----------------------------------------------------------------------------
22 |
23 | function getTaskflowMetaData(props) {
24 | const dataDir = props.simulation.steps.Visualization.metadata.dataDir;
25 | const fileName = props.simulation.steps.Visualization.metadata.fileName;
26 |
27 | return {
28 | dataDir,
29 | fileName,
30 | sessionId: props.simulation.steps.Visualization.folderId,
31 | };
32 | }
33 |
34 | // ----------------------------------------------------------------------------
35 |
36 | function getPayload(props) {
37 | const sessionKey = props.simulation.steps.Visualization.folderId;
38 | const dataDir = props.simulation.steps.Visualization.metadata.dataDir;
39 | const fileName = props.simulation.steps.Visualization.metadata.fileName;
40 |
41 | return {
42 | dataDir, // where the output for the sim will be
43 | fileName, // the file to load
44 | sessionKey, // for pvw, we use this later for connecting,
45 | output: {
46 | folder: {
47 | id: props.simulation.steps.Visualization.folderId,
48 | },
49 | },
50 | };
51 | }
52 |
53 | // ----------------------------------------------------------------------------
54 |
55 | export default function openFoamStart(props) {
56 | return (
57 |
64 | );
65 | }
66 |
--------------------------------------------------------------------------------
/src/workflows/pyfr/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/src/workflows/pyfr/logo.png
--------------------------------------------------------------------------------
/src/workflows/visualizer/components/root/NewSimulation.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import { FileUploadEntry } from '../../../../panels/ItemEditor';
5 |
6 | const newSim = (props) => (
7 |
8 | );
9 |
10 | newSim.propTypes = {
11 | owner: PropTypes.func,
12 | };
13 |
14 | newSim.defaultProps = {
15 | owner: undefined,
16 | };
17 |
18 | export default newSim;
19 |
--------------------------------------------------------------------------------
/src/workflows/visualizer/components/steps/Introduction/content.html:
--------------------------------------------------------------------------------
1 |
2 |
ParaView
3 |
4 | ParaView is an open-source, multi-platform data analysis and visualization
5 | application. ParaView users can quickly build visualizations to analyze
6 | their data using qualitative and quantitative techniques. The data
7 | exploration can be done interactively in 3D or programmatically using
8 | ParaView’s batch processing capabilities.
9 |
10 |
11 | ParaView was developed to analyze extremely large datasets using
12 | distributed memory computing resources. It can be run on supercomputers
13 | to analyze datasets of petascale size as well as on laptops for smaller
14 | data, has become an integral tool in many national laboratories,
15 | universities and industry, and has won several awards related to high
16 | performance computation.
17 |
18 |
19 |
Find out more
20 |
21 |
--------------------------------------------------------------------------------
/src/workflows/visualizer/components/steps/Introduction/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import DocumentationHTML from '../../../../generic/components/steps/DocumentationHTML';
3 | import staticContent from './content.html';
4 |
5 | export default (props) => ;
6 |
--------------------------------------------------------------------------------
/src/workflows/visualizer/components/steps/Visualization/Start.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import JobSubmission from '../../../../generic/components/steps/JobSubmission';
3 |
4 | // ----------------------------------------------------------------------------
5 |
6 | const actionList = [
7 | { name: 'prepareJob', label: 'Start Visualization', icon: '' },
8 | ];
9 |
10 | // ----------------------------------------------------------------------------
11 |
12 | function clusterFilter(cluster) {
13 | return (
14 | 'config' in cluster &&
15 | 'paraview' in cluster.config &&
16 | 'installDir' in cluster.config.paraview &&
17 | cluster.config.paraview.installDir
18 | );
19 | }
20 |
21 | // ----------------------------------------------------------------------------
22 |
23 | function getTaskflowMetaData(props) {
24 | console.log('getTaskflowMetaData', props);
25 | return {
26 | sessionId: props.simulation._id,
27 | };
28 | }
29 |
30 | // ----------------------------------------------------------------------------
31 |
32 | function getPayload(props) {
33 | console.log('getPayload', props);
34 | const sessionKey = props.simulation._id;
35 |
36 | return {
37 | sessionKey, // for pvw, we use this later for connecting,
38 | input: {
39 | file: {
40 | id: props.simulation.metadata.inputFolder.files.dataset,
41 | },
42 | },
43 | output: {
44 | folder: {
45 | id: props.simulation.metadata.outputFolder._id,
46 | },
47 | },
48 | };
49 | }
50 |
51 | // ----------------------------------------------------------------------------
52 |
53 | export default function openFoamStart(props) {
54 | return (
55 |
62 | );
63 | }
64 |
--------------------------------------------------------------------------------
/src/workflows/visualizer/index.js:
--------------------------------------------------------------------------------
1 | import rootNewSimulation from './components/root/NewSimulation';
2 | import rootViewSimulation from '../generic/components/root/ViewSimulation';
3 |
4 | import stepIntroduction from './components/steps/Introduction';
5 | import stepStartViz from './components/steps/Visualization/Start';
6 | import stepVisualizer from './components/steps/Visualization/View';
7 |
8 | import logo from './logo.png';
9 |
10 | export default {
11 | name: 'ParaViewWeb',
12 | logo,
13 | components: {
14 | NewSimulation: rootNewSimulation,
15 | ViewSimulation: rootViewSimulation,
16 | },
17 | config: {
18 | cluster: {
19 | 'config.paraview.installDir': {
20 | type: 'text',
21 | label: 'ParaView Directory',
22 | description: 'Path to the home directory of ParaView.',
23 | },
24 | },
25 | },
26 | steps: {
27 | _order: ['Introduction', 'Visualization'],
28 | _initial_state: {
29 | Introduction: {
30 | type: 'information',
31 | metadata: {
32 | alwaysAvailable: true,
33 | },
34 | },
35 | Visualization: {
36 | type: 'output',
37 | metadata: {
38 | disabled: false,
39 | },
40 | },
41 | },
42 | Introduction: {
43 | default: stepIntroduction,
44 | },
45 | Visualization: {
46 | default: stepStartViz,
47 | run: stepVisualizer,
48 | },
49 | },
50 | taskFlows: {
51 | Visualization: 'hpccloud.taskflow.paraview.visualizer.ParaViewTaskFlow',
52 | },
53 | primaryJobs: {
54 | Visualization: 'paraview',
55 | },
56 | labels: {
57 | Introduction: {
58 | default: 'Introduction',
59 | },
60 | Visualization: {
61 | default: 'Visualization',
62 | run: 'Visualization (running)',
63 | },
64 | },
65 | };
66 |
--------------------------------------------------------------------------------
/src/workflows/visualizer/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/src/workflows/visualizer/logo.png
--------------------------------------------------------------------------------
/style/ActiveList.mcss:
--------------------------------------------------------------------------------
1 | .list {
2 | list-style: none;
3 | padding: 0;
4 | margin: 0;
5 | overflow-y: auto;
6 | }
7 |
8 | .selectable {
9 | box-sizing: border-box;
10 | color: #888;
11 | cursor: pointer;
12 | margin: 0;
13 | overflow: hidden;
14 | padding: 6px 15px;
15 | text-overflow: ellipsis;
16 | transition: all 0.35s ease;
17 | user-select: none;
18 | white-space: nowrap;
19 | }
20 |
21 | .unselectable {
22 | composes: selectable;
23 | cursor: not-allowed;
24 | color: #ddd;
25 | }
26 |
27 | .active {
28 | composes: selectable;
29 |
30 | background-color: #F0F0F0;
31 | color: #111;
32 | font-weight: bold;
33 | }
34 |
--------------------------------------------------------------------------------
/style/Layout.mcss:
--------------------------------------------------------------------------------
1 | .textLeft {
2 | text-align: left;
3 | }
4 |
5 | .textCenter {
6 | text-align: center;
7 | }
8 |
9 | .textRight {
10 | text-align: right;
11 | }
12 |
13 | .verticalFlexContainer {
14 | display: flex;
15 | flex-direction: column;
16 | justify-content: flex-start;
17 | align-items: stretch;
18 | }
19 |
20 | .horizontalFlexContainer {
21 | display: flex;
22 | flex-direction: row;
23 | justify-content: flex-start;
24 | align-items: stretch;
25 | }
26 |
27 | .rightRow {
28 | display: flex;
29 | flex-direction: row;
30 | justify-content: flex-end;
31 | align-items: center;
32 | }
33 |
34 | .flexItem {
35 | flex: 1;
36 | }
37 |
38 | .flexGrow {
39 | flex-grow: 1;
40 | }
41 |
42 | .horizontalCenter {
43 | justify-content: center;
44 | }
45 |
46 | .verticalCenter {
47 | align-items: center;
48 | }
49 |
50 | .fullWidth {
51 | width: 100%;
52 | }
53 |
54 | .halfHeight {
55 | height: 50vh;
56 | }
57 |
58 | .horizontalPadding {
59 | padding-left: 10px;
60 | padding-right: 10px;
61 | }
62 |
63 | .verticalPadding {
64 | padding-top: 5px;
65 | padding-bottom: 5px;
66 | }
67 |
68 | .linePadding {
69 | composes: horizontalPadding;
70 | composes: verticalPadding;
71 | }
72 |
73 | .topBar {
74 | composes: horizontalFlexContainer;
75 | composes: horizontalPadding;
76 |
77 | justify-content: space-between;
78 | align-items: center;
79 | flex: 1;
80 |
81 | height: 2.4em;
82 | line-height: 2.4em;
83 | }
84 |
85 | .subBar {
86 | composes: topBar;
87 | padding-left: 0;
88 | padding-right: 0;
89 | }
90 |
91 | .noMargin {
92 | margin-top: 0;
93 | margin-right: 0;
94 | margin-bottom: 0;
95 | margin-left: 0;
96 | }
97 |
--------------------------------------------------------------------------------
/style/Modal.mcss:
--------------------------------------------------------------------------------
1 | .modalContainer {
2 | position: absolute;
3 | z-index: 100;
4 | width: 75%;
5 | height: 400px;
6 | top: 0;
7 | left: 0;
8 | transform: translate(12.5%, 4em);
9 | box-shadow: 0px 7px 10px gray;
10 | overflow: hidden;
11 | background-color: white;
12 | border: 1px solid #ccc;
13 | transition: transform 0.5s ease, width 0.5s ease, height 0.5s ease;
14 | }
15 |
16 | .modalContainer.fullscreen {
17 | transform: translate(0, 0);
18 | height: 100%;
19 | width: 100%;
20 | }
21 |
22 | .modal {
23 | color: black;
24 | padding: 1em 2em 0;
25 | overflow: auto;
26 | height: calc(100% - 38px);
27 | white-space: pre;
28 | }
29 |
30 | .header {
31 | background-color: #eee;
32 | border-bottom: 1px solid #ccc;
33 | display: flex;
34 | justify-content: space-between;
35 | align-items: center;
36 | padding: 6px 20px;
37 | }
38 |
39 | .title {
40 | composes: title from 'HPCCloudStyle/JobMonitor.mcss';
41 | margin: 0;
42 | }
43 |
44 | .icon {
45 | color: #333;
46 | cursor: pointer;
47 | }
48 |
49 | .closeIcon {
50 | composes: fa from 'font-awesome/css/font-awesome.css';
51 | composes: fa-fw from 'font-awesome/css/font-awesome.css';
52 | composes: fa-times from 'font-awesome/css/font-awesome.css';
53 | font-size: 1.45em;
54 | margin-left: 10px;
55 | composes: icon;
56 | }
57 |
58 | .closeIcon:hover {
59 | color: #c54d57;
60 | }
61 |
62 | .fullscreenIcon {
63 | composes: fa from 'font-awesome/css/font-awesome.css';
64 | composes: fa-fw from 'font-awesome/css/font-awesome.css';
65 | composes: fa-arrows-alt from 'font-awesome/css/font-awesome.css';
66 | composes: icon;
67 | }
68 |
69 | .fullscreenIcon:hover {
70 | color: #18e;
71 | }
72 |
--------------------------------------------------------------------------------
/style/Preferences.mcss:
--------------------------------------------------------------------------------
1 | .linkSection {
2 | display: flex;
3 | justify-content: center;
4 | }
5 |
6 | .link {
7 | display: inline-block;
8 | padding: 60px 30px;
9 | width: 140px;
10 | text-align: center;
11 | border: 1px solid lightgrey;
12 | margin: 5px;
13 | transition: background-color 2s linear;
14 | }
15 |
16 | .link:hover{
17 | background-color: lightblue;
18 | }
19 |
20 | /* Icons */
21 | .preferenceIcon {
22 | composes: fa from 'font-awesome/css/font-awesome.css';
23 | composes: fa-fw from 'font-awesome/css/font-awesome.css';
24 | }
25 |
26 | .userIcon {
27 | composes: preferenceIcon;
28 | composes: fa-user from 'font-awesome/css/font-awesome.css';
29 | }
30 |
31 | .groupIcon {
32 | composes: preferenceIcon;
33 | composes: fa-users from 'font-awesome/css/font-awesome.css';
34 | }
35 |
36 | .clusterIcon {
37 | composes: preferenceIcon;
38 | composes: fa-share-alt from 'font-awesome/css/font-awesome.css';
39 | }
40 |
41 | .ec2Icon {
42 | composes: preferenceIcon;
43 | composes: fa-mixcloud from 'font-awesome/css/font-awesome.css';
44 | }
45 |
46 | .volumesIcon {
47 | composes: preferenceIcon;
48 | composes: fa-hdd-o from 'font-awesome/css/font-awesome.css';
49 | }
50 |
51 | .statusIcon {
52 | composes: preferenceIcon;
53 | composes: fa-info from 'font-awesome/css/font-awesome.css';
54 | }
55 |
56 | .networkIcon {
57 | composes: preferenceIcon;
58 | composes: fa-terminal from 'font-awesome/css/font-awesome.css';
59 | }
60 |
61 | .networkPendingIcon {
62 | composes: preferenceIcon;
63 | composes: fa-ellipsis-h from 'font-awesome/css/font-awesome.css';
64 | composes: colorBlue from 'HPCCloudStyle/Theme.mcss';
65 | }
66 |
67 | .networkSuccessIcon {
68 | composes: preferenceIcon;
69 | composes: fa-check from 'font-awesome/css/font-awesome.css';
70 | composes: colorGreen from 'HPCCloudStyle/Theme.mcss';
71 | }
72 |
73 | .networkErrorIcon {
74 | composes: preferenceIcon;
75 | composes: fa-warning from 'font-awesome/css/font-awesome.css';
76 | composes: colorRed from 'HPCCloudStyle/Theme.mcss';
77 | }
78 |
--------------------------------------------------------------------------------
/style/Profile.mcss:
--------------------------------------------------------------------------------
1 | .container {
2 | display: flex;
3 | flex-direction: column;
4 | justify-content: flex-start;
5 | align-items: stretch;
6 | }
7 |
8 | .header {
9 | display: flex;
10 | flex-direction: row;
11 | justify-content: space-between;
12 | align-items: center;
13 | margin-top: 10px;
14 | padding: 0 20px;
15 | }
16 |
17 | .buttons {
18 | text-align: right;
19 | }
20 |
21 | .noProfileMsg {
22 | position: absolute;
23 | width: 100%;
24 | height: 100%;
25 | text-align: center;
26 | }
27 |
28 |
29 | .button {
30 | composes: fa from 'font-awesome/css/font-awesome.css';
31 | composes: fa-fw from 'font-awesome/css/font-awesome.css';
32 | cursor: pointer;
33 | margin-left: 10px;
34 | padding: 2px 5px;
35 | }
36 |
37 | .addIcon {
38 | composes: button;
39 | composes: fa-plus from 'font-awesome/css/font-awesome.css';
40 | }
41 |
42 | .removeIcon {
43 | composes: button;
44 | composes: fa-minus from 'font-awesome/css/font-awesome.css';
45 | }
46 |
47 | .content {
48 | border: solid 1px #ccc;
49 | border-radius: 5px;
50 | margin: 5px 20px;
51 |
52 | display: flex;
53 | flex-direction: row;
54 | justify-content: flex-start;
55 | align-items: stretch;
56 | overflow: hidden;
57 | }
58 |
59 | .menu {
60 | min-width: 150px;
61 | max-width: 300px;
62 | width: 10%;
63 | border-right: solid 1px #ccc;
64 | overflow-y: auto;
65 | }
66 |
67 | .subContent {
68 | flex: 1;
69 | padding-bottom: 15px;
70 | padding-top: 5px;
71 | }
72 |
73 | .hiddenSubContent {
74 | composes: subContent;
75 | visibility: hidden;
76 | }
77 |
--------------------------------------------------------------------------------
/style/States.mcss:
--------------------------------------------------------------------------------
1 | .isHidden {
2 | display: none;
3 | }
4 |
5 | .isClickable {
6 | cursor: pointer;
7 | transition: color .25s ease;
8 | }
9 |
10 | .isClickable:hover {
11 | /* colorBlue */
12 | color: #18e;
13 | }
14 |
15 | .isBusy {
16 | composes: colorGreen from 'HPCCloudStyle/Theme.mcss';
17 | transition: color .25s ease;
18 | }
19 |
--------------------------------------------------------------------------------
/style/TableListing.mcss:
--------------------------------------------------------------------------------
1 | .container {
2 | composes: verticalFlexContainer from './Layout.mcss';
3 | }
4 |
5 | .table {
6 | composes: table from 'bootstrap/dist/css/bootstrap.css';
7 | composes: table-striped from 'bootstrap/dist/css/bootstrap.css';
8 | }
9 |
10 | .table > tbody > tr > td {
11 | cursor: pointer;
12 | vertical-align: middle;
13 | }
14 |
15 | .table > thead > tr > th {
16 | cursor: default;
17 | }
18 |
19 | .table > thead > tr > th > span {
20 | cursor: pointer;
21 | }
22 |
23 | .table > tbody > tr {
24 | transition: all 0.2s ease;
25 | }
26 |
27 | .table > tbody > tr:not(.selected):hover {
28 | background-color: #efefef;
29 | }
30 |
31 | .table > tbody > tr > td:first-child {
32 | text-align: center;
33 | }
34 |
35 | .table > tbody > tr > td:last-child {
36 | text-align: center;
37 | }
38 |
39 | .table > tbody > tr > td:last-child:hover {
40 | /* colorBlue, cannot compose this */
41 | color: #18e;
42 | }
43 |
44 | /* Selection styling rules */
45 | .selected {
46 | background-color: #aaa;
47 | }
48 |
49 | .table > tbody > tr:nth-of-type(odd).selected {
50 | background-color: #aaa;
51 | }
52 |
53 | /* action icons */
54 | .addIcon {
55 | composes: fa from 'font-awesome/css/font-awesome.css';
56 | composes: fa-plus from 'font-awesome/css/font-awesome.css';
57 | }
58 |
59 | .deleteIcon {
60 | composes: fa from 'font-awesome/css/font-awesome.css';
61 | composes: fa-trash from 'font-awesome/css/font-awesome.css';
62 | }
63 |
64 | .sortedDesc {
65 | composes: fa from 'font-awesome/css/font-awesome.css';
66 | composes: fa-fw from 'font-awesome/css/font-awesome.css';
67 | composes: fa-sort-desc from 'font-awesome/css/font-awesome.css';
68 | }
69 |
70 | .sortedAsc {
71 | composes: fa from 'font-awesome/css/font-awesome.css';
72 | composes: fa-fw from 'font-awesome/css/font-awesome.css';
73 | composes: fa-sort-asc from 'font-awesome/css/font-awesome.css';
74 | }
75 |
76 | .visHidden {
77 | visibility: hidden;
78 | }
--------------------------------------------------------------------------------
/style/Toaster.mcss:
--------------------------------------------------------------------------------
1 | .ToastContainer {
2 | composes: errorBox from 'HPCCloudStyle/Theme.mcss';
3 | position: fixed;
4 | visibility: visible;
5 | width: 100%;
6 | bottom: 8px;
7 | min-height: 40px;
8 | margin: 0 auto;
9 | padding: 9px 18px;
10 | font-size: 1.1em;
11 | border-radius: 0;
12 | opacity: 1;
13 | transition-delay:0s;
14 | transition: all 0.20s linear; /* fade in */
15 | }
16 |
17 | .ToastClearButton {
18 | height: 30px;
19 | width: 30px;
20 | position: absolute;
21 | right: 10px;
22 | margin-top: -5px;
23 | border: 1px solid #c98a88;
24 | border-radius: 6px;
25 | background-color: transparent;
26 | }
27 |
28 | .isHidden {
29 | visibility: hidden;
30 | opacity: 0;
31 | transition-delay:0s;
32 | transition: visibility 0s linear 1s, opacity 1s ease; /* fade out */
33 | }
34 |
35 | .CloseIcon {
36 | composes: fa from 'font-awesome/css/font-awesome.css';
37 | composes: fa-fw from 'font-awesome/css/font-awesome.css';
38 | composes: fa-close from 'font-awesome/css/font-awesome.css';
39 | margin-left: -2px;
40 | }
--------------------------------------------------------------------------------
/style/Toolbar.mcss:
--------------------------------------------------------------------------------
1 | .container {
2 | composes: subBar from 'HPCCloudStyle/Layout.mcss';
3 | background: #ccc;
4 | composes: colorBlack from 'HPCCloudStyle/Theme.mcss';
5 | }
6 |
7 | .filter {
8 | border-radius: 1em;
9 | padding: 2px 15px;
10 | border: 1px solid #ccc;
11 | line-height: 1.25em;
12 | }
13 |
14 | .breadcrumb {
15 | flex: 1;
16 | display: flex;
17 | justify-content: flex-start;
18 | }
19 |
20 | .toolbarTab {
21 | composes: colorBlack from 'HPCCloudStyle/Theme.mcss';
22 | }
23 |
24 | .breadcrumb a, .toolbarTab a {
25 | padding: 1px 10px;
26 | }
27 |
28 | .breadcrumb a:first-child, .toolbarTab a:first-child {
29 | padding-left: 12px;
30 | }
31 |
32 | .actions {
33 | flex: 1;
34 | display: flex;
35 | justify-content: flex-start;
36 | flex-direction: row-reverse;
37 | align-items: center;
38 | }
39 |
40 | .actionButton {
41 | composes: isClickable from 'HPCCloudStyle/States.mcss';
42 | padding: 7px 17px;
43 | }
44 |
45 | .title {
46 | flex: 1;
47 | text-align: center;
48 | cursor: default;
49 | }
50 |
--------------------------------------------------------------------------------
/style/Visualizer.mcss:
--------------------------------------------------------------------------------
1 | .button {
2 | composes: fa from 'font-awesome/css/font-awesome.css';
3 | composes: fa-fw from 'font-awesome/css/font-awesome.css';
4 | cursor: pointer;
5 | }
6 |
7 | .resetCameraButton {
8 | composes: button;
9 | composes: fa-arrows-alt from 'font-awesome/css/font-awesome.css';
10 |
11 | }
12 |
13 | .toggleMenuButton {
14 | composes: button;
15 | composes: fa-bars from 'font-awesome/css/font-awesome.css';
16 | margin-right: 10px;
17 | }
18 |
19 | .playButton {
20 | composes: button;
21 | composes: fa-play from 'font-awesome/css/font-awesome.css';
22 | }
23 |
24 | .stopButton {
25 | composes: button;
26 | composes: fa-stop from 'font-awesome/css/font-awesome.css';
27 | }
28 |
29 | .previousButton {
30 | composes: button;
31 | composes: fa-chevron-left from 'font-awesome/css/font-awesome.css';
32 | padding-right: 0;
33 | }
34 |
35 | .nextButton {
36 | composes: button;
37 | composes: fa-chevron-right from 'font-awesome/css/font-awesome.css';
38 | padding-left: 0;
39 | }
40 |
41 | .busy {
42 | composes: button;
43 | composes: fa-spinner from 'font-awesome/css/font-awesome.css';
44 | composes: fa-pulse from 'font-awesome/css/font-awesome.css';
45 | padding: 0;
46 | }
47 |
48 | .menu {
49 | position: absolute;
50 | top: 2.2em;
51 | right: 10px;
52 | height: calc(100vh - 4.5em);
53 | width: 300px;
54 | background-color: #eee;
55 | z-index: 2;
56 | border-radius: 5px;
57 | color: #111;
58 | font-size: 20px;
59 | transition: opacity 0.5s;
60 | opacity: .75;
61 | overflow: hidden;
62 | }
63 |
64 | .menu:hover {
65 | opacity: 1;
66 | }
67 |
68 | .hiddenMenu {
69 | composes: menu;
70 | z-index: -1;
71 | opacity: 0;
72 | }
73 |
74 | .viewport {
75 | position: absolute;
76 | top: 2.4em;
77 | left: 0;
78 | right: 0;
79 | height: calc(100vh - 4.9em);
80 | overflow: hidden;
81 | }
82 |
--------------------------------------------------------------------------------
/style/global.mcss:
--------------------------------------------------------------------------------
1 | a, a:visited {
2 | /* color: inherit; */
3 | text-decoration: none !important;
4 | transition: color .25s ease;
5 | }
6 |
7 | a:hover, a:active {
8 | color: #18e;
9 | text-decoration: none;
10 | }
11 |
12 | a:focus {
13 | outline: none;
14 | text-decoration: none;
15 | }
16 |
17 | input, textarea {
18 | box-sizing: border-box;
19 | }
20 |
21 | input[type=submit] {
22 | /*composes: button*/
23 | background-color: white;
24 | border: 1px solid lightgrey;
25 | padding: 5px 8px;
26 | margin: 3px;
27 | text-transform: uppercase;
28 | font-size: 0.80em;
29 | }
30 |
31 | textarea:focus, input:focus {
32 | outline-width: 0px;
33 | border-color: #888;
34 | }
35 |
36 | :global
37 | .lmr {
38 | margin-right: 5px;
39 | }
40 |
41 | :global
42 | .is-clickable {
43 | cursor: pointer;
44 | }
45 |
46 | :global
47 | .is-hidden {
48 | display: none;
49 | }
50 |
51 | :global
52 | .Outline * {
53 | user-select: none;
54 | }
55 |
56 | :global
57 | .Outline > ul > li > i.fa-check {
58 | display: none;
59 | }
60 |
61 | :global
62 | .Outline > ul > li > ul {
63 | padding-left: 15px;
64 | }
65 |
--------------------------------------------------------------------------------
/style/logo-mono.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kitware/HPCCloud/1a489d4fb7decbfa8bd4692b8e66dec5b05f3ce1/style/logo-mono.png
--------------------------------------------------------------------------------
/style/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
10 |
11 |
12 |
14 |
16 |
17 |
22 |
23 |
--------------------------------------------------------------------------------
/test/components/AccessHelper.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import * as AccessHelper from '../../src/utils/AccessHelper';
3 |
4 | /* global describe it */
5 |
6 | describe('userHasAccess', () => {
7 | // levels -> 0: READ, 1: WRITE, 2: ADMIN
8 | it('rejects users without sufficient access', () => {
9 | const user = { _id: 'abc123', groups: ['abc', 'def', 'ghi'] };
10 | const accessObj = { users: [], groups: [] };
11 | expect(AccessHelper.userHasAccess(user, accessObj, 'NONE')).toEqual(false);
12 | expect(AccessHelper.userHasAccess(user, accessObj, 'WRITE')).toEqual(false);
13 |
14 | // group
15 | accessObj.groups.push({ id: 'abc', flags: [], level: 0 });
16 | expect(AccessHelper.userHasAccess(user, accessObj, 'WRITE')).toEqual(false);
17 | accessObj.groups.pop();
18 |
19 | // user
20 | accessObj.users.push({ id: 'abc123', flags: [], level: 1 });
21 | expect(AccessHelper.userHasAccess(user, accessObj, 'ADMIN')).toEqual(false);
22 | });
23 |
24 | it('accepts users with sufficient access', () => {
25 | const user = { _id: 'abc123', groups: ['abc', 'def', 'ghi'] };
26 | const accessObj = { users: [], groups: [] };
27 |
28 | // group
29 | accessObj.groups.push({ id: 'abc', flags: [], level: 0 });
30 | expect(AccessHelper.userHasAccess(user, accessObj, 'READ')).toEqual(true);
31 |
32 | accessObj.groups[0].level = 1;
33 | expect(AccessHelper.userHasAccess(user, accessObj, 'WRITE')).toEqual(true);
34 | accessObj.groups.pop();
35 |
36 | // users
37 | accessObj.users.push({ id: 'abc123', flags: [], level: 2 });
38 | expect(AccessHelper.userHasAccess(user, accessObj, 'ADMIN')).toEqual(true);
39 |
40 | // works with numbers as access
41 | expect(AccessHelper.userHasAccess(user, accessObj, 2)).toEqual(true);
42 | });
43 | });
44 |
--------------------------------------------------------------------------------
/test/components/ButtonBar.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import React from 'react';
3 | import TestUtils from 'react-dom/test-utils';
4 | import ShallowRenderer from 'react-test-renderer/shallow';
5 | import ButtonBar from '../../src/panels/ButtonBar';
6 |
7 | /* global describe it */
8 |
9 | describe('ButtonBar', () => {
10 | it('should render an empty bar', () => {
11 | const el = TestUtils.renderIntoDocument( );
12 | const buttons = TestUtils.findAllInRenderedTree(
13 | el,
14 | (component) => component.tagName === 'BUTTON'
15 | );
16 | expect(buttons.length).toEqual(0);
17 | });
18 |
19 | it('should render a buttons', () => {
20 | const actions = [
21 | { name: 'Reset', disabled: false },
22 | { name: 'Submit', disabled: false },
23 | ];
24 | const el = TestUtils.renderIntoDocument( );
25 | const buttons = TestUtils.findAllInRenderedTree(
26 | el,
27 | (component) => component.tagName === 'BUTTON'
28 | );
29 | expect(buttons.length).toEqual(2);
30 | });
31 |
32 | it('should be hidden', () => {
33 | const actions = [
34 | { name: 'Reset', disabled: false },
35 | { name: 'Submit', disabled: false },
36 | ];
37 | const renderer = new ShallowRenderer();
38 | renderer.render( );
39 | const result = renderer.getRenderOutput();
40 | expect(result).toEqual(null); // when not visible it renders null
41 | });
42 | });
43 |
--------------------------------------------------------------------------------
/test/components/Format.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 |
3 | import { formatFileSize, formatTime } from '../../src/utils/Format';
4 |
5 | /* global describe it */
6 |
7 | describe('formatTime', () => {
8 | it('formats time to hh:mm:ss.ms', () => {
9 | // 15:32:00.000, the formatter takes unix seconds
10 | const date = new Date(1474061520000);
11 | const time = date.valueOf() / 1000;
12 | const hours =
13 | date.getHours().toString().length === 1
14 | ? `0${date.getHours()}`
15 | : date.getHours();
16 | // safe to test in whole numbered timezones (e.g. not Newfoundland or Nepal)
17 | expect(formatTime(time)).toEqual(`${hours}:32:00.000`);
18 |
19 | expect(formatTime(time + 1)).toEqual(`${hours}:32:01.000`);
20 |
21 | expect(formatTime(time + 0.001)).toEqual(`${hours}:32:00.001`);
22 | });
23 | });
24 |
25 | describe('formatFileSize', () => {
26 | it('catches wrong file sizes', () => {
27 | expect(formatFileSize(0)).toEqual('0 bytes');
28 |
29 | expect(formatFileSize(Infinity)).toEqual('unknown size');
30 |
31 | expect(formatFileSize(NaN)).toEqual('unknown size');
32 | });
33 |
34 | it('formats bytes', () => {
35 | expect(formatFileSize(1)).toEqual('1.0 bytes');
36 |
37 | expect(formatFileSize(1000)).toEqual('1000.0 bytes');
38 |
39 | expect(formatFileSize(1024 + 512)).toEqual('1.5 KB');
40 |
41 | const MB = 1024 * 1024;
42 | expect(formatFileSize(MB)).toEqual('1.0 MB');
43 |
44 | const GB = 1024 * 1024 * 1024;
45 | expect(formatFileSize(GB)).toEqual('1.0 GB');
46 | });
47 |
48 | it('formats with precision', () => {
49 | expect(formatFileSize(1024 + 512, 2)).toEqual('1.50 KB');
50 | });
51 | });
52 |
--------------------------------------------------------------------------------
/test/components/get.js:
--------------------------------------------------------------------------------
1 | import expect from 'expect';
2 | import get from '../../src/utils/get';
3 |
4 | /* global describe it */
5 |
6 | describe('get', () => {
7 | const obj = {
8 | prop1: {
9 | subpropA: {
10 | subsubPropA: 'my prop A',
11 | subsubPropB: 'B',
12 | },
13 | arrayProp: [0, 1, 2, 3, 4],
14 | },
15 | };
16 |
17 | it('fetches elements given path', () => {
18 | expect(get(obj, 'prop1.subpropA.subsubPropB')).toEqual('B');
19 | });
20 |
21 | it('fetches length of array and string', () => {
22 | expect(get(obj, 'prop1.arrayProp.length')).toEqual(5);
23 |
24 | expect(get(obj, 'prop1.subpropA.subsubPropA.length')).toEqual(9);
25 | });
26 |
27 | it("returns false if object doesn't exist", () => {
28 | expect(get(obj.fakeprop, 'someprop')).toBe(false);
29 |
30 | expect(get(obj, 'fakeprop.someprop')).toBe(false);
31 | });
32 |
33 | it('returns false when property not found', () => {
34 | expect(get(obj, 'fakeprop')).toBe(false);
35 |
36 | expect(get(obj, 'fakeprop.wow')).toBe(false);
37 | });
38 |
39 | it('returns false when final property not found', () => {
40 | expect(get(obj, 'prop1.subpropC')).toBe(false);
41 |
42 | expect(get(obj, 'prop1.subpropA.wow')).toBe(false);
43 | });
44 |
45 | it('returns 0 when the last property in a keypath is length', () => {
46 | expect(get(obj, 'prop1.fakeprop.length')).toEqual(0);
47 | });
48 | });
49 |
--------------------------------------------------------------------------------
/test/config/karma.base.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 |
3 | module.exports = {
4 | basePath: '..',
5 | client: {
6 | // set to true if you're trying to read some console.log statement
7 | captureConsole: false,
8 | },
9 | singleRun: true,
10 | frameworks: ['jasmine'],
11 | browsers: ['ChromeHeadless'],
12 | reporters: ['spec', 'coverage'],
13 | plugins: [
14 | 'karma-jasmine',
15 | 'karma-chrome-launcher',
16 | 'karma-spec-reporter',
17 | 'karma-webpack',
18 | 'karma-coverage',
19 | 'karma-sourcemap-loader',
20 | ],
21 | preprocessors: {
22 | 'tests.webpack.js': ['webpack', 'sourcemap'],
23 | },
24 | webpackMiddleware: {
25 | noInfo: true,
26 | stats: {
27 | chunks: false,
28 | },
29 | },
30 | coverageReporter: {
31 | reporters: [
32 | {
33 | type: 'html',
34 | dir: 'coverage/',
35 | subdir: 'html',
36 | },
37 | {
38 | type: 'lcovonly',
39 | dir: 'coverage',
40 | subdir: 'lcov',
41 | },
42 | ],
43 | },
44 | };
45 |
--------------------------------------------------------------------------------
/test/config/webpack.test.js:
--------------------------------------------------------------------------------
1 | // webpack for redux tests
2 | const path = require('path');
3 | const webpack = require('webpack');
4 |
5 | const appRules = require('../../config/rules-hpccloud.js');
6 | const pvwRules = require('../../config/rules-pvw.js');
7 | const visualizerRules = require('../../config/rules-visualizer.js');
8 | const vtkjsRules = require('../../config/rules-vtkjs.js');
9 | const wslinkRules = require('../../config/rules-wslink.js');
10 | const simputRules = require('../../config/rules-simput.js');
11 |
12 | const eslintrcPath = path.join(__dirname, '../../.eslintrc.js');
13 | const plugins = [];
14 |
15 | plugins.push(
16 | new webpack.DefinePlugin({
17 | KARMA_TEST_RUNNER: JSON.stringify(true),
18 | })
19 | );
20 |
21 | module.exports = {
22 | plugins,
23 | devtool: 'cheap-module-source-map',
24 | mode: 'development',
25 | module: {
26 | rules: [
27 | {
28 | test: /\.js$/,
29 | exclude: /node_modules|test/,
30 | loader: 'istanbul-instrumenter-loader',
31 | enforce: 'post',
32 | },
33 | {
34 | test: /\.js$/,
35 | exclude: /node_modules/,
36 | loader: 'eslint-loader',
37 | enforce: 'pre',
38 | options: { configFile: eslintrcPath },
39 | },
40 | ].concat(
41 | appRules,
42 | pvwRules,
43 | visualizerRules,
44 | vtkjsRules,
45 | wslinkRules,
46 | simputRules
47 | ),
48 | },
49 | resolve: {
50 | alias: {
51 | 'PVWStyle/ReactProperties/PropertyPanel.mcss': path.join(
52 | __dirname,
53 | '../../node_modules/simput/style/PropertyPanel.mcss'
54 | ),
55 | PVWStyle: path.join(__dirname, '../../node_modules/paraviewweb/style'),
56 | // see that file for why we do this.
57 | workflows: path.join(__dirname, '../../test/helpers/workflowNames'),
58 | // Constants.js uses Theme.mcss
59 | HPCCloudStyle: path.join(__dirname, '../../style'),
60 | SimputStyle: path.join(__dirname, '../../node_modules/simput/style'),
61 | },
62 | },
63 | externals: {
64 | Simput: 'Simput',
65 | },
66 | };
67 |
--------------------------------------------------------------------------------
/test/contexts/tests.all.js:
--------------------------------------------------------------------------------
1 | const reduxContext = require.context('../redux', true, /\.js$/);
2 | reduxContext.keys().forEach(reduxContext);
3 |
4 | const componentContext = require.context('../components', true, /\.js$/);
5 | componentContext.keys().forEach(componentContext);
6 |
--------------------------------------------------------------------------------
/test/contexts/tests.components.js:
--------------------------------------------------------------------------------
1 | const context = require.context('../components', true, /\.js$/);
2 | context.keys().forEach(context);
3 |
--------------------------------------------------------------------------------
/test/contexts/tests.redux.js:
--------------------------------------------------------------------------------
1 | const reduxContext = require.context('../redux', true, /\.js$/);
2 | reduxContext.keys().forEach(reduxContext);
3 |
--------------------------------------------------------------------------------
/test/helpers/complete.js:
--------------------------------------------------------------------------------
1 | export default function(done) {
2 | return (err) => {
3 | if (err) {
4 | done.fail(err);
5 | }
6 | done();
7 | };
8 | }
9 |
--------------------------------------------------------------------------------
/test/helpers/deepFreeze.js:
--------------------------------------------------------------------------------
1 | function isObject(val) {
2 | return (
3 | typeof val === 'object' &&
4 | !Array.isArray(val) &&
5 | !(val instanceof RegExp) &&
6 | !(val instanceof String) &&
7 | !(val instanceof Number)
8 | );
9 | }
10 |
11 | export default function deepFreeze(obj) {
12 | Object.keys(obj).forEach((key) => {
13 | var el = obj[key];
14 | if (isObject(el)) {
15 | deepFreeze(obj[key]);
16 | }
17 | });
18 | return Object.freeze(obj);
19 | }
20 |
--------------------------------------------------------------------------------
/test/helpers/workflowNames.js:
--------------------------------------------------------------------------------
1 | // redux/reducers/projects takes a workflows/index.js just for the workflow names
2 | // however by requiring that file we require a ton of react components which we're
3 | // not interested in testing here. So, we resolve 'workflows' to this file when testing.
4 | module.exports.workflowNames = [
5 | {
6 | value: 'PyFr',
7 | label: 'PyFR',
8 | },
9 | {
10 | value: 'PyFrExec',
11 | label: 'PyFR (Runtime)',
12 | },
13 | {
14 | value: 'Visualizer',
15 | label: 'ParaViewWeb',
16 | },
17 | ];
18 |
--------------------------------------------------------------------------------
/test/karma.all.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | var wpConfig = require('./config/webpack.test.js');
3 | var karmaConfig = require('./config/karma.base.js');
4 |
5 | wpConfig.entry = {
6 | 'tests.all.js': './test/contexts/tests.all.js',
7 | };
8 |
9 | karmaConfig.webpack = wpConfig;
10 |
11 | karmaConfig.files = [
12 | 'node_modules/babel-polyfill/dist/polyfill.js',
13 | 'dist/simput-pyfr.js',
14 | 'dist/simput-nwchem.js',
15 | 'dist/simput-nwchem-neb.js',
16 | 'dist/simput-openfoam-tutorials.js',
17 | 'dist/simput-openfoam-windtunnel.js',
18 | 'test/contexts/tests.all.js'
19 | ];
20 |
21 | karmaConfig.preprocessors = {
22 | 'test/contexts/tests.all.js': ['webpack', 'sourcemap'],
23 | };
24 |
25 | karmaConfig.coverageReporters = {
26 | dir: 'coverage/all',
27 | reporters: [
28 | {
29 | type: 'html',
30 | subdir: 'html'
31 | }, {
32 | type: 'lcovonly',
33 | subdir: 'lcov'
34 | },
35 | ],
36 | };
37 |
38 | module.exports = function(config) {
39 | config.set(karmaConfig);
40 | };
41 |
--------------------------------------------------------------------------------
/test/karma.component.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | var wpConfig = require('./config/webpack.test.js');
3 | var karmaConfig = require('./config/karma.base.js');
4 |
5 | wpConfig.entry = {
6 | 'tests.components.js': './test/contexts/tests.components.js',
7 | };
8 |
9 | karmaConfig.webpack = wpConfig;
10 |
11 | karmaConfig.files = [
12 | 'node_modules/babel-polyfill/dist/polyfill.js',
13 | 'dist/simput-pyfr.js',
14 | 'dist/simput-nwchem.js',
15 | 'dist/simput-nwchem-neb.js',
16 | 'dist/simput-openfoam-tutorials.js',
17 | 'dist/simput-openfoam-windtunnel.js',
18 | 'test/contexts/tests.components.js'
19 | ];
20 |
21 | karmaConfig.preprocessors = {
22 | 'test/contexts/tests.components.js': ['webpack', 'sourcemap'],
23 | };
24 |
25 | karmaConfig.coverageReporters = {
26 | dir: 'coverage/components',
27 | reporters: [
28 | {
29 | type: 'html',
30 | subdir: 'html'
31 | }, {
32 | type: 'lcovonly',
33 | subdir: 'lcov'
34 | },
35 | ],
36 | };
37 |
38 | module.exports = function(config) {
39 | config.set(karmaConfig);
40 | };
41 |
--------------------------------------------------------------------------------
/test/karma.redux.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | var wpConfig = require('./config/webpack.test.js');
3 | var karmaConfig = require('./config/karma.base.js');
4 |
5 | wpConfig.entry = {
6 | 'tests.redux.js': './test/contexts/tests.redux.js',
7 | };
8 |
9 | karmaConfig.webpack = wpConfig;
10 |
11 | karmaConfig.files = [
12 | 'node_modules/babel-polyfill/dist/polyfill.js',
13 | 'dist/simput-pyfr.js',
14 | 'dist/simput-nwchem.js',
15 | 'dist/simput-nwchem-neb.js',
16 | 'dist/simput-openfoam-tutorials.js',
17 | 'dist/simput-openfoam-windtunnel.js',
18 | 'test/contexts/tests.redux.js'
19 | ];
20 |
21 | karmaConfig.preprocessors = {
22 | 'test/contexts/tests.redux.js': ['webpack', 'sourcemap'],
23 | };
24 |
25 | karmaConfig.coverageReporters = {
26 | dir: 'coverage/redux',
27 | reporters: [
28 | {
29 | type: 'html',
30 | subdir: 'html'
31 | }, {
32 | type: 'lcovonly',
33 | subdir: 'lcov'
34 | },
35 | ]
36 | };
37 |
38 | module.exports = function(config) {
39 | config.set(karmaConfig);
40 | };
41 |
--------------------------------------------------------------------------------
/test/sampleData/awsClusters.js:
--------------------------------------------------------------------------------
1 | export default [
2 | {
3 | _id: 'a1',
4 | config: {
5 | launch: {
6 | params: {
7 | extra_rules: [
8 | {
9 | cidr_ip: '100',
10 | from_port: 9000,
11 | proto: 'tcp',
12 | to_port: 9000,
13 | },
14 | ],
15 | gpu: 0,
16 | master_instance_ami: 'ami-wow',
17 | master_instance_type: 't2.nano',
18 | node_instance_ami: 'ami-wow',
19 | node_instance_count: 0,
20 | node_instance_type: 't2.nano',
21 | source_cidr_ip: '100',
22 | },
23 | spec: 'ec2',
24 | },
25 | scheduler: {
26 | type: 'sge',
27 | },
28 | },
29 | name: '0001',
30 | profileId: 'p1',
31 | status: 'running',
32 | type: 'ec2',
33 | },
34 | {
35 | _id: 'b2',
36 | config: {
37 | host: '100',
38 | launch: {
39 | params: {
40 | extra_rules: [
41 | {
42 | cidr_ip: '100',
43 | from_port: 9000,
44 | proto: 'tcp',
45 | to_port: 9000,
46 | },
47 | ],
48 | gpu: 0,
49 | master_instance_ami: 'ami-wow',
50 | master_instance_type: 't2.nano',
51 | node_instance_ami: 'ami-wow',
52 | node_instance_count: 1,
53 | node_instance_type: 't2.nano',
54 | source_cidr_ip: '100',
55 | },
56 | spec: 'ec2',
57 | },
58 | scheduler: {
59 | type: 'sge',
60 | },
61 | },
62 | name: 'my new node',
63 | profileId: 'q2',
64 | status: 'running',
65 | type: 'ec2',
66 | },
67 | ];
68 |
--------------------------------------------------------------------------------
/test/sampleData/awsState.js:
--------------------------------------------------------------------------------
1 | export default {
2 | list: [
3 | {
4 | _id: '574c8a770640fd3f1a3b377a',
5 | accessKeyId: 'aradomstringofcharacters',
6 | availabilityZone: 'us-north-2a',
7 | name: 'northerly',
8 | publicIPs: false,
9 | regionHost: 'ec2.us-north-2.amazonaws.com',
10 | regionName: 'us-west-2',
11 | status: 'available',
12 | },
13 | ],
14 | active: 0,
15 | pending: false,
16 | mapById: {
17 | '574c8a770640fd3f1a3b377a': {
18 | _id: '574c8a770640fd3f1a3b377a',
19 | accessKeyId: 'aradomstringofcharacters',
20 | availabilityZone: 'us-north-2a',
21 | name: 'northerly',
22 | publicIPs: false,
23 | regionHost: 'ec2.us-north-2.amazonaws.com',
24 | regionName: 'us-north-2',
25 | status: 'available',
26 | },
27 | },
28 | };
29 |
--------------------------------------------------------------------------------
/test/sampleData/machines.js:
--------------------------------------------------------------------------------
1 | export default {
2 | 'eu-central-1': {
3 | 'General purpose': [
4 | {
5 | id: 't2.nano',
6 | cpu: '1',
7 | memory: '0.5 GiB',
8 | storage: 'EBS only',
9 | family: 'General purpose',
10 | price: '0.0075000000',
11 | gpu: 0,
12 | },
13 | ],
14 | 'Storage optimized': [
15 | {
16 | id: 'i2.xlarge',
17 | cpu: '4',
18 | memory: '30.5 GiB',
19 | storage: '1 x 800 SSD',
20 | family: 'Storage optimized',
21 | price: '1.0130000000',
22 | gpu: 0,
23 | },
24 | {
25 | id: 'd2.xlarge',
26 | cpu: '4',
27 | memory: '30.5 GiB',
28 | storage: '3 x 2000 HDD',
29 | family: 'Storage optimized',
30 | price: '0.7940000000',
31 | gpu: 0,
32 | },
33 | ],
34 | },
35 | 'us-west-2': {
36 | 'General purpose': [
37 | {
38 | id: 't2.nano',
39 | cpu: '1',
40 | memory: '0.5 GiB',
41 | storage: 'EBS only',
42 | family: 'General purpose',
43 | price: '0.0100000000',
44 | gpu: 0,
45 | },
46 | {
47 | id: 't2.micro',
48 | cpu: '1',
49 | memory: '1 GiB',
50 | storage: 'EBS only',
51 | family: 'General purpose',
52 | price: '0.0200000000',
53 | gpu: 0,
54 | },
55 | ],
56 | 'Storage optimized': [
57 | {
58 | id: 'i2.xlarge',
59 | cpu: '4',
60 | memory: '30.5 GiB',
61 | storage: '1 x 800 SSD',
62 | family: 'Storage optimized',
63 | price: '0.8530000000',
64 | gpu: 0,
65 | },
66 | {
67 | id: 'd2.xlarge',
68 | cpu: '4',
69 | memory: '30.5 GiB',
70 | storage: '3 x 2000 HDD',
71 | family: 'Storage optimized',
72 | price: '0.6900000000',
73 | gpu: 0,
74 | },
75 | ],
76 | },
77 | };
78 |
--------------------------------------------------------------------------------
/test/sampleData/projectsData.js:
--------------------------------------------------------------------------------
1 | // GET /projects with two sample projects inside
2 | export default [
3 | {
4 | _id: '574c84270640fd3f1a3b3747',
5 | access: {
6 | groups: [],
7 | users: [
8 | {
9 | id: '574c841b0640fd3f1a3b3741',
10 | level: 2,
11 | },
12 | ],
13 | },
14 | created: '2016-05-30T18:19:19.405000+00:00',
15 | description: '',
16 | folderId: '574c84270640fd3f1a3b3745',
17 | metadata: {
18 | inputFolder: {
19 | _id: '574c84270640fd3f1a3b3749',
20 | files: {},
21 | },
22 | outputFolder: {
23 | _id: '574c84270640fd3f1a3b3748',
24 | files: {},
25 | },
26 | },
27 | name: 'proj 1',
28 | steps: ['Introduction', 'Simulation', 'Visualization'],
29 | type: 'PyFrExec',
30 | updated: '2016-05-30T18:19:19.461000+00:00',
31 | userId: '574c841b0640fd3f1a3b3741',
32 | },
33 | {
34 | _id: '574f1e440640fd086c69303a',
35 | access: {
36 | groups: [],
37 | users: [
38 | {
39 | id: '574c841b0640fd3f1a3b3741',
40 | level: 2,
41 | },
42 | ],
43 | },
44 | created: '2016-06-01T17:41:24.468000+00:00',
45 | description: '',
46 | folderId: '574f1e440640fd086c693038',
47 | metadata: {
48 | inputFolder: {
49 | _id: '574f1e440640fd086c69303c',
50 | files: {},
51 | },
52 | outputFolder: {
53 | _id: '574f1e440640fd086c69303b',
54 | files: {},
55 | },
56 | },
57 | name: 'proj 2',
58 | steps: ['Introduction', 'Visualization'],
59 | type: 'Visualizer',
60 | updated: '2016-06-01T17:41:24.518000+00:00',
61 | userId: '574c841b0640fd3f1a3b3741',
62 | },
63 | ];
64 |
--------------------------------------------------------------------------------
/test/sampleData/runFormState.js:
--------------------------------------------------------------------------------
1 | export default {
2 | EC2: {
3 | profile: 'ec2Id',
4 | machine: {
5 | id: 't2.nano',
6 | cpu: '1',
7 | memory: '0.5 GiB',
8 | storage: 'EBS only',
9 | family: 'General purpose',
10 | price: '0.0065000000',
11 | gpu: 0,
12 | },
13 | clusterSize: '',
14 | volumeSize: '',
15 | cluster: null,
16 | },
17 | Traditional: {
18 | profile: 'tradId',
19 | runtime: {
20 | numberOfGpusPerNode: 1,
21 | numberOfSlots: 1,
22 | queue: '',
23 | },
24 | },
25 | };
26 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const webpack = require('webpack');
3 |
4 | const appRules = require('./config/rules-hpccloud.js');
5 | const linterRules = require('./config/rules-linter.js');
6 | const pvwRules = require('./config/rules-pvw.js');
7 | const visualizerRules = require('./config/rules-visualizer.js');
8 | const vtkjsRules = require('./config/rules-vtkjs.js');
9 | const wslinkRules = require('./config/rules-wslink.js');
10 | const simputRules = require('./config/rules-simput.js');
11 |
12 | const entry = path.join(__dirname, 'src/app.js');
13 | const plugins = [];
14 |
15 | plugins.push(
16 | new webpack.DefinePlugin({
17 | KARMA_TEST_RUNNER: JSON.stringify(false),
18 | })
19 | );
20 |
21 | module.exports = {
22 | plugins,
23 | entry,
24 | output: {
25 | path: path.join(__dirname, './dist'),
26 | filename: 'HPCCloud.js',
27 | },
28 | module: {
29 | rules: [
30 | {
31 | test: entry,
32 | loader: 'expose-loader?HPCCloud',
33 | },
34 | ].concat(
35 | linterRules,
36 | appRules,
37 | pvwRules,
38 | visualizerRules,
39 | vtkjsRules,
40 | wslinkRules,
41 | simputRules
42 | ),
43 | },
44 | resolve: {
45 | alias: {
46 | 'PVWStyle/ReactProperties/PropertyPanel.mcss': path.resolve(
47 | './node_modules/simput/style/PropertyPanel.mcss'
48 | ),
49 | PVWStyle: path.join(__dirname, './node_modules/paraviewweb/style'),
50 | VisualizerStyle: path.join(
51 | __dirname,
52 | './node_modules/pvw-visualizer/style'
53 | ),
54 | SimputStyle: path.resolve('./node_modules/simput/style'),
55 | HPCCloudStyle: path.resolve('./style'),
56 | workflows: path.resolve('./src/workflows'),
57 | },
58 | },
59 | externals: {
60 | Simput: 'Simput',
61 | },
62 | devServer: {
63 | contentBase: './dist/',
64 | port: 9999,
65 | proxy: {
66 | '/api/*': 'http://localhost:8080',
67 | '/static/*': 'http://localhost:8080',
68 | },
69 | },
70 | };
71 |
--------------------------------------------------------------------------------