├── .dockerignore ├── .eslintignore ├── .gitignore ├── CHANGELOG.md ├── README.md ├── TODO.md ├── config ├── docker │ ├── Dockerfile │ └── Dockerfile.release ├── env.js ├── jest │ ├── CSSStub.js │ └── FileStub.js ├── nginx │ ├── mime.types │ └── nginx.conf ├── paths.js ├── polyfills.js ├── webpack.config.dev.js └── webpack.config.prod.js ├── doc └── create-container.md ├── media ├── Gorae.001.png ├── Gorae.002.png └── Gorae.003.png ├── package.json ├── public ├── assets │ └── images │ │ ├── container-world.png │ │ ├── docker-600x400.png │ │ ├── docker-banner2.jpg │ │ ├── docker-factory.png │ │ ├── docker-logo-s.png │ │ ├── docker-logo.png │ │ ├── docker-logo2-s.png │ │ ├── docker-logo2-xs.png │ │ ├── docker-panel.png │ │ ├── docker-panel2.png │ │ ├── docker-ship.png │ │ ├── docker-swarm.png │ │ ├── docker-turtles-communication-s.png │ │ ├── docker-turtles-communication.jpg │ │ └── docker.jpg ├── favicon.ico ├── index.html └── vendors │ └── wetty │ ├── hterm_all.js │ └── socket.io.js ├── scripts ├── build.js ├── start.js └── test.js └── src ├── DevTools.jsx ├── actions ├── commit.jsx ├── container.exec.jsx ├── container.jsx ├── containers.jsx ├── daemon.jsx ├── events.jsx ├── form.jsx ├── image.create.jsx ├── image.jsx ├── image.remove.jsx ├── images.jsx ├── network.create.jsx ├── network.jsx ├── network.remove.jsx ├── networks.jsx ├── nodes.jsx ├── services.jsx ├── swarm.jsx ├── tasks.jsx ├── volume.create.jsx ├── volume.remove.jsx └── volumes.jsx ├── api └── api.jsx ├── assets ├── css │ ├── animate.css │ ├── container.css │ ├── image.css │ ├── main.css │ └── normalize.css ├── less │ ├── _bootstrap │ │ ├── alerts.less │ │ ├── badges.less │ │ ├── breadcrumbs.less │ │ ├── button-groups.less │ │ ├── buttons.less │ │ ├── carousel.less │ │ ├── close.less │ │ ├── code.less │ │ ├── component-animations.less │ │ ├── dropdowns.less │ │ ├── forms.less │ │ ├── glyphicons.less │ │ ├── grid.less │ │ ├── input-groups.less │ │ ├── jumbotron.less │ │ ├── labels.less │ │ ├── list-group.less │ │ ├── media.less │ │ ├── mixins.less │ │ ├── mixins │ │ │ ├── alerts.less │ │ │ ├── background-variant.less │ │ │ ├── border-radius.less │ │ │ ├── buttons.less │ │ │ ├── center-block.less │ │ │ ├── clearfix.less │ │ │ ├── forms.less │ │ │ ├── gradients.less │ │ │ ├── grid-framework.less │ │ │ ├── grid.less │ │ │ ├── hide-text.less │ │ │ ├── image.less │ │ │ ├── labels.less │ │ │ ├── list-group.less │ │ │ ├── nav-divider.less │ │ │ ├── nav-vertical-align.less │ │ │ ├── opacity.less │ │ │ ├── pagination.less │ │ │ ├── panels.less │ │ │ ├── progress-bar.less │ │ │ ├── reset-filter.less │ │ │ ├── reset-text.less │ │ │ ├── resize.less │ │ │ ├── responsive-visibility.less │ │ │ ├── size.less │ │ │ ├── tab-focus.less │ │ │ ├── table-row.less │ │ │ ├── text-emphasis.less │ │ │ ├── text-overflow.less │ │ │ └── vendor-prefixes.less │ │ ├── modals.less │ │ ├── navbar.less │ │ ├── navs.less │ │ ├── normalize.less │ │ ├── pager.less │ │ ├── pagination.less │ │ ├── panels.less │ │ ├── popovers.less │ │ ├── print.less │ │ ├── progress-bars.less │ │ ├── responsive-embed.less │ │ ├── responsive-utilities.less │ │ ├── scaffolding.less │ │ ├── tables.less │ │ ├── theme.less │ │ ├── thumbnails.less │ │ ├── tooltip.less │ │ ├── type.less │ │ ├── utilities.less │ │ ├── variables.less │ │ └── wells.less │ ├── _global │ │ └── global.less │ ├── bootstrap-ext │ │ ├── alerts.less │ │ ├── badges.less │ │ ├── breadcrumbs.less │ │ ├── button-groups.less │ │ ├── buttons.less │ │ ├── close.less │ │ ├── code.less │ │ ├── dropdowns.less │ │ ├── forms.less │ │ ├── glyphicons.less │ │ ├── input-groups.less │ │ ├── labels.less │ │ ├── list-group.less │ │ ├── media.less │ │ ├── modals.less │ │ ├── navbar.less │ │ ├── navs.less │ │ ├── pager.less │ │ ├── pagination.less │ │ ├── panels.less │ │ ├── popovers.less │ │ ├── progress-bars.less │ │ ├── scaffolding.less │ │ ├── tables.less │ │ ├── thumbnails.less │ │ ├── tooltip.less │ │ ├── type.less │ │ └── wells.less │ ├── bootstrap.less │ ├── core │ │ ├── colors │ │ │ ├── colors.less │ │ │ └── palette.less │ │ ├── layout │ │ │ ├── boxed.less │ │ │ ├── component-animation.less │ │ │ ├── content.less │ │ │ ├── footer.less │ │ │ ├── sidebar.less │ │ │ └── utils.less │ │ ├── mixins │ │ │ └── nav-vertical-align.less │ │ └── variables │ │ │ ├── variables-core.less │ │ │ └── variables-custom.less │ ├── helpers.less │ └── main.less └── sass │ └── _.sass ├── components ├── Containers.jsx ├── Dashboard.jsx ├── Events.jsx ├── FooterBar.jsx ├── FooterBarSimple.jsx ├── HeaderBar.jsx ├── HeaderBarSimple.jsx ├── Images.jsx ├── Networks.jsx ├── Nodes.jsx ├── SideBar.css ├── SideBar.jsx ├── Volumes.jsx ├── __tests__ │ └── Header-test.jsx ├── _sample.jsx ├── containers │ ├── Basic.jsx │ ├── Changes.jsx │ ├── ContainerDetail.jsx │ ├── ContainerList.jsx │ ├── Logs.jsx │ ├── Processes.jsx │ ├── Stats.jsx │ ├── Terminal.jsx │ ├── TerminalDialog.jsx │ ├── basic │ │ ├── Bindings.jsx │ │ ├── Environment.jsx │ │ ├── Labels.jsx │ │ ├── Network.jsx │ │ ├── Path.jsx │ │ └── State.jsx │ ├── stats │ │ ├── barChart.css │ │ ├── barChart.jsx │ │ ├── circleChart.css │ │ ├── circleChart.jsx │ │ ├── lineChart.css │ │ ├── lineChart.jsx │ │ └── sparkline.jsx │ └── terminal.css ├── daemon │ ├── Daemon.jsx │ ├── DaemonDetail.jsx │ ├── Plugins.jsx │ ├── Swarm.jsx │ └── Version.jsx ├── dashboard │ ├── Cpu.jsx │ ├── Disk.jsx │ ├── Memory.jsx │ └── Network.jsx ├── errors │ ├── 404.jsx │ ├── 500.jsx │ └── index.jsx ├── events │ └── Monitor.jsx ├── images │ ├── Basic.jsx │ ├── History.jsx │ ├── ImageDetail.jsx │ └── Pull.jsx ├── networks │ ├── Basic.jsx │ ├── Create.jsx │ ├── NetworkDetail.jsx │ └── Relation.jsx ├── nodes │ ├── NodeDetail.jsx │ └── NodeItem.jsx ├── notifier │ └── Snack.jsx ├── ui │ ├── button │ │ ├── Button.jsx │ │ └── __tests__ │ │ │ └── Button-test.jsx │ ├── checkbox │ │ └── Checkbox.jsx │ ├── dialog │ │ ├── Dialog.jsx │ │ └── dialog.css │ ├── index.jsx │ ├── stateIcon.jsx │ └── typeWriter.jsx └── volumes │ └── Create.jsx ├── containers ├── About.css ├── About.jsx ├── App.jsx └── Home.jsx ├── helpers └── helpers.jsx ├── index.html ├── index.js ├── reducers ├── article.jsx ├── container.jsx ├── containers.jsx ├── daemon.jsx ├── events.jsx ├── form.jsx ├── history.jsx ├── image.jsx ├── images.jsx ├── network.jsx ├── networks.jsx ├── nodes.jsx ├── notifier.jsx ├── services.jsx ├── tasks.jsx ├── user.jsx ├── volume.jsx └── volumes.jsx ├── routes.jsx └── store ├── configureStore.development.jsx ├── configureStore.jsx └── configureStore.production.jsx /.dockerignore: -------------------------------------------------------------------------------- 1 | # system, ide 2 | .DS_Store 3 | .idea 4 | 5 | # src 6 | node_modules/ 7 | public/ 8 | scripts/ 9 | src/ 10 | .eslintignore 11 | .git* 12 | *.md 13 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/** 2 | **/*.css 3 | **/*.html 4 | src/**/*-test.js 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | 6 | # testing 7 | coverage 8 | 9 | # production 10 | build 11 | server 12 | 13 | # misc 14 | .DS_Store 15 | .env 16 | npm-debug.log 17 | v8.log 18 | yarn.lock 19 | .yarnclean 20 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | # 0.1.0 (2016-10-18) 3 | 4 | 5 | ### Features 6 | 7 | * **lint:** pretty formatter and add lint run-script 7a2737e 8 | * switch sample app reducer, router, redux and etc b6e5553 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # [![](media/Gorae.001.png)](https://github.com/rhiokim/gorae) 3 | 4 | The `gorae` project is web interface solution for docker related products such as DDC, DC/OS of Mesosphere using modern web technologies. 5 | 6 | Actually, this project consists of four seperated products. 7 | 8 | * Gorae for Docker engine 9 | * Gorae Swarm for Orchestration and Continuous Deployment on Docker Swarm 10 | * Gorae Registry for Docker Distribution 11 | * Gorae Pipe for Pipeline between DVCS and Gorae Swarm (exactly Docker Swarm) 12 | 13 | And even these are made of docker image. It means, if you want to run this project on your machine and own system. You just run `docker run` command 14 | 15 | ## Gorae Pipe 16 | ![](media/Gorae.002.png) 17 | 18 | ## Gorae CI/CD 19 | ![](media/Gorae.003.png) 20 | 21 | ### References 22 | - https://docs.docker.com/engine/reference/api/docker_remote_api/ 23 | - http://blog.couchbase.com/2016/february/enabling-docker-remote-api-docker-machine-mac-osx 24 | - https://github.com/apocas/dockerode 25 | - https://github.com/CenturyLinkLabs/golang-builder 26 | - https://forums.docker.com/t/docker-osx-var-run-docker-sock-file-missing/623 27 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | ## TODO 2 | 3 | - menuitem click handler 4 | - improve to show error 5 | 6 | ### Container 7 | - port mapping 8 | 9 | ### Image 10 | - display result after remove image. 11 | 12 | ### Network 13 | - delete from network 14 | -------------------------------------------------------------------------------- /config/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM mhart/alpine-node:6 2 | # FROM node:latest 3 | MAINTAINER [Rhio Kim ] 4 | 5 | #copy package first to cache npm-install and speed up build 6 | COPY server server 7 | COPY build www 8 | 9 | WORKDIR server 10 | RUN npm --quiet --no-color install 11 | 12 | EXPOSE 8082 13 | 14 | CMD ["npm", "start"] 15 | -------------------------------------------------------------------------------- /config/docker/Dockerfile.release: -------------------------------------------------------------------------------- 1 | FROM mhart/alpine-node:6 2 | # FROM node:latest 3 | MAINTAINER [Rhio Kim 4 | 5 | #copy package first to cache npm-install and speed up build 6 | COPY server server 7 | COPY www www 8 | 9 | WORKDIR server 10 | RUN npm --quiet --no-color install 11 | 12 | EXPOSE 8081 13 | 14 | CMD ["npm", "start"] 15 | -------------------------------------------------------------------------------- /config/env.js: -------------------------------------------------------------------------------- 1 | // Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be 2 | // injected into the application via DefinePlugin in Webpack configuration. 3 | 4 | var REACT_APP = /^REACT_APP_/i; 5 | 6 | function getPkgInfo() { 7 | var pkg = require('../package.json'); 8 | var getRepoInfo = require('git-repo-info'); 9 | var info = getRepoInfo(); 10 | var keywords = pkg.keywords && pkg.keywords.join(', ') || []; 11 | 12 | return { 13 | 'name': `"${pkg.name}"`, 14 | 'version': `"${pkg.version}"`, 15 | 'description': `"${pkg.description || ''}"`, 16 | 'keywords': `"${keywords}"`, 17 | 'author': `"${pkg.author}"`, 18 | 'license': `"${pkg.license}"`, 19 | 'homepage': `"${pkg.homepage}"`, 20 | 'sha': `"${info.sha}"` 21 | } 22 | } 23 | 24 | function getClientEnvironment(publicUrl) { 25 | var processEnv = Object 26 | .keys(process.env) 27 | .filter(key => REACT_APP.test(key)) 28 | .reduce((env, key) => { 29 | env[key] = JSON.stringify(process.env[key]); 30 | return env; 31 | }, { 32 | // Useful for determining whether we’re running in production mode. 33 | // Most importantly, it switches React into the correct mode. 34 | 'NODE_ENV': JSON.stringify( 35 | process.env.NODE_ENV || 'development' 36 | ), 37 | '__API__': JSON.stringify( 38 | process.env.NODE_ENV === 'development' ? 'http://localhost:8082' : '' 39 | ), 40 | // Useful for resolving the correct path to static assets in `public`. 41 | // For example, . 42 | // This should only be used as an escape hatch. Normally you would put 43 | // images into the `src` and `import` them in code to get their paths. 44 | 'PUBLIC_URL': JSON.stringify(publicUrl) 45 | }); 46 | return {'process.env': processEnv, 'pkginfo': getPkgInfo()}; 47 | } 48 | 49 | module.exports = getClientEnvironment; 50 | -------------------------------------------------------------------------------- /config/jest/CSSStub.js: -------------------------------------------------------------------------------- 1 | module.exports = {}; 2 | -------------------------------------------------------------------------------- /config/jest/FileStub.js: -------------------------------------------------------------------------------- 1 | module.exports = "test-file-stub"; 2 | -------------------------------------------------------------------------------- /config/paths.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var fs = require('fs'); 3 | 4 | // Make sure any symlinks in the project folder are resolved: 5 | // https://github.com/facebookincubator/create-react-app/issues/637 6 | var appDirectory = fs.realpathSync(process.cwd()); 7 | function resolveApp(relativePath) { 8 | return path.resolve(appDirectory, relativePath); 9 | } 10 | 11 | // We support resolving modules according to `NODE_PATH`. 12 | // This lets you use absolute paths in imports inside large monorepos: 13 | // https://github.com/facebookincubator/create-react-app/issues/253. 14 | 15 | // It works similar to `NODE_PATH` in Node itself: 16 | // https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders 17 | 18 | // We will export `nodePaths` as an array of absolute paths. 19 | // It will then be used by Webpack configs. 20 | // Jest doesn’t need this because it already handles `NODE_PATH` out of the box. 21 | 22 | var nodePaths = (process.env.NODE_PATH || '') 23 | .split(process.platform === 'win32' ? ';' : ':') 24 | .filter(Boolean) 25 | .map(resolveApp); 26 | 27 | // config after eject: we're in ./config/ 28 | module.exports = { 29 | appBuild: resolveApp('build'), 30 | appPublic: resolveApp('public'), 31 | appHtml: resolveApp('public/index.html'), 32 | appIndexJs: resolveApp('src/index.js'), 33 | appPackageJson: resolveApp('package.json'), 34 | appSrc: resolveApp('src'), 35 | testsSetup: resolveApp('src/setupTests.js'), 36 | appNodeModules: resolveApp('node_modules'), 37 | ownNodeModules: resolveApp('node_modules'), 38 | nodePaths: nodePaths 39 | }; 40 | 41 | 42 | 43 | // config before publish: we're in ./packages/react-scripts/config/ 44 | if (__dirname.indexOf(path.join('packages', 'react-scripts', 'config')) !== -1) { 45 | module.exports = { 46 | appBuild: resolveOwn('../../../build'), 47 | appPublic: resolveOwn('../template/public'), 48 | appHtml: resolveOwn('../template/public/index.html'), 49 | appIndexJs: resolveOwn('../template/src/index.js'), 50 | appPackageJson: resolveOwn('../package.json'), 51 | appSrc: resolveOwn('../template/src'), 52 | testsSetup: resolveOwn('../template/src/setupTests.js'), 53 | appNodeModules: resolveOwn('../node_modules'), 54 | ownNodeModules: resolveOwn('../node_modules'), 55 | nodePaths: nodePaths 56 | }; 57 | } 58 | -------------------------------------------------------------------------------- /config/polyfills.js: -------------------------------------------------------------------------------- 1 | if (typeof Promise === 'undefined') { 2 | // Rejection tracking prevents a common issue where React gets into an 3 | // inconsistent state due to an error, but it gets swallowed by a Promise, 4 | // and the user has no idea what causes React's erratic future behavior. 5 | require('promise/lib/rejection-tracking').enable(); 6 | window.Promise = require('promise/lib/es6-extensions.js'); 7 | } 8 | 9 | // fetch() polyfill for making API calls. 10 | require('whatwg-fetch'); 11 | 12 | // Object.assign() is commonly used with React. 13 | // It will use the native implementation if it's present and isn't buggy. 14 | Object.assign = require('object-assign'); 15 | -------------------------------------------------------------------------------- /doc/create-container.md: -------------------------------------------------------------------------------- 1 | 2 | ### refs 3 | - https://docs.docker.com/engine/reference/commandline/create/ 4 | -------------------------------------------------------------------------------- /media/Gorae.001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhiokim/gorae/0a61ab2034385cd2c16a226a277a36962988122d/media/Gorae.001.png -------------------------------------------------------------------------------- /media/Gorae.002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhiokim/gorae/0a61ab2034385cd2c16a226a277a36962988122d/media/Gorae.002.png -------------------------------------------------------------------------------- /media/Gorae.003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhiokim/gorae/0a61ab2034385cd2c16a226a277a36962988122d/media/Gorae.003.png -------------------------------------------------------------------------------- /public/assets/images/container-world.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhiokim/gorae/0a61ab2034385cd2c16a226a277a36962988122d/public/assets/images/container-world.png -------------------------------------------------------------------------------- /public/assets/images/docker-600x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhiokim/gorae/0a61ab2034385cd2c16a226a277a36962988122d/public/assets/images/docker-600x400.png -------------------------------------------------------------------------------- /public/assets/images/docker-banner2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhiokim/gorae/0a61ab2034385cd2c16a226a277a36962988122d/public/assets/images/docker-banner2.jpg -------------------------------------------------------------------------------- /public/assets/images/docker-factory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhiokim/gorae/0a61ab2034385cd2c16a226a277a36962988122d/public/assets/images/docker-factory.png -------------------------------------------------------------------------------- /public/assets/images/docker-logo-s.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhiokim/gorae/0a61ab2034385cd2c16a226a277a36962988122d/public/assets/images/docker-logo-s.png -------------------------------------------------------------------------------- /public/assets/images/docker-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhiokim/gorae/0a61ab2034385cd2c16a226a277a36962988122d/public/assets/images/docker-logo.png -------------------------------------------------------------------------------- /public/assets/images/docker-logo2-s.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhiokim/gorae/0a61ab2034385cd2c16a226a277a36962988122d/public/assets/images/docker-logo2-s.png -------------------------------------------------------------------------------- /public/assets/images/docker-logo2-xs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhiokim/gorae/0a61ab2034385cd2c16a226a277a36962988122d/public/assets/images/docker-logo2-xs.png -------------------------------------------------------------------------------- /public/assets/images/docker-panel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhiokim/gorae/0a61ab2034385cd2c16a226a277a36962988122d/public/assets/images/docker-panel.png -------------------------------------------------------------------------------- /public/assets/images/docker-panel2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhiokim/gorae/0a61ab2034385cd2c16a226a277a36962988122d/public/assets/images/docker-panel2.png -------------------------------------------------------------------------------- /public/assets/images/docker-ship.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhiokim/gorae/0a61ab2034385cd2c16a226a277a36962988122d/public/assets/images/docker-ship.png -------------------------------------------------------------------------------- /public/assets/images/docker-swarm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhiokim/gorae/0a61ab2034385cd2c16a226a277a36962988122d/public/assets/images/docker-swarm.png -------------------------------------------------------------------------------- /public/assets/images/docker-turtles-communication-s.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhiokim/gorae/0a61ab2034385cd2c16a226a277a36962988122d/public/assets/images/docker-turtles-communication-s.png -------------------------------------------------------------------------------- /public/assets/images/docker-turtles-communication.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhiokim/gorae/0a61ab2034385cd2c16a226a277a36962988122d/public/assets/images/docker-turtles-communication.jpg -------------------------------------------------------------------------------- /public/assets/images/docker.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhiokim/gorae/0a61ab2034385cd2c16a226a277a36962988122d/public/assets/images/docker.jpg -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rhiokim/gorae/0a61ab2034385cd2c16a226a277a36962988122d/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 24 | React App 25 | 26 | 27 |
28 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /scripts/test.js: -------------------------------------------------------------------------------- 1 | process.env.NODE_ENV = 'test'; 2 | process.env.PUBLIC_URL = ''; 3 | 4 | // Load environment variables from .env file. Suppress warnings using silent 5 | // if this file is missing. dotenv will never modify any environment variables 6 | // that have already been set. 7 | // https://github.com/motdotla/dotenv 8 | require('dotenv').config({silent: true}); 9 | 10 | const jest = require('jest'); 11 | const argv = process.argv.slice(2); 12 | 13 | // Watch unless on CI 14 | if (!process.env.CI) { 15 | argv.push('--watch'); 16 | } 17 | 18 | 19 | jest.run(argv); 20 | -------------------------------------------------------------------------------- /src/DevTools.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {createDevTools} from 'redux-devtools'; 3 | import LogMonitor from 'redux-devtools-log-monitor'; 4 | import DockMonitor from 'redux-devtools-dock-monitor'; 5 | 6 | export default createDevTools( 7 | 8 | 9 | 10 | ); 11 | -------------------------------------------------------------------------------- /src/actions/commit.jsx: -------------------------------------------------------------------------------- 1 | import docker from '../api/api'; 2 | 3 | export const REQUEST_COMMIT = 'REQUEST_COMMIT'; 4 | export const SUCCESS_COMMIT = 'RECEIVE_COMMIT'; 5 | export const FAIL_COMMIT = 'FAIL_COMMIT'; 6 | 7 | const requestCommits = () => { 8 | return { 9 | type: REQUEST_COMMIT 10 | }; 11 | }; 12 | 13 | const receiveCommits = data => { 14 | return { 15 | type: SUCCESS_COMMIT, 16 | commit: data, 17 | receivedAt: Date.now() 18 | }; 19 | }; 20 | 21 | const fetchCommitsFail = () => ({ 22 | type: FAIL_COMMIT 23 | }); 24 | 25 | export const commit = ({id, comment, repo, tag, config}) => dispatch => { 26 | dispatch(requestCommits()); 27 | 28 | return docker.post(`commit?container=${id}&tag=${tag}`, {params: {repo:1}}, config) 29 | .then(response => { 30 | const {status, data} = response; 31 | 32 | if (status !== 201) { 33 | dispatch(fetchCommitsFail()); 34 | return; 35 | } 36 | 37 | dispatch(receiveCommits(data)); 38 | }); 39 | }; 40 | -------------------------------------------------------------------------------- /src/actions/container.exec.jsx: -------------------------------------------------------------------------------- 1 | import docker from '../api/api'; 2 | 3 | export const REQUEST_EXEC_CONTAINER = 'REQUEST_EXEC_CONTAINER'; 4 | export const SUCCESS_EXEC_CONTAINER = 'SUCCESS_EXEC_CONTAINER'; 5 | export const FAIL_EXEC_CONTAINER = 'FAIL_EXEC_CONTAINER'; 6 | 7 | /** 8 | * Remove Node 9 | */ 10 | const requestExecContainer = () => { 11 | return { 12 | type: REQUEST_EXEC_CONTAINER 13 | }; 14 | }; 15 | 16 | const successExecContainer = (data) => { 17 | return { 18 | type: SUCCESS_EXEC_CONTAINER, 19 | exec: data, 20 | receivedAt: Date.now() 21 | }; 22 | }; 23 | 24 | const faileExecContainer = (error) => ({ 25 | type: FAIL_EXEC_CONTAINER, 26 | error: error 27 | }); 28 | 29 | const initialData = { 30 | "AttachStdin": true, 31 | "AttachStdout": true, 32 | "AttachStderr": true, 33 | "Cmd": ["sh"], 34 | "DetachKeys": "ctrl-p,ctrl-q", 35 | "Privileged": true, 36 | "Tty": true, 37 | "User": "" 38 | }; 39 | 40 | export const execContainer = (id, data = {}) => dispatch => { 41 | dispatch(requestExecContainer()); 42 | 43 | data = Object.assign(initialData, data); 44 | 45 | return docker.post(`containers/${id}/exec`, data) 46 | .then(response => { 47 | const {status, data} = response; 48 | 49 | if (status !== 201) { 50 | dispatch(faileExecContainer(data)); 51 | return; 52 | } 53 | 54 | dispatch(successExecContainer(data)); 55 | }) 56 | .catch(error => { 57 | const {data} = error.response; 58 | dispatch(faileExecContainer(data)); 59 | }); 60 | }; 61 | -------------------------------------------------------------------------------- /src/actions/containers.jsx: -------------------------------------------------------------------------------- 1 | /* global __API__ */ 2 | import docker from '../api/api'; 3 | // import axios from 'axios'; 4 | 5 | export const REQUEST_CONTAINERS = 'REQUEST_CONTAINERS'; 6 | export const RECEIVE_CONTAINERS = 'RECEIVE_CONTAINERS'; 7 | export const RECEIVE_CONTAINERS_FAIL = 'RECEIVE_CONTAINERS_FAIL'; 8 | 9 | export const CONTAINER_FILTER_BY_NAME = 'CONTAINER_FILTER_BY_NAME'; 10 | // const api = axios.create({ 11 | // baseURL: __API__ 12 | // }); 13 | 14 | const requestContainers = () => { 15 | return { 16 | type: REQUEST_CONTAINERS 17 | }; 18 | }; 19 | 20 | const receiveContainers = data => { 21 | return { 22 | type: RECEIVE_CONTAINERS, 23 | containers: data, 24 | receivedAt: Date.now() 25 | }; 26 | }; 27 | 28 | const fetchContainersFail = () => ({ 29 | type: RECEIVE_CONTAINERS_FAIL 30 | }); 31 | 32 | const _filterByName = name => ({ 33 | type: CONTAINER_FILTER_BY_NAME, 34 | name: name 35 | }) 36 | 37 | export const filterByName = name => dispatch => { 38 | dispatch(_filterByName(name)); 39 | } 40 | 41 | export const fetchContainers = params => dispatch => { 42 | dispatch(requestContainers()); 43 | 44 | return docker.get('containers/json', { 45 | params: params 46 | }) 47 | .then(response => { 48 | const {status, data} = response; 49 | 50 | if (status !== 200) { 51 | dispatch(fetchContainersFail()); 52 | return; 53 | } 54 | 55 | dispatch(receiveContainers(data)); 56 | }); 57 | }; 58 | -------------------------------------------------------------------------------- /src/actions/daemon.jsx: -------------------------------------------------------------------------------- 1 | /* global __API__ */ 2 | import docker from '../api/api'; 3 | // import axios from 'axios'; 4 | 5 | export const REQUEST_INFO = 'REQUEST_INFO'; 6 | export const RECEIVE_INFO = 'RECEIVE_INFO'; 7 | export const RECEIVE_INFO_FAIL = 'RECEIVE_INFO_FAIL'; 8 | 9 | export const REQUEST_VERSION = 'REQUEST_VERSION'; 10 | export const RECEIVE_VERSION = 'RECEIVE_VERSION'; 11 | export const RECEIVE_VERSION_FAIL = 'RECEIVE_VERSION_FAIL'; 12 | 13 | // const api = axios.create({ 14 | // baseURL: __API__ 15 | // }); 16 | 17 | const requestInfo = () => { 18 | return { 19 | type: REQUEST_INFO 20 | }; 21 | }; 22 | 23 | const receiveInfo = data => { 24 | return { 25 | type: RECEIVE_INFO, 26 | info: data, 27 | receivedAt: Date.now() 28 | }; 29 | }; 30 | 31 | const fetchInfoFail = () => ({ 32 | type: RECEIVE_INFO_FAIL 33 | }); 34 | 35 | const requestVersion = () => { 36 | return { 37 | type: REQUEST_VERSION 38 | }; 39 | }; 40 | 41 | const receiveVersion = data => { 42 | return { 43 | type: RECEIVE_VERSION, 44 | version: data, 45 | receivedAt: Date.now() 46 | }; 47 | }; 48 | 49 | const fetchVersionFail = () => ({ 50 | type: RECEIVE_VERSION_FAIL 51 | }); 52 | 53 | export const fetchInfo = () => dispatch => { 54 | dispatch(requestInfo()); 55 | 56 | return docker.get(`info`) 57 | .then(response => { 58 | const {status, data} = response; 59 | 60 | if (status !== 200) { 61 | dispatch(fetchInfoFail()); 62 | return; 63 | } 64 | 65 | dispatch(receiveInfo(data)); 66 | }); 67 | }; 68 | 69 | export const fetchVersion = () => dispatch => { 70 | dispatch(requestVersion()); 71 | 72 | return docker.get(`version`) 73 | .then(response => { 74 | const {status, data} = response; 75 | 76 | if (status !== 200) { 77 | dispatch(fetchVersionFail()); 78 | return; 79 | } 80 | 81 | dispatch(receiveVersion(data)); 82 | }); 83 | }; 84 | -------------------------------------------------------------------------------- /src/actions/events.jsx: -------------------------------------------------------------------------------- 1 | /* global __API__ */ 2 | import docker from '../api/api'; 3 | // import axios from 'axios'; 4 | 5 | export const FILTER_EVENTS_TYPE = 'FILTER_EVENTS_TYPE'; 6 | 7 | export const REQUEST_EVENTS = 'REQUEST_EVENTS'; 8 | export const RECEIVE_EVENTS = 'RECEIVE_EVENTS'; 9 | export const RECEIVE_EVENTS_FAIL = 'RECEIVE_EVENTS_FAIL'; 10 | 11 | export const REQUEST_EVENT_STREAM = 'REQUEST_EVENT_STREAM'; 12 | export const RECEIVE_EVENT_STREAM = 'RECEIVE_EVENT_STREAM'; 13 | export const RECEIVE_EVENT_STREAM_FAIL = 'RECEIVE_EVENT_STREAM_FAIL'; 14 | 15 | // const api = axios.create({ 16 | // baseURL: __API__ 17 | // }); 18 | 19 | const requestEventStream = () => { 20 | return { 21 | type: REQUEST_EVENT_STREAM 22 | }; 23 | }; 24 | 25 | const receiveEventStream = data => { 26 | return { 27 | type: RECEIVE_EVENT_STREAM, 28 | event: data, 29 | receivedAt: Date.now() 30 | }; 31 | }; 32 | 33 | const fetchEventStreamFail = e => ({ 34 | type: RECEIVE_EVENT_STREAM_FAIL, 35 | e: e 36 | }); 37 | 38 | const requestEvents = () => { 39 | return { 40 | type: REQUEST_EVENTS 41 | }; 42 | }; 43 | 44 | const receiveEvents = data => { 45 | return { 46 | type: RECEIVE_EVENTS, 47 | events: data, 48 | receivedAt: Date.now() 49 | }; 50 | }; 51 | 52 | const fetchEventsFail = e => ({ 53 | type: RECEIVE_EVENTS_FAIL, 54 | e: e 55 | }); 56 | 57 | export let evtSource; 58 | 59 | export const connEventStream = () => dispatch => { 60 | if (evtSource === undefined) { 61 | evtSource = new EventSource(`${process.env.__API__}/api/events`); 62 | 63 | evtSource.onopen = e => { 64 | dispatch(requestEventStream(e)); 65 | }; 66 | 67 | evtSource.onerror = e => { 68 | if (e.currentTarget.readyState === EventSource.CONNECTING) { 69 | evtSource = new EventSource(`${process.env.__API__}/api/events`); 70 | return; 71 | } 72 | dispatch(fetchEventStreamFail(e)); 73 | }; 74 | 75 | evtSource.onmessage = e => { 76 | const evt = JSON.parse(e.data); 77 | 78 | dispatch(receiveEventStream(evt)); 79 | }; 80 | } 81 | 82 | return evtSource; 83 | }; 84 | 85 | export const fetchEvents = params => dispatch => { 86 | dispatch(requestEvents()); 87 | 88 | return docker.get('events', {params: params}) 89 | .then(response => { 90 | const {status, data} = response; 91 | 92 | if (status !== 200) { 93 | dispatch(fetchEventsFail()); 94 | return; 95 | } 96 | 97 | let res = data.replace(/\n/g, ','); 98 | 99 | res = res.substr(0, res.length - 1); 100 | res = JSON.parse('[' + res + ']'); 101 | dispatch(receiveEvents(res)); 102 | }); 103 | }; 104 | 105 | export const filter = type => dispatch => { 106 | dispatch({ 107 | type: FILTER_EVENTS_TYPE, 108 | filter: type 109 | }); 110 | }; 111 | -------------------------------------------------------------------------------- /src/actions/form.jsx: -------------------------------------------------------------------------------- 1 | /* global __API__ */ 2 | export const UPDATE_MOUNTS = 'UPDATE_MOUNTS'; 3 | export const UPDATE_ENVIRONMENT = 'UPDATE_ENVIRONMENT'; 4 | 5 | export const updateMounts = data => { 6 | return { 7 | type: UPDATE_MOUNTS, 8 | data: data 9 | }; 10 | }; 11 | 12 | export const updateEnv = data => { 13 | return { 14 | type: UPDATE_ENVIRONMENT, 15 | data: data 16 | }; 17 | }; 18 | -------------------------------------------------------------------------------- /src/actions/image.create.jsx: -------------------------------------------------------------------------------- 1 | import docker from '../api/api'; 2 | 3 | export const REQUEST_CREATE_IMAGE = 'REQUEST_CREATE_IMAGE'; 4 | export const SUCCESS_CREATE_IMAGE = 'SUCCESS_CREATE_IMAGE'; 5 | export const FAIL_CREATE_IMAGE = 'FAIL_CREATE_IMAGE'; 6 | 7 | /** 8 | * Remove Node 9 | */ 10 | const requestCreateImage = () => { 11 | return { 12 | type: REQUEST_CREATE_IMAGE 13 | }; 14 | }; 15 | 16 | const successCreateImage = (data) => { 17 | return { 18 | type: SUCCESS_CREATE_IMAGE, 19 | pull: data, 20 | receivedAt: Date.now() 21 | }; 22 | }; 23 | 24 | const faileCreateImage = (error) => ({ 25 | type: FAIL_CREATE_IMAGE, 26 | error: error 27 | }); 28 | 29 | export const createImage = ({registry, fromImage, tag}) => dispatch => { 30 | dispatch(requestCreateImage()); 31 | 32 | registry = registry ? `${registry}/` : '' 33 | return docker.post(`images/create?fromImage=${registry}${fromImage}&tag=${tag}`) 34 | .then(response => { 35 | const {status, data} = response; 36 | 37 | if (status !== 200) { 38 | dispatch(faileCreateImage(data)); 39 | return; 40 | } 41 | 42 | dispatch(successCreateImage(data)); 43 | }) 44 | .catch(error => { 45 | const {data} = error.response; 46 | dispatch(faileCreateImage(data)); 47 | }); 48 | }; 49 | -------------------------------------------------------------------------------- /src/actions/image.jsx: -------------------------------------------------------------------------------- 1 | /* global __API__ */ 2 | import docker from '../api/api'; 3 | // import axios from 'axios'; 4 | 5 | export const REQUEST_IMAGE = 'REQUEST_IMAGE'; 6 | export const RECEIVE_IMAGE = 'RECEIVE_IMAGE'; 7 | export const RECEIVE_IMAGE_FAIL = 'RECEIVE_IMAGE_FAIL'; 8 | 9 | export const REQUEST_IMAGE_HISTORY = 'REQUEST_IMAGE_HISTORY'; 10 | export const RECEIVE_IMAGE_HISTORY = 'RECEIVE_IMAGE_HISTORY'; 11 | export const RECEIVE_IMAGE_HISTORY_FAIL = 'RECEIVE_IMAGE_HISTORY_FAIL'; 12 | 13 | // const api = axios.create({ 14 | // baseURL: __API__ 15 | // }); 16 | 17 | const requestImage = () => { 18 | return { 19 | type: REQUEST_IMAGE 20 | }; 21 | }; 22 | 23 | const receiveImage = data => { 24 | return { 25 | type: RECEIVE_IMAGE, 26 | image: data, 27 | receivedAt: Date.now() 28 | }; 29 | }; 30 | 31 | const fetchImageFail = () => ({ 32 | type: RECEIVE_IMAGE_FAIL 33 | }); 34 | 35 | export const fetchImage = id => dispatch => { 36 | dispatch(requestImage()); 37 | 38 | return docker.get(`images/${id}/json`) 39 | .then(response => { 40 | const {status, data} = response; 41 | 42 | if (status !== 200) { 43 | dispatch(fetchImageFail()); 44 | return; 45 | } 46 | 47 | dispatch(receiveImage(data)); 48 | }); 49 | }; 50 | 51 | const requestImageHistory = () => { 52 | return { 53 | type: REQUEST_IMAGE_HISTORY 54 | }; 55 | }; 56 | 57 | const receiveImageHistory = data => { 58 | return { 59 | type: RECEIVE_IMAGE_HISTORY, 60 | history: data, 61 | receivedAt: Date.now() 62 | }; 63 | }; 64 | 65 | const fetchImageHistoryFail = () => ({ 66 | type: RECEIVE_IMAGE_HISTORY_FAIL 67 | }); 68 | 69 | export const fetchImageHistory = id => dispatch => { 70 | dispatch(requestImageHistory()); 71 | 72 | return docker.get(`images/${id}/history`) 73 | .then(response => { 74 | const {status, data} = response; 75 | 76 | if (status !== 200) { 77 | dispatch(fetchImageHistoryFail()); 78 | return; 79 | } 80 | 81 | dispatch(receiveImageHistory(data)); 82 | }); 83 | }; 84 | -------------------------------------------------------------------------------- /src/actions/image.remove.jsx: -------------------------------------------------------------------------------- 1 | import docker from '../api/api'; 2 | 3 | export const REQUEST_REMOVE_IMAGE = 'REQUEST_REMOVE_IMAGE'; 4 | export const SUCCESS_REMOVE_IMAGE = 'SUCCESS_REMOVE_IMAGE'; 5 | export const FAIL_REMOVE_IMAGE = 'FAIL_REMOVE_IMAGE'; 6 | 7 | /** 8 | * Remove Node 9 | */ 10 | const requestRemoveImage = () => { 11 | return { 12 | type: REQUEST_REMOVE_IMAGE 13 | }; 14 | }; 15 | 16 | const successRemoveImage = (data) => { 17 | return { 18 | type: SUCCESS_REMOVE_IMAGE, 19 | images: data, 20 | receivedAt: Date.now() 21 | }; 22 | }; 23 | 24 | const faileRemoveImage = (error) => ({ 25 | type: FAIL_REMOVE_IMAGE, 26 | error: error 27 | }); 28 | 29 | export const removeImage = (name) => dispatch => { 30 | dispatch(requestRemoveImage()); 31 | 32 | return docker.delete(`images/${name}`) 33 | .then(response => { 34 | const {status, data} = response; 35 | 36 | if (status !== 200) { 37 | dispatch(faileRemoveImage(data)); 38 | return; 39 | } 40 | 41 | dispatch(successRemoveImage(data)); 42 | }) 43 | .catch(error => { 44 | const {data} = error.response; 45 | dispatch(faileRemoveImage(data)); 46 | }); 47 | }; 48 | -------------------------------------------------------------------------------- /src/actions/images.jsx: -------------------------------------------------------------------------------- 1 | /* global __API__ */ 2 | import docker from '../api/api'; 3 | // import axios from 'axios'; 4 | 5 | export const REQUEST_IMAGES = 'REQUEST_IMAGES'; 6 | export const RECEIVE_IMAGES = 'RECEIVE_IMAGES'; 7 | export const RECEIVE_IMAGES_FAIL = 'RECEIVE_IMAGES_FAIL'; 8 | 9 | export const IMAGE_FILTER_BY_NAME = 'IMAGE_FILTER_BY_NAME'; 10 | 11 | // const api = axios.create({ 12 | // baseURL: __API__ 13 | // }); 14 | 15 | const requestImages = () => { 16 | return { 17 | type: REQUEST_IMAGES 18 | }; 19 | }; 20 | 21 | const receiveImages = data => { 22 | return { 23 | type: RECEIVE_IMAGES, 24 | images: data, 25 | receivedAt: Date.now() 26 | }; 27 | }; 28 | 29 | const fetchImagesFail = () => ({ 30 | type: RECEIVE_IMAGES_FAIL 31 | }); 32 | 33 | const _filterByName = name => ({ 34 | type: IMAGE_FILTER_BY_NAME, 35 | name: name 36 | }) 37 | 38 | export const filterByName = name => dispatch => { 39 | dispatch(_filterByName(name)); 40 | } 41 | 42 | export const fetchImages = params => dispatch => { 43 | dispatch(requestImages()); 44 | 45 | return docker.get('images/json', { 46 | params: params 47 | }) 48 | .then(response => { 49 | const {status, data} = response; 50 | 51 | if (status !== 200) { 52 | dispatch(fetchImagesFail()); 53 | return; 54 | } 55 | 56 | dispatch(receiveImages(data)); 57 | }); 58 | }; 59 | -------------------------------------------------------------------------------- /src/actions/network.create.jsx: -------------------------------------------------------------------------------- 1 | import docker from '../api/api'; 2 | 3 | export const REQUEST_CREATE_NETWORK = 'REQUEST_CREATE_NETWORK'; 4 | export const SUCCESS_CREATE_NETWORK = 'SUCCESS_CREATE_NETWORK'; 5 | export const FAIL_CREATE_NETWORK = 'FAIL_CREATE_NETWORK'; 6 | 7 | /** 8 | * Remove Node 9 | */ 10 | const requestCreateNetwork = () => { 11 | return { 12 | type: REQUEST_CREATE_NETWORK 13 | }; 14 | }; 15 | 16 | const successCreateNetwork = (data) => { 17 | return { 18 | type: SUCCESS_CREATE_NETWORK, 19 | create: data, 20 | receivedAt: Date.now() 21 | }; 22 | }; 23 | 24 | const faileCreateNetwork = (error) => ({ 25 | type: FAIL_CREATE_NETWORK, 26 | error: error 27 | }); 28 | 29 | export const createNetwork = (data) => dispatch => { 30 | dispatch(requestCreateNetwork()); 31 | 32 | return docker.post(`networks/create`, data) 33 | .then(response => { 34 | const {status, data} = response; 35 | 36 | if (status !== 201) { 37 | dispatch(faileCreateNetwork(data)); 38 | return; 39 | } 40 | 41 | dispatch(successCreateNetwork(data)); 42 | }) 43 | .catch(error => { 44 | const {data} = error.response; 45 | dispatch(faileCreateNetwork(data)); 46 | }); 47 | }; 48 | -------------------------------------------------------------------------------- /src/actions/network.jsx: -------------------------------------------------------------------------------- 1 | /* global __API__ */ 2 | import docker from '../api/api'; 3 | // import axios from 'axios'; 4 | 5 | export const REQUEST_NETWORK = 'REQUEST_NETWORK'; 6 | export const RECEIVE_NETWORK = 'RECEIVE_NETWORK'; 7 | export const RECEIVE_NETWORK_FAIL = 'RECEIVE_NETWORK_FAIL'; 8 | 9 | // const api = axios.create({ 10 | // baseURL: __API__ 11 | // }); 12 | 13 | const requestNetwork = () => { 14 | return { 15 | type: REQUEST_NETWORK 16 | }; 17 | }; 18 | 19 | const receiveNetwork = data => { 20 | return { 21 | type: RECEIVE_NETWORK, 22 | network: data, 23 | receivedAt: Date.now() 24 | }; 25 | }; 26 | 27 | const fetchNetworkFail = () => ({ 28 | type: RECEIVE_NETWORK_FAIL 29 | }); 30 | 31 | export const fetchNetwork = id => dispatch => { 32 | dispatch(requestNetwork()); 33 | 34 | return docker.get(`networks/${id}`) 35 | .then(response => { 36 | const {status, data} = response; 37 | 38 | if (status !== 200) { 39 | dispatch(fetchNetworkFail()); 40 | return; 41 | } 42 | 43 | dispatch(receiveNetwork(data)); 44 | }); 45 | }; 46 | -------------------------------------------------------------------------------- /src/actions/network.remove.jsx: -------------------------------------------------------------------------------- 1 | import docker from '../api/api'; 2 | 3 | export const REQUEST_REMOVE_NETWORK = 'REQUEST_REMOVE_NETWORK'; 4 | export const SUCCESS_REMOVE_NETWORK = 'SUCCESS_REMOVE_NETWORK'; 5 | export const FAIL_REMOVE_NETWORK = 'FAIL_REMOVE_NETWORK'; 6 | 7 | /** 8 | * Remove Node 9 | */ 10 | const requestRemoveNetwork = () => { 11 | return { 12 | type: REQUEST_REMOVE_NETWORK 13 | }; 14 | }; 15 | 16 | const successRemoveNetwork = () => { 17 | return { 18 | type: SUCCESS_REMOVE_NETWORK, 19 | receivedAt: Date.now() 20 | }; 21 | }; 22 | 23 | const faileRemoveNetwork = (error) => ({ 24 | type: FAIL_REMOVE_NETWORK, 25 | error: error 26 | }); 27 | 28 | export const removeNetwork = (name, params = {}) => dispatch => { 29 | dispatch(requestRemoveNetwork()); 30 | 31 | return docker.delete(`networks/${name}`) 32 | .then(response => { 33 | const {status, data} = response; 34 | 35 | if (status !== 204) { 36 | dispatch(faileRemoveNetwork(data)); 37 | return; 38 | } 39 | 40 | dispatch(successRemoveNetwork()); 41 | }) 42 | .catch(error => { 43 | const {data} = error.response; 44 | dispatch(faileRemoveNetwork(data)); 45 | }); 46 | }; 47 | -------------------------------------------------------------------------------- /src/actions/networks.jsx: -------------------------------------------------------------------------------- 1 | /* global __API__ */ 2 | import docker from '../api/api'; 3 | // import axios from 'axios'; 4 | 5 | export const REQUEST_NETWORKS = 'REQUEST_NETWORKS'; 6 | export const RECEIVE_NETWORKS = 'RECEIVE_NETWORKS'; 7 | export const RECEIVE_NETWORKS_FAIL = 'RECEIVE_NETWORKS_FAIL'; 8 | export const NETWORK_FILTER_BY_NAME = 'NETWORK_FILTER_BY_NAME'; 9 | 10 | // const api = axios.create({ 11 | // baseURL: __API__ 12 | // }); 13 | 14 | const requestNetworks = () => { 15 | return { 16 | type: REQUEST_NETWORKS 17 | }; 18 | }; 19 | 20 | const receiveNetworks = data => { 21 | return { 22 | type: RECEIVE_NETWORKS, 23 | networks: data, 24 | receivedAt: Date.now() 25 | }; 26 | }; 27 | 28 | const fetchNetworksFail = () => ({ 29 | type: RECEIVE_NETWORKS_FAIL 30 | }); 31 | 32 | const _filterByName = name => ({ 33 | type: NETWORK_FILTER_BY_NAME, 34 | name: name 35 | }) 36 | 37 | export const filterByName = name => dispatch => { 38 | dispatch(_filterByName(name)); 39 | } 40 | 41 | export const fetchNetworks = () => dispatch => { 42 | dispatch(requestNetworks()); 43 | 44 | return docker.get('networks') 45 | .then(response => { 46 | const {status, data} = response; 47 | 48 | if (status !== 200) { 49 | dispatch(fetchNetworksFail()); 50 | return; 51 | } 52 | 53 | dispatch(receiveNetworks(data)); 54 | }); 55 | }; 56 | -------------------------------------------------------------------------------- /src/actions/nodes.jsx: -------------------------------------------------------------------------------- 1 | /* global __API__ */ 2 | // DEPRECATED 3 | import docker from '../api/api'; 4 | // import axios from 'axios'; 5 | 6 | export const REQUEST_NODES = 'REQUEST_NODES'; 7 | export const RECEIVE_NODES = 'RECEIVE_NODES'; 8 | export const RECEIVE_NODES_FAIL = 'RECEIVE_NODES_FAIL'; 9 | 10 | // const api = axios.create({ 11 | // baseURL: __API__ 12 | // }); 13 | 14 | const requestNodes = () => { 15 | return { 16 | type: REQUEST_NODES 17 | }; 18 | }; 19 | 20 | const receiveNodes = data => { 21 | return { 22 | type: RECEIVE_NODES, 23 | nodes: data, 24 | receivedAt: Date.now() 25 | }; 26 | }; 27 | 28 | const fetchNodesFail = () => ({ 29 | type: RECEIVE_NODES_FAIL 30 | }); 31 | 32 | export const fetchNodes = () => dispatch => { 33 | dispatch(requestNodes()); 34 | 35 | return docker.get('nodes') 36 | .then(response => { 37 | const {status, data} = response; 38 | 39 | if (status !== 200) { 40 | dispatch(fetchNodesFail()); 41 | return; 42 | } 43 | 44 | dispatch(receiveNodes(data)); 45 | }); 46 | }; 47 | -------------------------------------------------------------------------------- /src/actions/services.jsx: -------------------------------------------------------------------------------- 1 | /* global __API__ */ 2 | // DEPRECATED 3 | import docker from '../api/api'; 4 | // import axios from 'axios'; 5 | 6 | export const REQUEST_SERVICES = 'REQUEST_SERVICES'; 7 | export const RECEIVE_SERVICES = 'RECEIVE_SERVICES'; 8 | export const RECEIVE_SERVICES_FAIL = 'RECEIVE_SERVICES_FAIL'; 9 | 10 | // const api = axios.create({ 11 | // baseURL: __API__ 12 | // }); 13 | 14 | const requestServices = () => { 15 | return { 16 | type: REQUEST_SERVICES 17 | }; 18 | }; 19 | 20 | const receiveServices = data => { 21 | return { 22 | type: RECEIVE_SERVICES, 23 | services: data, 24 | receivedAt: Date.now() 25 | }; 26 | }; 27 | 28 | const fetchServicesFail = () => ({ 29 | type: RECEIVE_SERVICES_FAIL 30 | }); 31 | 32 | export const fetchServices = () => dispatch => { 33 | dispatch(requestServices()); 34 | 35 | return docker.get('nodes') 36 | .then(response => { 37 | const {status, data} = response; 38 | 39 | if (status !== 200) { 40 | dispatch(fetchServicesFail()); 41 | return; 42 | } 43 | 44 | dispatch(receiveServices(data)); 45 | }); 46 | }; 47 | -------------------------------------------------------------------------------- /src/actions/tasks.jsx: -------------------------------------------------------------------------------- 1 | /* global __API__ */ 2 | // DEPRECATED 3 | import docker from '../api/api'; 4 | // import axios from 'axios'; 5 | 6 | export const REQUEST_TASKS = 'REQUEST_TASKS'; 7 | export const RECEIVE_TASKS = 'RECEIVE_TASKS'; 8 | export const RECEIVE_TASKS_FAIL = 'RECEIVE_TASKS_FAIL'; 9 | 10 | // const api = axios.create({ 11 | // baseURL: __API__ 12 | // }); 13 | 14 | const requestTasks = () => { 15 | return { 16 | type: REQUEST_TASKS 17 | }; 18 | }; 19 | 20 | const receiveTasks = data => { 21 | return { 22 | type: RECEIVE_TASKS, 23 | tasks: data, 24 | receivedAt: Date.now() 25 | }; 26 | }; 27 | 28 | const fetchTasksFail = () => ({ 29 | type: RECEIVE_TASKS_FAIL 30 | }); 31 | 32 | export const fetchTasks = () => dispatch => { 33 | dispatch(requestTasks()); 34 | 35 | return docker.get('tasks') 36 | .then(response => { 37 | const {status, data} = response; 38 | 39 | if (status !== 200) { 40 | dispatch(fetchTasksFail()); 41 | return; 42 | } 43 | 44 | dispatch(receiveTasks(data)); 45 | }); 46 | }; 47 | -------------------------------------------------------------------------------- /src/actions/volume.create.jsx: -------------------------------------------------------------------------------- 1 | import docker from '../api/api'; 2 | 3 | export const REQUEST_CREATE_VOLUME = 'REQUEST_CREATE_VOLUME'; 4 | export const SUCCESS_CREATE_VOLUME = 'SUCCESS_CREATE_VOLUME'; 5 | export const FAIL_CREATE_VOLUME = 'FAIL_CREATE_VOLUME'; 6 | 7 | /** 8 | * Remove Node 9 | */ 10 | const requestCreateVolume = () => { 11 | return { 12 | type: REQUEST_CREATE_VOLUME 13 | }; 14 | }; 15 | 16 | const successCreateVolume = (data) => { 17 | return { 18 | type: SUCCESS_CREATE_VOLUME, 19 | create: data, 20 | receivedAt: Date.now() 21 | }; 22 | }; 23 | 24 | const faileCreateVolume = (error) => ({ 25 | type: FAIL_CREATE_VOLUME, 26 | error: error 27 | }); 28 | 29 | export const createVolume = (data) => dispatch => { 30 | dispatch(requestCreateVolume()); 31 | 32 | return docker.post(`volumes/create`,data) 33 | .then(response => { 34 | const {status, data} = response; 35 | 36 | if (status !== 201) { 37 | dispatch(faileCreateVolume(data)); 38 | return; 39 | } 40 | 41 | dispatch(successCreateVolume(data)); 42 | }) 43 | .catch(error => { 44 | const {data} = error.response; 45 | dispatch(faileCreateVolume(data)); 46 | }); 47 | }; 48 | -------------------------------------------------------------------------------- /src/actions/volume.remove.jsx: -------------------------------------------------------------------------------- 1 | import docker from '../api/api'; 2 | 3 | export const REQUEST_REMOVE_VOLUME = 'REQUEST_REMOVE_VOLUME'; 4 | export const SUCCESS_REMOVE_VOLUME = 'SUCCESS_REMOVE_VOLUME'; 5 | export const FAIL_REMOVE_VOLUME = 'FAIL_REMOVE_VOLUME'; 6 | 7 | /** 8 | * Remove Node 9 | */ 10 | const requestRemoveVolume = () => { 11 | return { 12 | type: REQUEST_REMOVE_VOLUME 13 | }; 14 | }; 15 | 16 | const successRemoveVolume = () => { 17 | return { 18 | type: SUCCESS_REMOVE_VOLUME, 19 | receivedAt: Date.now() 20 | }; 21 | }; 22 | 23 | const faileRemoveVolume = (error) => ({ 24 | type: FAIL_REMOVE_VOLUME, 25 | error: error 26 | }); 27 | 28 | export const removeVolume = (name) => dispatch => { 29 | dispatch(requestRemoveVolume()); 30 | 31 | return docker.delete(`volumes/${name}`) 32 | .then(response => { 33 | const {status, data} = response; 34 | 35 | if (status !== 204) { 36 | dispatch(faileRemoveVolume(data)); 37 | return; 38 | } 39 | 40 | dispatch(successRemoveVolume()); 41 | }) 42 | .catch(error => { 43 | const {data} = error.response; 44 | dispatch(faileRemoveVolume(data)); 45 | }); 46 | }; 47 | -------------------------------------------------------------------------------- /src/actions/volumes.jsx: -------------------------------------------------------------------------------- 1 | /* global __API__ */ 2 | import docker from '../api/api'; 3 | // import axios from 'axios'; 4 | 5 | export const REQUEST_VOLUMES = 'REQUEST_VOLUMES'; 6 | export const RECEIVE_VOLUMES = 'RECEIVE_VOLUMES'; 7 | export const RECEIVE_VOLUMES_FAIL = 'RECEIVE_VOLUMES_FAIL'; 8 | 9 | export const VOLUME_FILTER_BY_NAME = 'VOLUME_FILTER_BY_NAME'; 10 | 11 | // const api = axios.create({ 12 | // baseURL: __API__ 13 | // }); 14 | 15 | const requestVolumes = () => { 16 | return { 17 | type: REQUEST_VOLUMES 18 | }; 19 | }; 20 | 21 | const receiveVolumes = data => { 22 | return { 23 | type: RECEIVE_VOLUMES, 24 | volumes: data.Volumes, 25 | warnings: data.Warnings, 26 | receivedAt: Date.now() 27 | }; 28 | }; 29 | 30 | const fetchVolumesFail = () => ({ 31 | type: RECEIVE_VOLUMES_FAIL 32 | }); 33 | 34 | const _filterByName = name => ({ 35 | type: VOLUME_FILTER_BY_NAME, 36 | name: name 37 | }) 38 | 39 | export const filterByName = name => dispatch => { 40 | dispatch(_filterByName(name)); 41 | } 42 | 43 | export const fetchVolumes = () => dispatch => { 44 | dispatch(requestVolumes()); 45 | 46 | return docker.get('volumes') 47 | .then(response => { 48 | const {status, data} = response; 49 | 50 | if (status !== 200) { 51 | dispatch(fetchVolumesFail()); 52 | return; 53 | } 54 | 55 | dispatch(receiveVolumes(data)); 56 | }); 57 | }; 58 | -------------------------------------------------------------------------------- /src/api/api.jsx: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | export default axios.create({ 4 | baseURL: `${process.env.__API__}/api/` 5 | }); 6 | 7 | export const api = axios.create({ 8 | baseURL: process.env.__API__ 9 | }); 10 | -------------------------------------------------------------------------------- /src/assets/css/container.css: -------------------------------------------------------------------------------- 1 | .container-detail .mdl-card__supporting-text { 2 | margin: 0 40px 40px 40px !important; 3 | } 4 | 5 | .container-detail .mdl-textfield { 6 | position: relative; 7 | padding: 20px 0; 8 | } 9 | 10 | /* container list */ 11 | .mdl-data-table td:first-of-type, .mdl-data-table th:first-of-type { 12 | padding-left: 16px; 13 | padding-right: 16px; 14 | } 15 | 16 | .mdl-data-table td, .mdl-data-table th { 17 | padding: 12px 6px 12px 6px; 18 | } 19 | 20 | .container-table td:first-of-type, 21 | .container-table th:first-of-type, 22 | .container-table th:nth-child(2) { 23 | width: 50px; 24 | } 25 | 26 | .container-table td:last-of-type, 27 | .container-table th:last-of-type { 28 | width: 100px; 29 | } 30 | 31 | .mdl-data-table__cell--non-numeric i.material-icons { 32 | vertical-align: bottom; 33 | } 34 | -------------------------------------------------------------------------------- /src/assets/css/image.css: -------------------------------------------------------------------------------- 1 | .image .mdl-card { 2 | min-height: inherit; 3 | } 4 | 5 | .image .history .mdl-card .mdl-card__supporting-text { 6 | margin: 10px 30px; 7 | } 8 | 9 | .image .mdl-layout__content section:not(:last-of-type) { 10 | margin-bottom: 24px; 11 | } 12 | 13 | .image-table td:first-of-type, 14 | .image-table th:first-of-type{ 15 | width: 50px; 16 | } 17 | 18 | .image-table td:last-of-type, 19 | .image-table th:last-of-type { 20 | width: 110px; 21 | } 22 | -------------------------------------------------------------------------------- /src/assets/less/_bootstrap/alerts.less: -------------------------------------------------------------------------------- 1 | // 2 | // Alerts 3 | // -------------------------------------------------- 4 | 5 | 6 | // Base styles 7 | // ------------------------- 8 | 9 | .alert { 10 | padding: @alert-padding; 11 | margin-bottom: @line-height-computed; 12 | border: 1px solid transparent; 13 | border-radius: @alert-border-radius; 14 | 15 | // Headings for larger alerts 16 | h4 { 17 | margin-top: 0; 18 | // Specified for the h4 to prevent conflicts of changing @headings-color 19 | color: inherit; 20 | } 21 | 22 | // Provide class for links that match alerts 23 | .alert-link { 24 | font-weight: @alert-link-font-weight; 25 | } 26 | 27 | // Improve alignment and spacing of inner content 28 | > p, 29 | > ul { 30 | margin-bottom: 0; 31 | } 32 | 33 | > p + p { 34 | margin-top: 5px; 35 | } 36 | } 37 | 38 | // Dismissible alerts 39 | // 40 | // Expand the right padding and account for the close button's positioning. 41 | 42 | .alert-dismissable, // The misspelled .alert-dismissable was deprecated in 3.2.0. 43 | .alert-dismissible { 44 | padding-right: (@alert-padding + 20); 45 | 46 | // Adjust close link position 47 | .close { 48 | position: relative; 49 | top: -2px; 50 | right: -21px; 51 | color: inherit; 52 | } 53 | } 54 | 55 | // Alternate styles 56 | // 57 | // Generate contextual modifier classes for colorizing the alert. 58 | 59 | .alert-success { 60 | .alert-variant(@alert-success-bg; @alert-success-border; @alert-success-text); 61 | } 62 | 63 | .alert-info { 64 | .alert-variant(@alert-info-bg; @alert-info-border; @alert-info-text); 65 | } 66 | 67 | .alert-warning { 68 | .alert-variant(@alert-warning-bg; @alert-warning-border; @alert-warning-text); 69 | } 70 | 71 | .alert-danger { 72 | .alert-variant(@alert-danger-bg; @alert-danger-border; @alert-danger-text); 73 | } 74 | -------------------------------------------------------------------------------- /src/assets/less/_bootstrap/badges.less: -------------------------------------------------------------------------------- 1 | // 2 | // Badges 3 | // -------------------------------------------------- 4 | 5 | 6 | // Base class 7 | .badge { 8 | display: inline-block; 9 | min-width: 10px; 10 | padding: 3px 7px; 11 | font-size: @font-size-small; 12 | font-weight: @badge-font-weight; 13 | color: @badge-color; 14 | line-height: @badge-line-height; 15 | vertical-align: middle; 16 | white-space: nowrap; 17 | text-align: center; 18 | background-color: @badge-bg; 19 | border-radius: @badge-border-radius; 20 | 21 | // Empty badges collapse automatically (not available in IE8) 22 | &:empty { 23 | display: none; 24 | } 25 | 26 | // Quick fix for badges in buttons 27 | .btn & { 28 | position: relative; 29 | top: -1px; 30 | } 31 | 32 | .btn-xs &, 33 | .btn-group-xs > .btn & { 34 | top: 0; 35 | padding: 1px 5px; 36 | } 37 | 38 | // Hover state, but only for links 39 | a& { 40 | &:hover, 41 | &:focus { 42 | color: @badge-link-hover-color; 43 | text-decoration: none; 44 | cursor: pointer; 45 | } 46 | } 47 | 48 | // Account for badges in navs 49 | .list-group-item.active > &, 50 | .nav-pills > .active > a > & { 51 | color: @badge-active-color; 52 | background-color: @badge-active-bg; 53 | } 54 | 55 | .list-group-item > & { 56 | float: right; 57 | } 58 | 59 | .list-group-item > & + & { 60 | margin-right: 5px; 61 | } 62 | 63 | .nav-pills > li > a > & { 64 | margin-left: 3px; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/assets/less/_bootstrap/breadcrumbs.less: -------------------------------------------------------------------------------- 1 | // 2 | // Breadcrumbs 3 | // -------------------------------------------------- 4 | 5 | 6 | .breadcrumb { 7 | padding: @breadcrumb-padding-vertical @breadcrumb-padding-horizontal; 8 | margin-bottom: @line-height-computed; 9 | list-style: none; 10 | background-color: @breadcrumb-bg; 11 | border-radius: @border-radius-base; 12 | 13 | > li { 14 | display: inline-block; 15 | 16 | + li:before { 17 | content: "@{breadcrumb-separator}\00a0"; // Unicode space added since inline-block means non-collapsing white-space 18 | padding: 0 5px; 19 | color: @breadcrumb-color; 20 | } 21 | } 22 | 23 | > .active { 24 | color: @breadcrumb-active-color; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/assets/less/_bootstrap/close.less: -------------------------------------------------------------------------------- 1 | // 2 | // Close icons 3 | // -------------------------------------------------- 4 | 5 | 6 | .close { 7 | float: right; 8 | font-size: (@font-size-base * 1.5); 9 | font-weight: @close-font-weight; 10 | line-height: 1; 11 | color: @close-color; 12 | text-shadow: @close-text-shadow; 13 | .opacity(.2); 14 | 15 | &:hover, 16 | &:focus { 17 | color: @close-color; 18 | text-decoration: none; 19 | cursor: pointer; 20 | .opacity(.5); 21 | } 22 | 23 | // Additional properties for button version 24 | // iOS requires the button element instead of an anchor tag. 25 | // If you want the anchor version, it requires `href="#"`. 26 | // See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile 27 | button& { 28 | padding: 0; 29 | cursor: pointer; 30 | background: transparent; 31 | border: 0; 32 | -webkit-appearance: none; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/assets/less/_bootstrap/code.less: -------------------------------------------------------------------------------- 1 | // 2 | // Code (inline and block) 3 | // -------------------------------------------------- 4 | 5 | 6 | // Inline and block code styles 7 | code, 8 | kbd, 9 | pre, 10 | samp { 11 | font-family: @font-family-monospace; 12 | } 13 | 14 | // Inline code 15 | code { 16 | padding: 2px 4px; 17 | font-size: 90%; 18 | color: @code-color; 19 | background-color: @code-bg; 20 | border-radius: @border-radius-base; 21 | } 22 | 23 | // User input typically entered via keyboard 24 | kbd { 25 | padding: 2px 4px; 26 | font-size: 90%; 27 | color: @kbd-color; 28 | background-color: @kbd-bg; 29 | border-radius: @border-radius-small; 30 | box-shadow: inset 0 -1px 0 rgba(0,0,0,.25); 31 | 32 | kbd { 33 | padding: 0; 34 | font-size: 100%; 35 | font-weight: bold; 36 | box-shadow: none; 37 | } 38 | } 39 | 40 | // Blocks of code 41 | pre { 42 | display: block; 43 | padding: ((@line-height-computed - 1) / 2); 44 | margin: 0 0 (@line-height-computed / 2); 45 | font-size: (@font-size-base - 1); // 14px to 13px 46 | line-height: @line-height-base; 47 | word-break: break-all; 48 | word-wrap: break-word; 49 | color: @pre-color; 50 | background-color: @pre-bg; 51 | border: 1px solid @pre-border-color; 52 | border-radius: @border-radius-base; 53 | 54 | // Account for some code outputs that place code tags in pre tags 55 | code { 56 | padding: 0; 57 | font-size: inherit; 58 | color: inherit; 59 | white-space: pre-wrap; 60 | background-color: transparent; 61 | border-radius: 0; 62 | } 63 | } 64 | 65 | // Enable scrollable blocks of code 66 | .pre-scrollable { 67 | max-height: @pre-scrollable-max-height; 68 | overflow-y: scroll; 69 | } 70 | -------------------------------------------------------------------------------- /src/assets/less/_bootstrap/component-animations.less: -------------------------------------------------------------------------------- 1 | // 2 | // Component animations 3 | // -------------------------------------------------- 4 | 5 | // Heads up! 6 | // 7 | // We don't use the `.opacity()` mixin here since it causes a bug with text 8 | // fields in IE7-8. Source: https://github.com/twbs/bootstrap/pull/3552. 9 | 10 | .fade { 11 | opacity: 0; 12 | .transition(opacity .15s linear); 13 | &.in { 14 | opacity: 1; 15 | } 16 | } 17 | 18 | .collapse { 19 | display: none; 20 | 21 | &.in { display: block; } 22 | tr&.in { display: table-row; } 23 | tbody&.in { display: table-row-group; } 24 | } 25 | 26 | .collapsing { 27 | position: relative; 28 | height: 0; 29 | overflow: hidden; 30 | .transition-property(~"height, visibility"); 31 | .transition-duration(.35s); 32 | .transition-timing-function(ease); 33 | } 34 | -------------------------------------------------------------------------------- /src/assets/less/_bootstrap/grid.less: -------------------------------------------------------------------------------- 1 | // 2 | // Grid system 3 | // -------------------------------------------------- 4 | 5 | 6 | // Container widths 7 | // 8 | // Set the container width, and override it for fixed navbars in media queries. 9 | 10 | .container { 11 | .container-fixed(); 12 | 13 | @media (min-width: @screen-sm-min) { 14 | width: @container-sm; 15 | } 16 | @media (min-width: @screen-md-min) { 17 | width: @container-md; 18 | } 19 | @media (min-width: @screen-lg-min) { 20 | width: @container-lg; 21 | } 22 | } 23 | 24 | 25 | // Fluid container 26 | // 27 | // Utilizes the mixin meant for fixed width containers, but without any defined 28 | // width for fluid, full width layouts. 29 | 30 | .container-fluid { 31 | .container-fixed(); 32 | } 33 | 34 | 35 | // Row 36 | // 37 | // Rows contain and clear the floats of your columns. 38 | 39 | .row { 40 | .make-row(); 41 | } 42 | 43 | 44 | // Columns 45 | // 46 | // Common styles for small and large grid columns 47 | 48 | .make-grid-columns(); 49 | 50 | 51 | // Extra small grid 52 | // 53 | // Columns, offsets, pushes, and pulls for extra small devices like 54 | // smartphones. 55 | 56 | .make-grid(xs); 57 | 58 | 59 | // Small grid 60 | // 61 | // Columns, offsets, pushes, and pulls for the small device range, from phones 62 | // to tablets. 63 | 64 | @media (min-width: @screen-sm-min) { 65 | .make-grid(sm); 66 | } 67 | 68 | 69 | // Medium grid 70 | // 71 | // Columns, offsets, pushes, and pulls for the desktop device range. 72 | 73 | @media (min-width: @screen-md-min) { 74 | .make-grid(md); 75 | } 76 | 77 | 78 | // Large grid 79 | // 80 | // Columns, offsets, pushes, and pulls for the large desktop device range. 81 | 82 | @media (min-width: @screen-lg-min) { 83 | .make-grid(lg); 84 | } 85 | -------------------------------------------------------------------------------- /src/assets/less/_bootstrap/jumbotron.less: -------------------------------------------------------------------------------- 1 | // 2 | // Jumbotron 3 | // -------------------------------------------------- 4 | 5 | 6 | .jumbotron { 7 | padding-top: @jumbotron-padding; 8 | padding-bottom: @jumbotron-padding; 9 | margin-bottom: @jumbotron-padding; 10 | color: @jumbotron-color; 11 | background-color: @jumbotron-bg; 12 | 13 | h1, 14 | .h1 { 15 | color: @jumbotron-heading-color; 16 | } 17 | 18 | p { 19 | margin-bottom: (@jumbotron-padding / 2); 20 | font-size: @jumbotron-font-size; 21 | font-weight: 200; 22 | } 23 | 24 | > hr { 25 | border-top-color: darken(@jumbotron-bg, 10%); 26 | } 27 | 28 | .container &, 29 | .container-fluid & { 30 | border-radius: @border-radius-large; // Only round corners at higher resolutions if contained in a container 31 | padding-left: (@grid-gutter-width / 2); 32 | padding-right: (@grid-gutter-width / 2); 33 | } 34 | 35 | .container { 36 | max-width: 100%; 37 | } 38 | 39 | @media screen and (min-width: @screen-sm-min) { 40 | padding-top: (@jumbotron-padding * 1.6); 41 | padding-bottom: (@jumbotron-padding * 1.6); 42 | 43 | .container &, 44 | .container-fluid & { 45 | padding-left: (@jumbotron-padding * 2); 46 | padding-right: (@jumbotron-padding * 2); 47 | } 48 | 49 | h1, 50 | .h1 { 51 | font-size: @jumbotron-heading-font-size; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/assets/less/_bootstrap/labels.less: -------------------------------------------------------------------------------- 1 | // 2 | // Labels 3 | // -------------------------------------------------- 4 | 5 | .label { 6 | display: inline; 7 | padding: .2em .6em .3em; 8 | font-size: 75%; 9 | font-weight: bold; 10 | line-height: 1; 11 | color: @label-color; 12 | text-align: center; 13 | white-space: nowrap; 14 | vertical-align: baseline; 15 | border-radius: .25em; 16 | 17 | // Add hover effects, but only for links 18 | a& { 19 | &:hover, 20 | &:focus { 21 | color: @label-link-hover-color; 22 | text-decoration: none; 23 | cursor: pointer; 24 | } 25 | } 26 | 27 | // Empty labels collapse automatically (not available in IE8) 28 | &:empty { 29 | display: none; 30 | } 31 | 32 | // Quick fix for labels in buttons 33 | .btn & { 34 | position: relative; 35 | top: -1px; 36 | } 37 | } 38 | 39 | // Colors 40 | // Contextual variations (linked labels get darker on :hover) 41 | 42 | .label-default { 43 | .label-variant(@label-default-bg); 44 | } 45 | 46 | .label-primary { 47 | .label-variant(@label-primary-bg); 48 | } 49 | 50 | .label-success { 51 | .label-variant(@label-success-bg); 52 | } 53 | 54 | .label-info { 55 | .label-variant(@label-info-bg); 56 | } 57 | 58 | .label-warning { 59 | .label-variant(@label-warning-bg); 60 | } 61 | 62 | .label-danger { 63 | .label-variant(@label-danger-bg); 64 | } 65 | -------------------------------------------------------------------------------- /src/assets/less/_bootstrap/media.less: -------------------------------------------------------------------------------- 1 | .media { 2 | // Proper spacing between instances of .media 3 | margin-top: 15px; 4 | 5 | &:first-child { 6 | margin-top: 0; 7 | } 8 | } 9 | 10 | .media, 11 | .media-body { 12 | zoom: 1; 13 | overflow: hidden; 14 | } 15 | 16 | .media-body { 17 | width: 10000px; 18 | } 19 | 20 | .media-object { 21 | display: block; 22 | 23 | // Fix collapse in webkit from max-width: 100% and display: table-cell. 24 | &.img-thumbnail { 25 | max-width: none; 26 | } 27 | } 28 | 29 | .media-right, 30 | .media > .pull-right { 31 | padding-left: 10px; 32 | } 33 | 34 | .media-left, 35 | .media > .pull-left { 36 | padding-right: 10px; 37 | } 38 | 39 | .media-left, 40 | .media-right, 41 | .media-body { 42 | display: table-cell; 43 | vertical-align: top; 44 | } 45 | 46 | .media-middle { 47 | vertical-align: middle; 48 | } 49 | 50 | .media-bottom { 51 | vertical-align: bottom; 52 | } 53 | 54 | // Reset margins on headings for tighter default spacing 55 | .media-heading { 56 | margin-top: 0; 57 | margin-bottom: 5px; 58 | } 59 | 60 | // Media list variation 61 | // 62 | // Undo default ul/ol styles 63 | .media-list { 64 | padding-left: 0; 65 | list-style: none; 66 | } 67 | -------------------------------------------------------------------------------- /src/assets/less/_bootstrap/mixins.less: -------------------------------------------------------------------------------- 1 | // Mixins 2 | // -------------------------------------------------- 3 | 4 | // Utilities 5 | @import "mixins/hide-text.less"; 6 | @import "mixins/opacity.less"; 7 | @import "mixins/image.less"; 8 | @import "mixins/labels.less"; 9 | @import "mixins/reset-filter.less"; 10 | @import "mixins/resize.less"; 11 | @import "mixins/responsive-visibility.less"; 12 | @import "mixins/size.less"; 13 | @import "mixins/tab-focus.less"; 14 | @import "mixins/reset-text.less"; 15 | @import "mixins/text-emphasis.less"; 16 | @import "mixins/text-overflow.less"; 17 | @import "mixins/vendor-prefixes.less"; 18 | 19 | // Components 20 | @import "mixins/alerts.less"; 21 | @import "mixins/buttons.less"; 22 | @import "mixins/panels.less"; 23 | @import "mixins/pagination.less"; 24 | @import "mixins/list-group.less"; 25 | @import "mixins/nav-divider.less"; 26 | @import "mixins/forms.less"; 27 | @import "mixins/progress-bar.less"; 28 | @import "mixins/table-row.less"; 29 | 30 | // Skins 31 | @import "mixins/background-variant.less"; 32 | @import "mixins/border-radius.less"; 33 | @import "mixins/gradients.less"; 34 | 35 | // Layout 36 | @import "mixins/clearfix.less"; 37 | @import "mixins/center-block.less"; 38 | @import "mixins/nav-vertical-align.less"; 39 | @import "mixins/grid-framework.less"; 40 | @import "mixins/grid.less"; 41 | -------------------------------------------------------------------------------- /src/assets/less/_bootstrap/mixins/alerts.less: -------------------------------------------------------------------------------- 1 | // Alerts 2 | 3 | .alert-variant(@background; @border; @text-color) { 4 | background-color: @background; 5 | border-color: @border; 6 | color: @text-color; 7 | 8 | hr { 9 | border-top-color: darken(@border, 5%); 10 | } 11 | .alert-link { 12 | color: darken(@text-color, 10%); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/assets/less/_bootstrap/mixins/background-variant.less: -------------------------------------------------------------------------------- 1 | // Contextual backgrounds 2 | 3 | .bg-variant(@color) { 4 | background-color: @color; 5 | a&:hover, 6 | a&:focus { 7 | background-color: darken(@color, 10%); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/assets/less/_bootstrap/mixins/border-radius.less: -------------------------------------------------------------------------------- 1 | // Single side border-radius 2 | 3 | .border-top-radius(@radius) { 4 | border-top-right-radius: @radius; 5 | border-top-left-radius: @radius; 6 | } 7 | .border-right-radius(@radius) { 8 | border-bottom-right-radius: @radius; 9 | border-top-right-radius: @radius; 10 | } 11 | .border-bottom-radius(@radius) { 12 | border-bottom-right-radius: @radius; 13 | border-bottom-left-radius: @radius; 14 | } 15 | .border-left-radius(@radius) { 16 | border-bottom-left-radius: @radius; 17 | border-top-left-radius: @radius; 18 | } 19 | -------------------------------------------------------------------------------- /src/assets/less/_bootstrap/mixins/buttons.less: -------------------------------------------------------------------------------- 1 | // Button variants 2 | // 3 | // Easily pump out default styles, as well as :hover, :focus, :active, 4 | // and disabled options for all buttons 5 | 6 | .button-variant(@color; @background; @border) { 7 | color: @color; 8 | background-color: @background; 9 | border-color: @border; 10 | 11 | &:focus, 12 | &.focus { 13 | color: @color; 14 | background-color: darken(@background, 10%); 15 | border-color: darken(@border, 25%); 16 | } 17 | &:hover { 18 | color: @color; 19 | background-color: darken(@background, 10%); 20 | border-color: darken(@border, 12%); 21 | } 22 | &:active, 23 | &.active, 24 | .open > .dropdown-toggle& { 25 | color: @color; 26 | background-color: darken(@background, 10%); 27 | border-color: darken(@border, 12%); 28 | 29 | &:hover, 30 | &:focus, 31 | &.focus { 32 | color: @color; 33 | background-color: darken(@background, 17%); 34 | border-color: darken(@border, 25%); 35 | } 36 | } 37 | &:active, 38 | &.active, 39 | .open > .dropdown-toggle& { 40 | background-image: none; 41 | } 42 | &.disabled, 43 | &[disabled], 44 | fieldset[disabled] & { 45 | &:hover, 46 | &:focus, 47 | &.focus { 48 | background-color: @background; 49 | border-color: @border; 50 | } 51 | } 52 | 53 | .badge { 54 | color: @background; 55 | background-color: @color; 56 | } 57 | } 58 | 59 | // Button sizes 60 | .button-size(@padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) { 61 | padding: @padding-vertical @padding-horizontal; 62 | font-size: @font-size; 63 | line-height: @line-height; 64 | border-radius: @border-radius; 65 | } 66 | -------------------------------------------------------------------------------- /src/assets/less/_bootstrap/mixins/center-block.less: -------------------------------------------------------------------------------- 1 | // Center-align a block level element 2 | 3 | .center-block() { 4 | display: block; 5 | margin-left: auto; 6 | margin-right: auto; 7 | } 8 | -------------------------------------------------------------------------------- /src/assets/less/_bootstrap/mixins/clearfix.less: -------------------------------------------------------------------------------- 1 | // Clearfix 2 | // 3 | // For modern browsers 4 | // 1. The space content is one way to avoid an Opera bug when the 5 | // contenteditable attribute is included anywhere else in the document. 6 | // Otherwise it causes space to appear at the top and bottom of elements 7 | // that are clearfixed. 8 | // 2. The use of `table` rather than `block` is only necessary if using 9 | // `:before` to contain the top-margins of child elements. 10 | // 11 | // Source: http://nicolasgallagher.com/micro-clearfix-hack/ 12 | 13 | .clearfix() { 14 | &:before, 15 | &:after { 16 | content: " "; // 1 17 | display: table; // 2 18 | } 19 | &:after { 20 | clear: both; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/assets/less/_bootstrap/mixins/forms.less: -------------------------------------------------------------------------------- 1 | // Form validation states 2 | // 3 | // Used in forms.less to generate the form validation CSS for warnings, errors, 4 | // and successes. 5 | 6 | .form-control-validation(@text-color: #555; @border-color: #ccc; @background-color: #f5f5f5) { 7 | // Color the label and help text 8 | .help-block, 9 | .control-label, 10 | .radio, 11 | .checkbox, 12 | .radio-inline, 13 | .checkbox-inline, 14 | &.radio label, 15 | &.checkbox label, 16 | &.radio-inline label, 17 | &.checkbox-inline label { 18 | color: @text-color; 19 | } 20 | // Set the border and box shadow on specific inputs to match 21 | .form-control { 22 | border-color: @border-color; 23 | .box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); // Redeclare so transitions work 24 | &:focus { 25 | border-color: darken(@border-color, 10%); 26 | @shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 6px lighten(@border-color, 20%); 27 | .box-shadow(@shadow); 28 | } 29 | } 30 | // Set validation states also for addons 31 | .input-group-addon { 32 | color: @text-color; 33 | border-color: @border-color; 34 | background-color: @background-color; 35 | } 36 | // Optional feedback icon 37 | .form-control-feedback { 38 | color: @text-color; 39 | } 40 | } 41 | 42 | 43 | // Form control focus state 44 | // 45 | // Generate a customized focus state and for any input with the specified color, 46 | // which defaults to the `@input-border-focus` variable. 47 | // 48 | // We highly encourage you to not customize the default value, but instead use 49 | // this to tweak colors on an as-needed basis. This aesthetic change is based on 50 | // WebKit's default styles, but applicable to a wider range of browsers. Its 51 | // usability and accessibility should be taken into account with any change. 52 | // 53 | // Example usage: change the default blue border and shadow to white for better 54 | // contrast against a dark gray background. 55 | .form-control-focus(@color: @input-border-focus) { 56 | @color-rgba: rgba(red(@color), green(@color), blue(@color), .6); 57 | &:focus { 58 | border-color: @color; 59 | outline: 0; 60 | .box-shadow(~"inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px @{color-rgba}"); 61 | } 62 | } 63 | 64 | // Form control sizing 65 | // 66 | // Relative text size, padding, and border-radii changes for form controls. For 67 | // horizontal sizing, wrap controls in the predefined grid classes. `