diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 0b1d2535be..0000000000 --- a/Dockerfile +++ /dev/null @@ -1,28 +0,0 @@ -FROM bagel/universe:337f873f4f23f4b2603972229ae3519c5f61f6d7 - -# Source -COPY ./app /opt/hub/app -# Webpack -COPY ./webpack.config.js /opt/hub/webpack.config.js -COPY ./_webpack /opt/hub/_webpack -# Make -COPY ./Makefile /opt/hub/Makefile -# Gulp -COPY ./gulpfile.js /opt/hub/gulpfile.js -COPY ./gulp-tasks /opt/hub/gulp-tasks -# ESLint -COPY ./.eslintrc /opt/hub/.eslintrc -# Flow -ENV LOGNAME bagels -COPY ./flow-libs /opt/hub/flow-libs -COPY .flowconfig /opt/hub/.flowconfig -ENV PATH /opt/flow/:$PATH - -RUN DEBUG=* webpack -d -RUN make server-target -RUN make styles-base -RUN gulp images::dev -RUN make images -RUN make docker-font-dev -# favicon -COPY ./app/favicon.ico /opt/hub/app/.build/ diff --git a/Jenkinsfile b/Jenkinsfile deleted file mode 100644 index fa29520b5f..0000000000 --- a/Jenkinsfile +++ /dev/null @@ -1,8 +0,0 @@ -// Only run on Linux atm -wrappedNode(label: 'docker') { - deleteDir() - stage "checkout" - checkout scm - - documentationChecker("docs") -} diff --git a/Makefile b/Makefile deleted file mode 100644 index abe9264a6e..0000000000 --- a/Makefile +++ /dev/null @@ -1,94 +0,0 @@ -.PHONY: dns server-prod-target server-target server-extras base base-tag prod prod-tag push-builders js-prod images images-prod - -# Set up make's -dns: - ./containers/dnsmasq/configure_system_dns.sh -hub-deps: - git clone git@github.com:docker/docker-ux.git ./private-deps/docker-ux - git clone git@github.com:docker/hub-js-sdk.git ./private-deps/hub-js-sdk -# -> bootstrap-dev -server-target: - mkdir -p app/.build/public/styles - cp -R app/img app/.build/public -styles-base: - cp ./private-deps/docker-ux/dist/styles/main.css ./app/.build/public/styles/main.css -images: - cp -R ./private-deps/docker-ux/dist/images ./app/.build/public/ -docker-font-dev: - cp -R ./private-deps/docker-ux/dist/fonts ./app/.build/public/ - cp ./app/fonts/* ./app/.build/public/fonts/ - mkdir -p app/.build/public/styles - cp ./app/styles/font-awesome.min.css ./app/.build/public/styles/font-awesome.min.css - -# Circle make's -local: - docker build -f local.Dockerfile -t bagel/hub-builders-local . -copy-local: - docker run --name bagel-local -d bagel/hub-builders-local sleep 50s - docker cp bagel-local:/opt/hub/.build-prod ./.local/ -stage: - docker build -f dockerfiles/Dockerfile-stage-build -t bagel/hub-builders-stage . -copy-stage: - docker run --name bagel-stage -d bagel/hub-builders-stage sleep 50s - docker cp bagel-stage:/opt/hub/.build-prod ./.stage/ -prod: - docker build -f dockerfiles/Dockerfile-prod-build -t bagel/hub-builders-prod . -base-prod-tag: - $(shell docker tag bagel/hub-builders-prod:latest bagel/hub-builders-prod:$(shell git rev-parse --verify HEAD)) -copy-prod: - docker run --name bagel-prod -d bagel/hub-builders-prod sleep 50s - docker cp bagel-prod:/opt/hub/.build-prod . - -# Dockerfile make's -server-prod-target: - rm -rf .build-prod - mkdir -p .build-prod -server-extras: - cp app-server/package.json .build-prod/package.json - cp app-server/favicons/favicon-dev.ico .build-prod/favicon.ico - cp app-server/Dockerfile .build-prod/Dockerfile -js-prod: - ENV=production webpack --production --config _webpack/webpack.prod.config.js - ENV=production webpack --production --config _webpack/webpack.server.config.js -js-stage: - ENV=staging webpack --production --config _webpack/webpack.prod.config.js - ENV=staging webpack --production --config _webpack/webpack.server.config.js -js-local: - ENV=local webpack --production --config _webpack/webpack.prod.config.js - ENV=local webpack --production --config _webpack/webpack.server.config.js -images-prod: - cp -R ./private-deps/docker-ux/dist/images .build-prod/public/ -docker-font-prod: - cp -R ./private-deps/docker-ux/dist/fonts .build-prod/public - cp -R ./app/fonts/* .build-prod/public/fonts/ - mkdir -p app/.build-prod/public/styles - cp ./app/styles/font-awesome.min.css .build-prod/public/styles/font-awesome.min.css -styles-base-prod: - cp ./private-deps/docker-ux/dist/styles/main.css .build-prod/public/styles/main.css -stats-dir: - mkdir -p /stats/css -css-stats: - /opt/hub/node_modules/.bin/cssstats file /opt/hub/.build-prod/public/styles/$(shell cat /tmp/.client-js-hash) > /stats/css-stats.json - -# Unused make commands -# Universe commands are no longer used as we now have the universe branch -dev-test-jest: - docker build -f dockerfiles/Dockerfile-builders-dev-jest -t bagel/hub-builders-dev-jest . -prod-tag: - $(shell docker tag bagel/hub-prod:latest bagel/hub-prod:$(shell git rev-parse --verify HEAD)) -universe: -# [ ! "${$(npm -v):0:1}" == "2" ] && echo "please \"npm install -g npm\" to get npm3'" && exit 1 - rm -rf node_modules - npm install --production - docker build -f dockerfiles/milky-way -t bagel/milky-way . - docker build -f dockerfiles/universe -t bagel/universe . -push-universe: - $(shell docker tag bagel/milky-way:latest bagel/milky-way:$(shell git rev-parse --verify HEAD)) - $(shell docker tag bagel/universe:latest bagel/universe:$(shell git rev-parse --verify HEAD)) - docker push bagel/milky-way - docker push bagel/universe -new-universe: - sed -i '.bak' "s/universe:[a-z0-9]*$$/universe:${UNIVERSE_TAG}/" Dockerfile - sed -i '.bak' "s/universe:[a-z0-9]*$$/universe:${UNIVERSE_TAG}/" local.Dockerfile - sed -i '.bak' "s/universe:[a-z0-9]*$$/universe:${UNIVERSE_TAG}/" dockerfiles/* - sed -i '.bak' "s/milky-way:[a-z0-9]*$$/milky-way:${UNIVERSE_TAG}/" dockerfiles/* diff --git a/README.md b/README.md deleted file mode 100644 index 50a2ce98bb..0000000000 --- a/README.md +++ /dev/null @@ -1,43 +0,0 @@ -# Quickstart - -*Make sure to clone this repo into your `/Users/` directory for it to run correctly* - -```bash -make dns -make hub-deps -# you must log in as the 'dux' user. ask one of the frontend -# team members for credentials -npm login -npm install -docker-compose build -npm run build:dev -./startup-scripts/bootstrap-dev.sh -docker-compose up -d -``` - -At this point you will need `tmux` to run `boot-dev-tmux.sh`, it can -be installed on OSX by `brew install tmux` - -```bash -./startup-scripts/boot-dev-tmux.sh -``` - -## tmux env - -Here are some basic commands to help you get around tmux. `C` is -Control, `-` means hit both keys, everything else it a literal -character you need to produce. - -| Command | Keys | -|--------------|---------| -| Next Window | C-b n | -| Next Panel | C-b o | -| Close Window | C-b & y | - -# Docs - -* [React](docs/concepts/React.md) -* [Flux](docs/concepts/Flux.md) -* [React Native](docs/concepts/React-Native.md) -* [React Router](docs/concepts/React-Router.md) -* [Immutability](docs/concepts/Immutability.md) diff --git a/_webpack/_common.webpack.config b/_webpack/_common.webpack.config deleted file mode 100644 index bf58cb7d55..0000000000 --- a/_webpack/_common.webpack.config +++ /dev/null @@ -1,105 +0,0 @@ -var ExtractTextPlugin = require("extract-text-webpack-plugin"); -var debug = require('debug')('webpack--common'); -var fs = require('fs'); -var merge = require('lodash/object/merge'); -var cssstats = require('postcss-cssstats'); -var loaders = require('./_commonLoaders'); - -/* Dux Button Config */ -var elementButton = require('@dux/element-button/defaults'); -var buttons = elementButton.mkButtons([{ - name: 'primary', - color: '#FFF', - bg: '#22B8EB' -},{ - name: 'secondary', - color: '#FFF', - bg: '#232C37' -},{ - name: 'coral', - color: '#FFF', - bg: '#FF85AF' -},{ - name: 'success', - color: '#FFF', - bg: '#0FD85A' -},{ - name: 'warning', - color: '#FFF', - bg: '#FF8546' -},{ - name: 'yellow', - color: '#FFF', - bg: '#FFDE50' -},{ - name: 'alert', - color: '#FFF', - bg: '#EB3E46' -}]); -/** - * cssnaneOpts can be true or an options object - * - * http://cssnano.co/options/ - */ -var cssnanoOpts = { - mergeIdents: false -}; -const defaults = merge(require('@dux/element-card/defaults')({ - capBackground: '#f1f6fb', - borderColor: '#c4cdda' - }), - { - duxElementButton: { - radius: '.25rem', - buttons: buttons - } - }); -module.exports = { - resolve: { - extensions: ['', '.js', '.jsx', '.json'], - root: [ - '/opt/hub/app/scripts/', - '/opt/hub/app/scripts/components' - ] - }, - module: { - preLoaders: loaders.preLoaders, - loaders: loaders.commonLoaders - }, - postcss: [ - require('postcss-import')(), - require('postcss-constants')({ - defaults: defaults - }), - require('postcss-each'), - require('postcss-cssnext')({ - browsers: 'last 2 versions', - features: { - // https://github.com/robwierzbowski/node-pixrem/issues/40 - rem: false - } - }), - require('postcss-nested'), - require('lost')({ - gutter: '1.25rem', - flexbox: 'flex' - }), - require('postcss-cssstats')(function(stats) { - /** - * this cssstats callback runs for every postcss file - * perhaps we want to write out this object and - * record the values over time? - * - * problem: there is no filename here - */ - debug(stats); - }), - require('postcss-url')(), - require('cssnano')(cssnanoOpts) - ], - eslint: { - failOnError: true - }, - bail: true, - profile: true -} diff --git a/_webpack/_commonLoaders.js b/_webpack/_commonLoaders.js deleted file mode 100644 index cd4a46ed51..0000000000 --- a/_webpack/_commonLoaders.js +++ /dev/null @@ -1,22 +0,0 @@ -var ExtractTextPlugin = require("extract-text-webpack-plugin"); - -var babelcfg = 'babel?optional[]=runtime&stage=0'; - -var preLoaders = [ - { test: /\.jsx?$/, exclude: /node_modules/, loader: 'eslint'} -] - -var commonLoaders = [ - // This loader matches .js and .jsx files - { test: /\.json$/, loader: 'json' }, - { test: /\.jsx?$/, exclude: /node_modules/, loader: babelcfg}, - { test: /dux.*\.jsx?$/, loader: babelcfg}, - { test: /hub-js-sdk.*\.jsx?$/, exclude: /hub-js-sdk.*node_modules.*\.jsx?$/, loader: babelcfg }, - { test: /\.css$/, loader: ExtractTextPlugin.extract('style-loader', 'css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss-loader') }, - { test: /\.svg$/, loader: 'svg-inline' } -] - -module.exports = { - preLoaders: preLoaders, - commonLoaders: commonLoaders -} diff --git a/_webpack/_envConfig.js b/_webpack/_envConfig.js deleted file mode 100644 index 69b6ded1a3..0000000000 --- a/_webpack/_envConfig.js +++ /dev/null @@ -1,104 +0,0 @@ -var webpack = require('webpack'); -var debug = require('debug')('_envConfig'); - -debug(process.env.ENV); - -function isProd() { - return process.env.ENV === 'production'; -} - -/** - * `development` is staging. - * `staging` is also staging. - * - * The keys in these objects are possible ENV configurations - * - * Pointing production to staging during Alpha - */ - -var HUB_URLS = { - local: 'https://hub.dev.docker.com', - development: 'https://hub-stage.docker.com', - staging: 'https://hub-stage.docker.com', - production: 'https://hub.docker.com' -} - -var RECURLY_PUBLIC_KEY = { - local: 'sjc-9XwqFDBZALFs9BP9dn3J8e', - development: 'sjc-9XwqFDBZALFs9BP9dn3J8e', - production: 'sjc-JIfmXVz2OVkg3xg10NhWm1' -} - -// NO LONGER USED -// var MUNCHKIN_CODE = { -// staging: '453-IHP-147', -// production: '929-FJL-178' -// } - -var BUGSNAG_API_KEY = { - staging: 'ec43d0373895ee5eb76ec75301157a85', - production: 'd639ea00dd6e493b739de27a7ee0f90c' -} - -var TUTUM_SIGNIN_URLS = { - development: 'https://dashboard-staging.tutum.co/login/docker/', - production: 'https://dashboard.tutum.co/login/docker/' -} - -var COOKIE_DOMAIN = { - local: 'hub.dev.docker.com', - development: 'bagels.docker.com', - staging: 'hub-stage.docker.com', - production: 'hub.docker.com' -}; - -// NODE_ENV is an express thing but is NOT being used by us -if (isProd() || process.env.ENV === 'staging') { - process.env.NODE_ENV = 'production' -} - -if ( !~['development', 'local', 'staging', 'production'].indexOf(process.env.ENV) ) { - process.env.ENV = 'development'; -} - -// Override some ENV vars -process.env.HUB_API_BASE_URL = process.env.HUB_API_BASE_URL || HUB_URLS[process.env.ENV] || 'https://hub-stage.docker.com'; -process.env.REGISTRY_API_BASE_URL = HUB_URLS[process.env.ENV] || 'https://hub-stage.docker.com'; -process.env.RECURLY_PUBLIC_KEY = RECURLY_PUBLIC_KEY[process.env.ENV] || 'sjc-9XwqFDBZALFs9BP9dn3J8e'; - - -process.env.CLIENT_JS_FILENAME = process.env.CLIENT_JS_FILENAME || 'client.js'; -process.env.CSS_FILENAME = process.env.CSS_FILENAME || 'style.css'; -process.env.COOKIE_DOMAIN = COOKIE_DOMAIN[process.env.ENV] || 'bagels.docker.com'; - -process.env.BOT_TRACKING_ID = 'PXbPb4C2uT'; - -if(isProd()) { - process.env.BUGSNAG_API_KEY = BUGSNAG_API_KEY.production; - process.env.GOOGLE_TAG_MANAGER = 'gtmActive'; - process.env.BOT_TRACKING_ID = 'PXPmP8ILuI'; -} else if(process.env.ENV === 'staging') { - process.env.BUGSNAG_API_KEY = BUGSNAG_API_KEY.staging; - process.env.GOOGLE_TAG_MANAGER = 'gtmDisabled'; -} - -process.env.TUTUM_SIGNIN_URL = TUTUM_SIGNIN_URLS[process.env.ENV] || 'https://dashboard-staging.tutum.co/login/docker/'; - -process.env.NAUTILUS_API_BASE_URL = HUB_URLS[process.env.ENV] + '/api/nautilus/v1'; - -debug(process.env); - -module.exports = new webpack.EnvironmentPlugin([ - 'BUGSNAG_API_KEY', - 'CLIENT_JS_FILENAME', - 'CSS_FILENAME', - 'ENV', - 'NODE_ENV', - 'GOOGLE_TAG_MANAGER', - 'BOT_TRACKING_ID', - 'HUB_API_BASE_URL', - 'NAUTILUS_API_BASE_URL', - 'RECURLY_PUBLIC_KEY', - 'REGISTRY_API_BASE_URL', - 'TUTUM_SIGNIN_URL' -]); diff --git a/_webpack/hashAndReplaceClient.js b/_webpack/hashAndReplaceClient.js deleted file mode 100644 index 837e0b3a88..0000000000 --- a/_webpack/hashAndReplaceClient.js +++ /dev/null @@ -1,37 +0,0 @@ -var fs = require('fs'); -var assert = require('assert'); -/** - * Writes the stats object out to /stats.json so we can fetch it from - * the appropriate container. - * - * This fails hard (throws an AssertionError) if the filename does - * not match the regex. This is good because we don't want it shipping - * to production if we can't reliably find the hash for client.js. - * - * The `CLIENT_JS_REGEX` should match `output.filename` in the webpack - * config below. - */ -module.exports = function() { - var CLIENT_JS_REGEX = /client..*.js$/; - this.plugin('done', function(stats) { - var filename = stats.toJson().assets[0].name; - - console.log(filename); - console.log(stats.toJson().assets[0]); - // write stats object - fs.writeFileSync( - '/tmp/dux-stats-client-js.json', - JSON.stringify(stats.toJson())); - - // test `filename` - assert.strictEqual(true, !!filename.match(CLIENT_JS_REGEX), filename + ' does not match expected client.js regex') - - /** - * Store the client.js hash in /tmp/.clientjs-hash for use - * in the server build process - */ - fs.writeFile('/tmp/.client-js-hash', filename, 'utf8', function(err) { - if (err) throw err; - }); - }); -} \ No newline at end of file diff --git a/_webpack/webpack.prod.config.js b/_webpack/webpack.prod.config.js deleted file mode 100644 index c377284c22..0000000000 --- a/_webpack/webpack.prod.config.js +++ /dev/null @@ -1,32 +0,0 @@ -var ExtractTextPlugin = require("extract-text-webpack-plugin"); -var ENV_CONFIG = require('./_envConfig.js'); -var HASH_CLIENT = require('./hashAndReplaceClient'); -var _ = require('lodash'); -var commonConfig = require('./_common.webpack.config'); -var webpack = require('webpack'); -var debug = require('debug')('webpack--client'); - -var clientConfig = { - entry: '/opt/hub/app/scripts/client.js', - devtool: 'source-map', - output: { - path: '.build-prod/public/', - filename: 'js/client.[hash].js' - }, - plugins: [ - ENV_CONFIG, - new webpack.optimize.DedupePlugin(), - new webpack.optimize.UglifyJsPlugin({ - compress: { - warnings: false - } - }), - new ExtractTextPlugin('styles/[name]-[id]-[hash].css', { allChunks: true }), - HASH_CLIENT - ] -}; -var clientBundle = _.assign({}, commonConfig, clientConfig); - -module.exports = [ - clientBundle -]; diff --git a/_webpack/webpack.server.config.js b/_webpack/webpack.server.config.js deleted file mode 100644 index 0214170503..0000000000 --- a/_webpack/webpack.server.config.js +++ /dev/null @@ -1,54 +0,0 @@ -var assert = require('assert'); -var ExtractTextPlugin = require("extract-text-webpack-plugin"); -var ENV_CONFIG = require('./_envConfig.js'); -var _ = require('lodash'); -var commonConfig = require('./_common.webpack.config'); -var debug = require('debug')('webpack--server'); -var fs = require('fs'); - -process.env.CLIENT_JS_FILENAME = fs.readFileSync('/tmp/.client-js-hash', 'utf-8').split('js/')[1]; -var CSS_FILENAME = _.filter(fs.readdirSync('/opt/hub/.build-prod/public/styles/'), - function(str) { - return !/.*\.map$/.test(str); - }); - -assert.strictEqual(1, CSS_FILENAME.length, CSS_FILENAME); -process.env.CSS_FILENAME = CSS_FILENAME[0]; -fs.writeFileSync('/tmp/.client-js-hash', CSS_FILENAME); - -/** - * blacklist this array from being included in `externals`. - * - * This has the effect of making any modules in this list be - * resolved at build time instead of runtime. This affects the - * server bundle - */ -var blacklist = ['.bin', 'hub-js-sdk', 'dux']; -var node_modules = fs.readdirSync('node_modules').filter(function(x) { - return !_.includes(blacklist, x); -}); - -debug('modules that will be runtime require dependencies of the server: ', node_modules); - - -var serverConfig = { - entry: '/opt/hub/app/scripts/server.js', - output: { - path: '.build-prod/', - filename: 'server.js', - libraryTarget: 'commonjs2' - }, - plugins: [ - ENV_CONFIG, - new ExtractTextPlugin('/.ignore/whatever.css', { - allChunks: true - }) - ], - target: 'node', - externals: node_modules, - node: { - __dirname: '/opt/hub/' - } -}; - -module.exports = _.assign({}, commonConfig, serverConfig); diff --git a/app-server/Dockerfile b/app-server/Dockerfile deleted file mode 100644 index 74d2fdc0a0..0000000000 --- a/app-server/Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM bagel/node-alpine:4.1.2 - -WORKDIR /opt/hub - -COPY ./package.json package.json -ADD ./modules.tar /opt/hub/ -COPY ./server.js /opt/hub/ -COPY ./public /opt/hub/public/ -COPY favicon.ico /opt/hub/favicon.ico - -CMD ["node", "--max-old-space-size=2048", "server.js"] diff --git a/app-server/favicons/fav copy.png b/app-server/favicons/fav copy.png deleted file mode 100644 index 7b36ba7a6e..0000000000 Binary files a/app-server/favicons/fav copy.png and /dev/null differ diff --git a/app-server/favicons/favicon-dev.ico b/app-server/favicons/favicon-dev.ico deleted file mode 100644 index f4766ac404..0000000000 Binary files a/app-server/favicons/favicon-dev.ico and /dev/null differ diff --git a/app-server/favicons/favicon.ico b/app-server/favicons/favicon.ico deleted file mode 100644 index 7b36ba7a6e..0000000000 Binary files a/app-server/favicons/favicon.ico and /dev/null differ diff --git a/app-server/package.json b/app-server/package.json deleted file mode 100644 index 2049a85b85..0000000000 --- a/app-server/package.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "name": "docker-hub", - "version": "0.0.1", - "private": true, - "scripts": { - "test": "gulp test", - "start": "node --harmony server/server.js" - }, - "dependencies": { - "@dux/element-card": "0.0.4", - "@dux/element-markdown": "0.0.3", - "@dux/element-button": "0.0.3", - "MD5": "^1.2.1", - "async": "^1.3.0", - "babel": "^5.0.12", - "babel-runtime": "^5.6.18", - "body-parser": "^1.12.2", - "classnames": "^2.1.2", - "cookie": "^0.1.2", - "cookie-parser": "^1.3.4", - "csurf": "^1.8.0", - "debug": "^2.1.3", - "dux": "file:../docker-ux", - "express": "^4.12.3", - "express-state": "^1.2.0", - "flux-router-component": "^0.6.1", - "fluxible": "^0.4.3", - "fluxible-plugin-fetchr": "^0.2.3", - "fluxible-plugin-routr": "^0.3.0", - "highlight.js": "^8.5.0", - "hub-js-sdk": "file:../hub-js-sdk", - "keymirror": "^0.1.1", - "lodash": "^3.6.0", - "marked": "^0.3.3", - "moment": "^2.10.3", - "newrelic": "christopherbiscardi/node-newrelic#c4ccca3764acafaf9c5899e4a1abece828e1f7b8", - "node-jsx": "^0.12.4", - "numeral": "^1.5.3", - "react": "^0.13.1", - "react-router": "^0.13.2", - "react-select": "^0.6.12", - "react-tagsinput": "^1.0.0", - "recurly-js": "git://github.com/recurly/recurly-js#d9740eb3ee416fb999635daecfb524a492dbb058", - "remarkable": "^1.6.0", - "serialize-javascript": "^1.0.0", - "serve-favicon": "^2.2.0", - "superagent": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } -} diff --git a/app/.htaccess b/app/.htaccess deleted file mode 100644 index ca346584ca..0000000000 --- a/app/.htaccess +++ /dev/null @@ -1,663 +0,0 @@ -# Apache Server Configs v2.2.0 | MIT License -# https://github.com/h5bp/server-configs-apache - -# (!) Using `.htaccess` files slows down Apache, therefore, if you have access -# to the main server config file (usually called `httpd.conf`), you should add -# this logic there: http://httpd.apache.org/docs/current/howto/htaccess.html. - -# ############################################################################## -# # CROSS-ORIGIN RESOURCE SHARING (CORS) # -# ############################################################################## - -# ------------------------------------------------------------------------------ -# | Cross-domain AJAX requests | -# ------------------------------------------------------------------------------ - -# Allow cross-origin AJAX requests. -# http://code.google.com/p/html5security/wiki/CrossOriginRequestSecurity -# http://enable-cors.org/ - -# -# Header set Access-Control-Allow-Origin "*" -# - -# ------------------------------------------------------------------------------ -# | CORS-enabled images | -# ------------------------------------------------------------------------------ - -# Send the CORS header for images when browsers request it. -# https://developer.mozilla.org/en-US/docs/HTML/CORS_Enabled_Image -# http://blog.chromium.org/2011/07/using-cross-domain-images-in-webgl-and.html -# http://hacks.mozilla.org/2011/11/using-cors-to-load-webgl-textures-from-cross-domain-images/ - - - - - SetEnvIf Origin ":" IS_CORS - Header set Access-Control-Allow-Origin "*" env=IS_CORS - - - - -# ------------------------------------------------------------------------------ -# | Web fonts access | -# ------------------------------------------------------------------------------ - -# Allow access to web fonts from all domains. - - - - Header set Access-Control-Allow-Origin "*" - - - - -# ############################################################################## -# # ERRORS # -# ############################################################################## - -# ------------------------------------------------------------------------------ -# | 404 error prevention for non-existing redirected folders | -# ------------------------------------------------------------------------------ - -# Prevent Apache from returning a 404 error as the result of a rewrite -# when the directory with the same name does not exist. -# http://httpd.apache.org/docs/current/content-negotiation.html#multiviews -# http://www.webmasterworld.com/apache/3808792.htm - -Options -MultiViews - -# ------------------------------------------------------------------------------ -# | Custom error messages / pages | -# ------------------------------------------------------------------------------ - -# Customize what Apache returns to the client in case of an error. -# http://httpd.apache.org/docs/current/mod/core.html#errordocument - -ErrorDocument 404 /404.html - - -# ############################################################################## -# # INTERNET EXPLORER # -# ############################################################################## - -# ------------------------------------------------------------------------------ -# | Better website experience | -# ------------------------------------------------------------------------------ - -# Force Internet Explorer to render pages in the highest available mode -# in the various cases when it may not. -# http://hsivonen.iki.fi/doctype/ie-mode.pdf - - - Header set X-UA-Compatible "IE=edge" - # `mod_headers` cannot match based on the content-type, however, this - # header should be send only for HTML pages and not for the other resources - - Header unset X-UA-Compatible - - - -# ------------------------------------------------------------------------------ -# | Cookie setting from iframes | -# ------------------------------------------------------------------------------ - -# Allow cookies to be set from iframes in Internet Explorer. -# http://msdn.microsoft.com/en-us/library/ms537343.aspx -# http://www.w3.org/TR/2000/CR-P3P-20001215/ - -# -# Header set P3P "policyref=\"/w3c/p3p.xml\", CP=\"IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\"" -# - - -# ############################################################################## -# # MIME TYPES AND ENCODING # -# ############################################################################## - -# ------------------------------------------------------------------------------ -# | Proper MIME types for all files | -# ------------------------------------------------------------------------------ - - - - # Audio - AddType audio/mp4 m4a f4a f4b - AddType audio/ogg oga ogg opus - - # Data interchange - AddType application/json json map - AddType application/ld+json jsonld - - # JavaScript - # Normalize to standard type. - # http://tools.ietf.org/html/rfc4329#section-7.2 - AddType application/javascript js - - # Video - AddType video/mp4 f4v f4p m4v mp4 - AddType video/ogg ogv - AddType video/webm webm - AddType video/x-flv flv - - # Web fonts - AddType application/font-woff woff - AddType application/vnd.ms-fontobject eot - - # Browsers usually ignore the font MIME types and simply sniff the bytes - # to figure out the font type. - # http://mimesniff.spec.whatwg.org/#matching-a-font-type-pattern - - # Chrome however, shows a warning if any other MIME types are used for - # the following fonts. - - AddType application/x-font-ttf ttc ttf - AddType font/opentype otf - - # Make SVGZ fonts work on the iPad. - # https://twitter.com/FontSquirrel/status/14855840545 - AddType image/svg+xml svgz - AddEncoding gzip svgz - - # Other - AddType application/octet-stream safariextz - AddType application/x-chrome-extension crx - AddType application/x-opera-extension oex - AddType application/x-web-app-manifest+json webapp - AddType application/x-xpinstall xpi - AddType application/xml atom rdf rss xml - AddType image/webp webp - AddType image/x-icon cur - AddType text/cache-manifest appcache manifest - AddType text/vtt vtt - AddType text/x-component htc - AddType text/x-vcard vcf - - - -# ------------------------------------------------------------------------------ -# | UTF-8 encoding | -# ------------------------------------------------------------------------------ - -# Use UTF-8 encoding for anything served as `text/html` or `text/plain`. -AddDefaultCharset utf-8 - -# Force UTF-8 for certain file formats. - - AddCharset utf-8 .atom .css .js .json .jsonld .rss .vtt .webapp .xml - - - -# ############################################################################## -# # URL REWRITES # -# ############################################################################## - -# ------------------------------------------------------------------------------ -# | Rewrite engine | -# ------------------------------------------------------------------------------ - -# Turn on the rewrite engine and enable the `FollowSymLinks` option (this is -# necessary in order for the following directives to work). - -# If your web host doesn't allow the `FollowSymlinks` option, you may need to -# comment it out and use `Options +SymLinksIfOwnerMatch`, but be aware of the -# performance impact. -# http://httpd.apache.org/docs/current/misc/perf-tuning.html#symlinks - -# Also, some cloud hosting services require `RewriteBase` to be set. -# http://www.rackspace.com/knowledge_center/frequently-asked-question/why-is-mod-rewrite-not-working-on-my-site - - - Options +FollowSymlinks - # Options +SymLinksIfOwnerMatch - RewriteEngine On - # RewriteBase / - - -# ------------------------------------------------------------------------------ -# | Suppressing / Forcing the `www.` at the beginning of URLs | -# ------------------------------------------------------------------------------ - -# The same content should never be available under two different URLs, -# especially not with and without `www.` at the beginning. This can cause -# SEO problems (duplicate content), and therefore, you should choose one -# of the alternatives and redirect the other one. - -# By default `Option 1` (no `www.`) is activated. -# http://no-www.org/faq.php?q=class_b - -# If you would prefer to use `Option 2`, just comment out all the lines -# from `Option 1` and uncomment the ones from `Option 2`. - -# IMPORTANT: NEVER USE BOTH RULES AT THE SAME TIME! - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# Option 1: rewrite www.example.com → example.com - - - RewriteCond %{HTTPS} !=on - RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC] - RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L] - - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# Option 2: rewrite example.com → www.example.com - -# Be aware that the following might not be a good idea if you use "real" -# subdomains for certain parts of your website. - -# -# RewriteCond %{HTTPS} !=on -# RewriteCond %{HTTP_HOST} !^www\. [NC] -# RewriteCond %{SERVER_ADDR} !=127.0.0.1 -# RewriteCond %{SERVER_ADDR} !=::1 -# RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L] -# - - -# ############################################################################## -# # SECURITY # -# ############################################################################## - -# ------------------------------------------------------------------------------ -# | Clickjacking | -# ------------------------------------------------------------------------------ - -# Protect website against clickjacking. - -# The example below sends the `X-Frame-Options` response header with the value -# `DENY`, informing browsers not to display the web page content in any frame. - -# This might not be the best setting for everyone. You should read about the -# other two possible values for `X-Frame-Options`: `SAMEORIGIN` & `ALLOW-FROM`. -# http://tools.ietf.org/html/rfc7034#section-2.1 - -# Keep in mind that while you could send the `X-Frame-Options` header for all -# of your site’s pages, this has the potential downside that it forbids even -# non-malicious framing of your content (e.g.: when users visit your site using -# a Google Image Search results page). - -# Nonetheless, you should ensure that you send the `X-Frame-Options` header for -# all pages that allow a user to make a state changing operation (e.g: pages -# that contain one-click purchase links, checkout or bank-transfer confirmation -# pages, pages that make permanent configuration changes, etc.). - -# Sending the `X-Frame-Options` header can also protect your website against -# more than just clickjacking attacks: https://cure53.de/xfo-clickjacking.pdf. - -# http://tools.ietf.org/html/rfc7034 -# http://blogs.msdn.com/b/ieinternals/archive/2010/03/30/combating-clickjacking-with-x-frame-options.aspx -# https://www.owasp.org/index.php/Clickjacking - -# -# Header set X-Frame-Options "DENY" -# -# Header unset X-Frame-Options -# -# - -# ------------------------------------------------------------------------------ -# | Content Security Policy (CSP) | -# ------------------------------------------------------------------------------ - -# Mitigate the risk of cross-site scripting and other content-injection attacks. - -# This can be done by setting a `Content Security Policy` which whitelists -# trusted sources of content for your website. - -# The example header below allows ONLY scripts that are loaded from the current -# site's origin (no inline scripts, no CDN, etc). This almost certainly won't -# work as-is for your site! - -# For more details on how to craft a reasonable policy for your site, read: -# http://html5rocks.com/en/tutorials/security/content-security-policy (or the -# specification: http://w3.org/TR/CSP). Also, to make things easier, you can -# use an online CSP header generator such as: http://cspisawesome.com/. - -# -# Header set Content-Security-Policy "script-src 'self'; object-src 'self'" -# -# Header unset Content-Security-Policy -# -# - -# ------------------------------------------------------------------------------ -# | File access | -# ------------------------------------------------------------------------------ - -# Block access to directories without a default document. -# You should leave the following uncommented, as you shouldn't allow anyone to -# surf through every directory on your server (which may includes rather private -# places such as the CMS's directories). - - - Options -Indexes - - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# Block access to hidden files and directories. -# This includes directories used by version control systems such as Git and SVN. - - - RewriteCond %{SCRIPT_FILENAME} -d [OR] - RewriteCond %{SCRIPT_FILENAME} -f - RewriteRule "(^|/)\." - [F] - - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# Block access to files that can expose sensitive information. - -# By default, block access to backup and source files that may be left by some -# text editors and can pose a security risk when anyone has access to them. -# http://feross.org/cmsploit/ - -# IMPORTANT: Update the `` regular expression from below to include -# any files that might end up on your production server and can expose sensitive -# information about your website. These files may include: configuration files, -# files that contain metadata about the project (e.g.: project dependencies), -# build scripts, etc.. - - - - # Apache < 2.3 - - Order allow,deny - Deny from all - Satisfy All - - - # Apache ≥ 2.3 - - Require all denied - - - - -# ------------------------------------------------------------------------------ -# | Reducing MIME-type security risks | -# ------------------------------------------------------------------------------ - -# Prevent some browsers from MIME-sniffing the response. - -# This reduces exposure to drive-by download attacks and should be enable -# especially if the web server is serving user uploaded content, content -# that could potentially be treated by the browser as executable. - -# http://blogs.msdn.com/b/ie/archive/2008/07/02/ie8-security-part-v-comprehensive-protection.aspx -# http://msdn.microsoft.com/en-us/library/ie/gg622941.aspx -# http://mimesniff.spec.whatwg.org/ - -# -# Header set X-Content-Type-Options "nosniff" -# - -# ------------------------------------------------------------------------------ -# | Reflected Cross-Site Scripting (XSS) attacks | -# ------------------------------------------------------------------------------ - -# (1) Try to re-enable the Cross-Site Scripting (XSS) filter built into the -# most recent web browsers. -# -# The filter is usually enabled by default, but in some cases it may be -# disabled by the user. However, in Internet Explorer for example, it can -# be re-enabled just by sending the `X-XSS-Protection` header with the -# value of `1`. -# -# (2) Prevent web browsers from rendering the web page if a potential reflected -# (a.k.a non-persistent) XSS attack is detected by the filter. -# -# By default, if the filter is enabled and browsers detect a reflected -# XSS attack, they will attempt to block the attack by making the smallest -# possible modifications to the returned web page. -# -# Unfortunately, in some browsers (e.g.: Internet Explorer), this default -# behavior may allow the XSS filter to be exploited, thereby, it's better -# to tell browsers to prevent the rendering of the page altogether, instead -# of attempting to modify it. -# -# http://hackademix.net/2009/11/21/ies-xss-filter-creates-xss-vulnerabilities -# -# IMPORTANT: Do not rely on the XSS filter to prevent XSS attacks! Ensure that -# you are taking all possible measures to prevent XSS attacks, the most obvious -# being: validating and sanitizing your site's inputs. -# -# http://blogs.msdn.com/b/ie/archive/2008/07/02/ie8-security-part-iv-the-xss-filter.aspx -# http://blogs.msdn.com/b/ieinternals/archive/2011/01/31/controlling-the-internet-explorer-xss-filter-with-the-x-xss-protection-http-header.aspx -# https://www.owasp.org/index.php/Cross-site_Scripting_%28XSS%29 - -# -# # (1) (2) -# Header set X-XSS-Protection "1; mode=block" -# -# Header unset X-XSS-Protection -# -# - -# ------------------------------------------------------------------------------ -# | Secure Sockets Layer (SSL) | -# ------------------------------------------------------------------------------ - -# Rewrite secure requests properly in order to prevent SSL certificate warnings. -# E.g.: prevent `https://www.example.com` when your certificate only allows -# `https://secure.example.com`. - -# -# RewriteCond %{SERVER_PORT} !^443 -# RewriteRule ^ https://example-domain-please-change-me.com%{REQUEST_URI} [R=301,L] -# - -# ------------------------------------------------------------------------------ -# | HTTP Strict Transport Security (HSTS) | -# ------------------------------------------------------------------------------ - -# Force client-side SSL redirection. - -# If a user types `example.com` in his browser, the above rule will redirect -# him to the secure version of the site. That still leaves a window of -# opportunity (the initial HTTP connection) for an attacker to downgrade or -# redirect the request. - -# The following header ensures that browser will ONLY connect to your server -# via HTTPS, regardless of what the users type in the address bar. - -# http://tools.ietf.org/html/draft-ietf-websec-strict-transport-sec-14#section-6.1 -# http://www.html5rocks.com/en/tutorials/security/transport-layer-security/ - -# IMPORTANT: Remove the `includeSubDomains` optional directive if the subdomains -# are not using HTTPS. - -# -# Header set Strict-Transport-Security "max-age=16070400; includeSubDomains" -# - -# ------------------------------------------------------------------------------ -# | Server software information | -# ------------------------------------------------------------------------------ - -# Avoid displaying the exact Apache version number, the description of the -# generic OS-type and the information about Apache's compiled-in modules. - -# ADD THIS DIRECTIVE IN THE `httpd.conf` AS IT WILL NOT WORK IN THE `.htaccess`! - -# ServerTokens Prod - - -# ############################################################################## -# # WEB PERFORMANCE # -# ############################################################################## - -# ------------------------------------------------------------------------------ -# | Compression | -# ------------------------------------------------------------------------------ - - - - # Force compression for mangled headers. - # http://developer.yahoo.com/blogs/ydn/posts/2010/12/pushing-beyond-gzipping - - - SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding - RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding - - - - # Compress all output labeled with one of the following MIME-types - # (for Apache versions below 2.3.7, you don't need to enable `mod_filter` - # and can remove the `` and `` lines - # as `AddOutputFilterByType` is still in the core directives). - - AddOutputFilterByType DEFLATE application/atom+xml \ - application/javascript \ - application/json \ - application/ld+json \ - application/rss+xml \ - application/vnd.ms-fontobject \ - application/x-font-ttf \ - application/x-web-app-manifest+json \ - application/xhtml+xml \ - application/xml \ - font/opentype \ - image/svg+xml \ - image/x-icon \ - text/css \ - text/html \ - text/plain \ - text/x-component \ - text/xml - - - - -# ------------------------------------------------------------------------------ -# | Content transformations | -# ------------------------------------------------------------------------------ - -# Prevent mobile network providers from modifying the website's content. -# http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.5. - -# -# Header set Cache-Control "no-transform" -# - -# ------------------------------------------------------------------------------ -# | ETags | -# ------------------------------------------------------------------------------ - -# Remove `ETags` as resources are sent with far-future expires headers. -# http://developer.yahoo.com/performance/rules.html#etags. - -# `FileETag None` doesn't work in all cases. - - Header unset ETag - - -FileETag None - -# ------------------------------------------------------------------------------ -# | Expires headers | -# ------------------------------------------------------------------------------ - -# The following expires headers are set pretty far in the future. If you -# don't control versioning with filename-based cache busting, consider -# lowering the cache time for resources such as style sheets and JavaScript -# files to something like one week. - - - - ExpiresActive on - ExpiresDefault "access plus 1 month" - - # CSS - ExpiresByType text/css "access plus 1 year" - - # Data interchange - ExpiresByType application/json "access plus 0 seconds" - ExpiresByType application/ld+json "access plus 0 seconds" - ExpiresByType application/xml "access plus 0 seconds" - ExpiresByType text/xml "access plus 0 seconds" - - # Favicon (cannot be renamed!) and cursor images - ExpiresByType image/x-icon "access plus 1 week" - - # HTML components (HTCs) - ExpiresByType text/x-component "access plus 1 month" - - # HTML - ExpiresByType text/html "access plus 0 seconds" - - # JavaScript - ExpiresByType application/javascript "access plus 1 year" - - # Manifest files - ExpiresByType application/x-web-app-manifest+json "access plus 0 seconds" - ExpiresByType text/cache-manifest "access plus 0 seconds" - - # Media - ExpiresByType audio/ogg "access plus 1 month" - ExpiresByType image/gif "access plus 1 month" - ExpiresByType image/jpeg "access plus 1 month" - ExpiresByType image/png "access plus 1 month" - ExpiresByType video/mp4 "access plus 1 month" - ExpiresByType video/ogg "access plus 1 month" - ExpiresByType video/webm "access plus 1 month" - - # Web feeds - ExpiresByType application/atom+xml "access plus 1 hour" - ExpiresByType application/rss+xml "access plus 1 hour" - - # Web fonts - ExpiresByType application/font-woff "access plus 1 month" - ExpiresByType application/vnd.ms-fontobject "access plus 1 month" - ExpiresByType application/x-font-ttf "access plus 1 month" - ExpiresByType font/opentype "access plus 1 month" - ExpiresByType image/svg+xml "access plus 1 month" - - - -# ------------------------------------------------------------------------------ -# | Filename-based cache busting | -# ------------------------------------------------------------------------------ - -# If you're not using a build process to manage your filename version revving, -# you might want to consider enabling the following directives to route all -# requests such as `/css/style.12345.css` to `/css/style.css`. - -# To understand why this is important and a better idea than `*.css?v231`, read: -# http://stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring - -# -# RewriteCond %{REQUEST_FILENAME} !-f -# RewriteRule ^(.+)\.(\d+)\.(js|css|png|jpe?g|gif)$ $1.$3 [L] -# - -# ------------------------------------------------------------------------------ -# | File concatenation | -# ------------------------------------------------------------------------------ - -# Allow concatenation from within specific style sheets and JavaScript files. - -# e.g.: -# -# If you have the following content in a file -# -# -# -# -# Apache will replace it with the content from the specified files. - -# -# -# Options +Includes -# AddOutputFilterByType INCLUDES application/javascript application/json -# SetOutputFilter INCLUDES -# -# -# Options +Includes -# AddOutputFilterByType INCLUDES text/css -# SetOutputFilter INCLUDES -# -# diff --git a/app/favicon.ico b/app/favicon.ico deleted file mode 100644 index ee01a5ee8a..0000000000 Binary files a/app/favicon.ico and /dev/null differ diff --git a/app/fonts/FontAwesome.otf b/app/fonts/FontAwesome.otf deleted file mode 100644 index 681bdd4d4c..0000000000 Binary files a/app/fonts/FontAwesome.otf and /dev/null differ diff --git a/app/fonts/fontawesome-webfont.eot b/app/fonts/fontawesome-webfont.eot deleted file mode 100644 index a30335d748..0000000000 Binary files a/app/fonts/fontawesome-webfont.eot and /dev/null differ diff --git a/app/fonts/fontawesome-webfont.svg b/app/fonts/fontawesome-webfont.svg deleted file mode 100644 index 6fd19abcb9..0000000000 --- a/app/fonts/fontawesome-webfont.svg +++ /dev/null @@ -1,640 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/fonts/fontawesome-webfont.ttf b/app/fonts/fontawesome-webfont.ttf deleted file mode 100644 index d7994e1308..0000000000 Binary files a/app/fonts/fontawesome-webfont.ttf and /dev/null differ diff --git a/app/fonts/fontawesome-webfont.woff b/app/fonts/fontawesome-webfont.woff deleted file mode 100644 index 6fd4ede0f3..0000000000 Binary files a/app/fonts/fontawesome-webfont.woff and /dev/null differ diff --git a/app/fonts/fontawesome-webfont.woff2 b/app/fonts/fontawesome-webfont.woff2 deleted file mode 100644 index 5560193ccc..0000000000 Binary files a/app/fonts/fontawesome-webfont.woff2 and /dev/null differ diff --git a/app/img/docker-logos/docker-logo.svg b/app/img/docker-logos/docker-logo.svg deleted file mode 100644 index 91c8e453fd..0000000000 --- a/app/img/docker-logos/docker-logo.svg +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/img/docker-logos/docker_logo-01.svg b/app/img/docker-logos/docker_logo-01.svg deleted file mode 100644 index c5f6b41245..0000000000 --- a/app/img/docker-logos/docker_logo-01.svg +++ /dev/null @@ -1,106 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/img/docker-logos/docker_logo-02.svg b/app/img/docker-logos/docker_logo-02.svg deleted file mode 100644 index 381aa6456c..0000000000 --- a/app/img/docker-logos/docker_logo-02.svg +++ /dev/null @@ -1,106 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/img/docker-logos/docker_logo-03.svg b/app/img/docker-logos/docker_logo-03.svg deleted file mode 100644 index 0e3c0e22ed..0000000000 --- a/app/img/docker-logos/docker_logo-03.svg +++ /dev/null @@ -1,110 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/img/docker-logos/docker_logo-04.svg b/app/img/docker-logos/docker_logo-04.svg deleted file mode 100644 index e06ac3f06b..0000000000 --- a/app/img/docker-logos/docker_logo-04.svg +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/img/docker-logos/docker_logo-05.svg b/app/img/docker-logos/docker_logo-05.svg deleted file mode 100644 index 4fbbf3671d..0000000000 --- a/app/img/docker-logos/docker_logo-05.svg +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/img/docker-logos/docker_logo-06.svg b/app/img/docker-logos/docker_logo-06.svg deleted file mode 100644 index cc0bccbdff..0000000000 --- a/app/img/docker-logos/docker_logo-06.svg +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/img/docker-logos/docker_logo-07.svg b/app/img/docker-logos/docker_logo-07.svg deleted file mode 100644 index 6cb705a9bd..0000000000 --- a/app/img/docker-logos/docker_logo-07.svg +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/img/docker-logos/docker_logo-08.svg b/app/img/docker-logos/docker_logo-08.svg deleted file mode 100644 index 28734a80b3..0000000000 --- a/app/img/docker-logos/docker_logo-08.svg +++ /dev/null @@ -1,102 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/img/services/bitbucket-logo.png b/app/img/services/bitbucket-logo.png deleted file mode 100644 index f3c9a9aa95..0000000000 Binary files a/app/img/services/bitbucket-logo.png and /dev/null differ diff --git a/app/img/services/github-logo.png b/app/img/services/github-logo.png deleted file mode 100644 index 582c451dac..0000000000 Binary files a/app/img/services/github-logo.png and /dev/null differ diff --git a/app/img/services/gitlab-logo.png b/app/img/services/gitlab-logo.png deleted file mode 100644 index 1b5d498261..0000000000 Binary files a/app/img/services/gitlab-logo.png and /dev/null differ diff --git a/app/robots.txt b/app/robots.txt deleted file mode 100644 index ee2cc216a6..0000000000 --- a/app/robots.txt +++ /dev/null @@ -1,3 +0,0 @@ -# robotstxt.org/ - -User-agent: * diff --git a/app/scripts/actions/addAutoBuildPushTriggerItem.js b/app/scripts/actions/addAutoBuildPushTriggerItem.js deleted file mode 100644 index a21b202150..0000000000 --- a/app/scripts/actions/addAutoBuildPushTriggerItem.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -export default function(actionContext) { - actionContext.dispatch('ADD_AUTOBUILD_PUSH_TRIGGER_ITEM'); -} diff --git a/app/scripts/actions/addCollaborator.js b/app/scripts/actions/addCollaborator.js deleted file mode 100644 index 37525ee890..0000000000 --- a/app/scripts/actions/addCollaborator.js +++ /dev/null @@ -1,29 +0,0 @@ -'use strict'; -import { Repositories } from 'hub-js-sdk'; -const { addCollaborator, getCollaboratorsForRepo } = Repositories; -import has from 'lodash/object/has'; -const debug = require('debug')('hub:actions:addCollaborator'); - -export default function addCollaboratorAction(actionContext, {JWT, namespace, name, user}, done) { - actionContext.dispatch('ADD_COLLAB_START'); - addCollaborator(JWT, { namespace, name, user }, (err, res) => { - if(err) { - if(has(err.response.body, 'detail')) { - debug('failed'); - actionContext.dispatch('ADD_COLLAB_ERROR', err.response.body.detail); - } - } else { - debug('succeeded'); - actionContext.dispatch('ADD_COLLAB_SUCCESS'); - getCollaboratorsForRepo(JWT, `${namespace}/${name}`, (getErr, getRes) => { - if(getErr) { - // 'Org repositories do not have collaborators.' - actionContext.dispatch('COLLAB_RECEIVE_COLLABORATORS', {}); - } else { - actionContext.dispatch('COLLAB_RECEIVE_COLLABORATORS', getRes.body); - } - }); - } - done(); - }); -} diff --git a/app/scripts/actions/addPipeline.js b/app/scripts/actions/addPipeline.js deleted file mode 100644 index b25996c516..0000000000 --- a/app/scripts/actions/addPipeline.js +++ /dev/null @@ -1,58 +0,0 @@ -'use strict'; - -import includes from 'lodash/collection/includes'; - -import createPipeline from '@dux/hub-sdk/webhooks/createPipeline'; -import MissingArgError from '@dux/hub-sdk/utils/MissingArgError'; -import ValidationError from '@dux/hub-sdk/utils/ValidationError'; - -function handleKnownErrors(err, dispatch) { - if(err instanceof MissingArgError) { - if(includes(err.missingArgs, 'namespace') || includes(err.missingArgs, 'name')) { - /** - * TODO: send something to bugsnag; The user doesn't control these values - * This can happen if an engineer forgets to pass in a required value that - * the user can't control - */ - dispatch('ADD_WEBHOOK_ERROR'); - } else { - dispatch('ADD_WEBHOOK_MISSING_ARGS', err.missingArgs); - } - } else if (err instanceof ValidationError) { - dispatch('ADD_WEBHOOK_VALIDATION_ERRORS', err.validationErrors); - } else { - // unknown error - dispatch('ADD_WEBHOOK_ERROR', err); - } -} - -export default function addPipeline({ dispatch, history }, - { - jwt, - namespace, - name, - pipelineName, - expectFinalCallback, - webhooks - }, - done) { - dispatch('ADD_WEBHOOK_START'); - createPipeline(jwt, - { - namespace, - name, - pipelineName, - expectFinalCallback, - webhooks - }, - (err, res) => { - if(err || !res.ok) { - handleKnownErrors(err, dispatch); - done(); - } else { - dispatch('ADD_WEBHOOK_SUCCESS'); - history.push(`/r/${namespace}/${name}/~/settings/webhooks/`); - done(); - } - }); -} diff --git a/app/scripts/actions/addRepoComment.js b/app/scripts/actions/addRepoComment.js deleted file mode 100644 index 3c0a30cb6a..0000000000 --- a/app/scripts/actions/addRepoComment.js +++ /dev/null @@ -1,24 +0,0 @@ -'use strict'; - -var debug = require('debug')('hub:actions:addRepoComment'); - -import { Repositories } from 'hub-js-sdk'; - -var addRepoComment = function(actionContext, {jwt, repoShortName, comment}) { - Repositories.addCommentToRepo(jwt, repoShortName, comment, function(addErr, addRes) { - if (addErr) { - debug(addErr); - } else if (addRes.body && addRes.ok) { - Repositories.getCommentsForRepo(jwt, repoShortName, function(getErr, getRes) { - if (getErr) { - debug(getErr); - } else { - actionContext.dispatch('RECEIVE_REPO_COMMENTS', getRes.body); - } - }, 1); - } - }); - -}; - -module.exports = addRepoComment; diff --git a/app/scripts/actions/addTeamCollaborator.js b/app/scripts/actions/addTeamCollaborator.js deleted file mode 100644 index e9e178b067..0000000000 --- a/app/scripts/actions/addTeamCollaborator.js +++ /dev/null @@ -1,26 +0,0 @@ -'use strict'; -import { - Repositories as R - } from 'hub-js-sdk'; -const debug = require('debug')('hub:actions:addCollaborator'); - -export default function addTeamCollaborator(actionContext, {JWT, namespace, name, id, permission}, done) { - actionContext.dispatch('ADD_COLLAB_START'); - R.addTeamCollaborator(JWT, { namespace, name, group_id: id, permission }, (err, res) => { - if(err) { - debug('failed'); - } else { - debug('succeeded'); - R.getTeamCollaboratorsForRepo(JWT, `${namespace}/${name}`, (getErr, getRes) => { - if (getErr) { - // 'User repository does not have any teams yet' - actionContext.dispatch('COLLAB_RECEIVE_TEAMS', {}); - } else { - actionContext.dispatch('COLLAB_RECEIVE_TEAMS', getRes.body); - } - }); - } - actionContext.dispatch('ADD_COLLAB_FINISH'); - done(); - }); -} diff --git a/app/scripts/actions/addTriggerLink.js b/app/scripts/actions/addTriggerLink.js deleted file mode 100644 index 1df118c658..0000000000 --- a/app/scripts/actions/addTriggerLink.js +++ /dev/null @@ -1,23 +0,0 @@ -'use strict'; -import _ from 'lodash'; -import { Autobuilds as AutoBuild } from 'hub-js-sdk'; -var debug = require('debug')('hub:actions:addTriggerLink'); - -export default function(actionContext, { JWT, namespace, name, to_repo }) { - // to_repo needs to be a repo id - AutoBuild.addAutomatedBuildLink(JWT, namespace, name, to_repo, function(err, res) { - if (err) { - debug(err); - actionContext.dispatch('LINK_AUTOBUILD_ERROR'); - } else { - actionContext.dispatch('LINK_AUTOBUILD_SUCCESS'); - AutoBuild.getAutomatedBuildLinks(JWT, namespace, name, function(getErr, getRes){ - if (getErr) { - debug(err); - } else { - actionContext.dispatch('RECEIVE_AUTOBUILD_LINKS', getRes.body.results); - } - }); - } - }); -} diff --git a/app/scripts/actions/addUserEmail.js b/app/scripts/actions/addUserEmail.js deleted file mode 100644 index 3f67808bde..0000000000 --- a/app/scripts/actions/addUserEmail.js +++ /dev/null @@ -1,34 +0,0 @@ -'use strict'; - -import { sortByOrder } from 'lodash'; -import { - Emails - } from 'hub-js-sdk'; -var debug = require('debug')('hub:actions:addEmail'); - -module.exports = function(actionContext, - { - JWT, newEmail, user - }, - done) { - Emails.addEmailsForUser(JWT, user.username, newEmail, function(err, res) { - if (err) { - debug('error', res.body); - actionContext.dispatch('ADD_EMAIL_INVALID', res.body.email); - } else if (res.ok) { - actionContext.dispatch('ADD_EMAIL_SUCCESS', res.body.email); - Emails.getEmailsForUser(JWT, user.username, function(emailErr, emailRes){ - if (emailErr) { - return done(); - } - var emails = emailRes.body.results; - var sortedEmails = sortByOrder(emails, - ['primary', 'verified'], - [false, false]); - actionContext.dispatch('RECEIVE_EMAILS', { - emails: sortedEmails - }); - }); - } - }); -}; diff --git a/app/scripts/actions/addUserEmailChange.js b/app/scripts/actions/addUserEmailChange.js deleted file mode 100644 index 3be02615c6..0000000000 --- a/app/scripts/actions/addUserEmailChange.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -export default function(actionContext, { email }) { - actionContext.dispatch('UPDATE_ADD_EMAIL', email); -} diff --git a/app/scripts/actions/addWebhookToPipeline.jsx b/app/scripts/actions/addWebhookToPipeline.jsx deleted file mode 100644 index a2605beda8..0000000000 --- a/app/scripts/actions/addWebhookToPipeline.jsx +++ /dev/null @@ -1,8 +0,0 @@ -'use strict'; - -export default function addWebhookToPipeline({ dispatch }, - params, - done) { - dispatch('ADD_WEBHOOK_NEW_HOOK'); - done(); -} diff --git a/app/scripts/actions/associateGithubAccount.js b/app/scripts/actions/associateGithubAccount.js deleted file mode 100644 index caf33396a8..0000000000 --- a/app/scripts/actions/associateGithubAccount.js +++ /dev/null @@ -1,23 +0,0 @@ -'use strict'; - -var debug = require('debug')('hub:actions:associateGithubAccount'); -import has from 'lodash/object/has'; -import { Builds } from 'hub-js-sdk'; - -export default function(actionContext, {jwt, code}) { - //TODO: immediately call the linked accounts status and update the authorized services page - Builds.associateGithubAccount(jwt, code, function(err, res) { - if (err) { - debug('error', err); - const { detail } = err.response.body; - if(detail) { - actionContext.dispatch('GITHUB_ASSOCIATE_ERROR', detail); - } - } else { - if (res.body) { - actionContext.dispatch('GITHUB_ASSOCIATE_SUCCESS', res.body); - } - } - }); - actionContext.dispatch(); -} diff --git a/app/scripts/actions/attemptChangeLongDescription.js b/app/scripts/actions/attemptChangeLongDescription.js deleted file mode 100644 index f976b9ad49..0000000000 --- a/app/scripts/actions/attemptChangeLongDescription.js +++ /dev/null @@ -1,56 +0,0 @@ -/* @flow */ -'use strict'; - -import { Repositories as Repos } from 'hub-js-sdk'; -import async from 'async'; -import { PENDING_DELETE } from 'common/enums/RepoStatus'; -var debug = require('debug')('hub:actions:attemptChangeLongDescription'); - -export default function(actionContext, - {jwt, repoShortName, longDescription}, - done) { - actionContext.dispatch('LONG_DESCRIPTION_ATTEMPT_START'); - - var _updateLongDescription = function(cb) { - Repos.patchRepo(jwt, repoShortName, { - full_description: longDescription - }, function(err, res) { - if (err) { - if(res && res.badRequest) { - debug('error', err); - actionContext.dispatch('LONG_BAD_REQUEST', res.body); - cb(err); - } else { - actionContext.dispatch('DETAILS_ERROR'); - cb(err); - } - } else { - actionContext.dispatch('LONG_DESCRIPTION_SUCCESS'); - cb(null, res.body); - } - }); - }; - - var _getRepoDetails = function(cb) { - Repos.getRepo(jwt, repoShortName, function(err, res) { - const { status, detail } = res.body; - - if (err || status === PENDING_DELETE) { - actionContext.dispatch('REPO_NOT_FOUND', err); - cb(null, detail); - } else { - actionContext.dispatch('RECEIVE_REPOSITORY', res.body); - cb(null, res.body); - } - }); - }; - - async.series([ - _updateLongDescription, - _getRepoDetails - ], function (err, results) { - if(err) { - debug('error', err); - } - }); -} diff --git a/app/scripts/actions/attemptChangeShortDescription.js b/app/scripts/actions/attemptChangeShortDescription.js deleted file mode 100644 index 725b7f5972..0000000000 --- a/app/scripts/actions/attemptChangeShortDescription.js +++ /dev/null @@ -1,58 +0,0 @@ -/* @flow */ -'use strict'; - -import async from 'async'; -import { Repositories as Repos } from 'hub-js-sdk'; -import { PENDING_DELETE } from 'common/enums/RepoStatus'; -var debug = require('debug')('hub:actions:attemptChangeShortDescription'); - -export default function(actionContext, - {jwt, repoShortName, shortDescription}, - done) { - actionContext.dispatch('SHORT_DESCRIPTION_ATTEMPT_START'); - - var name = repoShortName.split('/')[1]; - var namespace = repoShortName.split('/')[0]; - var _updateShortDescription = function(cb) { - Repos.patchRepo(jwt, repoShortName, {description: shortDescription}, - function(err, res) { - if (err) { - if(res && res.badRequest) { - debug('error', err); - actionContext.dispatch('SHORT_BAD_REQUEST', res.body); - cb(err); - } else { - actionContext.dispatch('DETAILS_ERROR'); - cb(err); - } - } else { - actionContext.dispatch('SHORT_DESCRIPTION_SUCCESS'); - cb(null, res.body); - } - } - ); - }; - - var _getRepoDetails = function(cb) { - Repos.getRepo(jwt, repoShortName, function(err, res) { - const { status, detail } = res.body; - - if (err || status === PENDING_DELETE) { - actionContext.dispatch('REPO_NOT_FOUND', err); - cb(null, detail); - } else { - actionContext.dispatch('RECEIVE_REPOSITORY', res.body); - cb(null, res.body); - } - }); - }; - - async.series([ - _updateShortDescription, - _getRepoDetails - ], function (err, results) { - if(err) { - debug('error', err); - } - }); -} diff --git a/app/scripts/actions/attemptLogin.js b/app/scripts/actions/attemptLogin.js deleted file mode 100644 index f0c0fe707f..0000000000 --- a/app/scripts/actions/attemptLogin.js +++ /dev/null @@ -1,147 +0,0 @@ -'use strict'; - -import { parallel, waterfall } from 'async'; -import { Auth, - Repositories as Repos - } from 'hub-js-sdk'; -var debug = require('debug')('hub:actions:attemptLogin'); -import { getActivityFeed } from 'hub-js-sdk/src/Hub/SDK/Notifications'; -import { getUser } from 'hub-js-sdk/src/Hub/SDK/JWT'; -import { - getOrgsForUser, - getUserSettings -} from 'hub-js-sdk/src/Hub/SDK/Users'; -import { getToken } from 'hub-js-sdk/src/Hub/SDK/Auth'; -import request from 'superagent'; - -function handleGetRepos({jwt, username, dispatch}) { - return function(callback) { - Repos.getReposForUser(jwt, username, function(err, res) { - if (err) { - callback(null, null); - } else { - dispatch('RECEIVE_REPOS', res.body); - } - }, 1); //get page 1 - }; -} - -function handleGetPrivateRepoStats({jwt, username, dispatch}) { - return function(callback) { - getUserSettings(jwt, username, function(err, res) { - if (res.ok) { - dispatch('RECEIVE_PRIVATE_REPOSTATS', res.body); - } - callback(null, null); - }); - }; -} - -//Get orgs for user -function _getOrgsForCurrentUser({jwt, username, dispatch}) { - return function(user, cb) { - getOrgsForUser(jwt, function(err, res) { - if (err) { - debug('error', err); - cb(null); - } else { - dispatch('RECEIVE_DASHBOARD_NAMESPACES', { - orgs: res.body, - user: user.username - }); - cb(null, user); - } - }); - }; -} - -function handleGetUserInfo({jwt, username, dispatch}, callback) { - waterfall([ - function(cb){ - getUser(jwt, function(err, res) { - if (err) { - cb(err, {}); - } else { - dispatch('RECEIVE_USER', res.body); - cb(null, res.body); - } - }); - }, - _getOrgsForCurrentUser({jwt, username, dispatch}) - ], function(err, user) { - callback(err, { user }); - }); -} - -function fetchDataForDashboard({ - jwt, username, dispatch, done -}) { - dispatch('RECEIVE_JWT', jwt); - dispatch('DASHBOARD_REPOS_STORE_ATTEMPTING_GET_REPOS'); - parallel([ - handleGetRepos({jwt, username, dispatch}), - handleGetPrivateRepoStats({jwt, username, dispatch}) - ], function(err, results) { - if (err) { - debug('error', err); - } - return done(); - }); -} - -module.exports = function({ dispatch, history }, - { username, password }, - done) { - dispatch('LOGIN_ATTEMPT_START'); - getToken(username, - password, - function(err, res) { - if (err) { - debug('error', err); - if (res.unauthorized) { - if(res.body && res.body.detail) { - /** - * This can happen if the user has not verified their email - */ - dispatch('LOGIN_UNAUTHORIZED_DETAIL', res.body); - } else { - dispatch('LOGIN_UNAUTHORIZED'); - } - } else if (res.badRequest){ - try { - dispatch('LOGIN_BAD_REQUEST', JSON.parse(res.text)); - } catch (error) { - dispatch('LOGIN_ERROR'); - } - } else { - // unhandled login error - dispatch('LOGIN_ERROR'); - } - } else { - debug('got token'); - if (res.body.token) { - request.post('/attempt-login/') - .send({jwt: res.body.token}) - .end((cookieErr, cookieRes) => { - handleGetUserInfo({ - jwt: res.body.token, - username, - dispatch - }, function(userErr, userRes) { - dispatch('LOGIN_CLEAR'); - dispatch('CURRENT_USER_CONTEXT', { - username: userRes.user.username - }); - history.pushState(null, '/'); - fetchDataForDashboard({ - jwt: res.body.token, - username: userRes.user.username, - dispatch, - done - }); - }); - }); - } - } - }); -}; diff --git a/app/scripts/actions/attemptSignup.js b/app/scripts/actions/attemptSignup.js deleted file mode 100644 index 197e35bc5d..0000000000 --- a/app/scripts/actions/attemptSignup.js +++ /dev/null @@ -1,30 +0,0 @@ -'use strict'; - -import { Auth } from 'hub-js-sdk'; -import type FluxibleActionContext from '../../../flow-libs/fluxible'; -var debug = require('debug')('hub:actions:attemptSignup'); - -type SignupPayload = { - username: String; - password: String; - email: String; -}; - -module.exports = function(actionContext: FluxibleActionContext, - payload: SignupPayload, - done: Function) { - actionContext.dispatch('SIGNUP_ATTEMPT_START'); - Auth.signup(payload, function(err, res) { - if (err) { - debug('error', err); - if (res.badRequest){ - actionContext.dispatch('SIGNUP_BAD_REQUEST', res.body); - } else { - done(); - } - actionContext.dispatch('SIGNUP_CLEAR_PASSWORD'); - } else { - actionContext.dispatch('SIGNUP_SUCCESS'); - } - }); -}; diff --git a/app/scripts/actions/cancelBuild.js b/app/scripts/actions/cancelBuild.js deleted file mode 100644 index 9ba44d0703..0000000000 --- a/app/scripts/actions/cancelBuild.js +++ /dev/null @@ -1,20 +0,0 @@ -'use strict'; -import { Builds } from 'hub-js-sdk'; -import has from 'lodash/object/has'; -const debug = require('debug')('hub:actions:cancelBuild'); - -export default function cancelBuildAction(actionContext, {JWT, id, namespace, name, build_code}, done) { - actionContext.dispatch('CANCEL_BUILD_START', id); - Builds.cancelBuild(JWT, { namespace, name, build_code }, (err, res) => { - if(err) { - debug('failed'); - const detail = has(err.response.body, 'detail') ? err.response.body : ''; - actionContext.dispatch('CANCEL_BUILD_ERROR', { id, detail: err.response.body.detail }); - - } else { - debug('succeeded'); - actionContext.dispatch('CANCEL_BUILD_SUCCESS', id); - } - done(); - }); -} diff --git a/app/scripts/actions/changePassword.js b/app/scripts/actions/changePassword.js deleted file mode 100644 index d38d26dede..0000000000 --- a/app/scripts/actions/changePassword.js +++ /dev/null @@ -1,48 +0,0 @@ -'use strict'; - -import { getToken, logout } from 'hub-js-sdk/src/Hub/SDK/Auth'; -import { changePassword } from 'hub-js-sdk/src/Hub/SDK/Users'; -import async from 'async'; -import request from 'superagent'; -var debug = require('debug')('hub:actions:changePassword'); - -var changePassAction = function({ dispatch, history }, - { - JWT, username, oldpassword, newpassword - }) { - changePassword( - JWT, - {username, oldpassword, newpassword}, - (err, res) => { - - if (err) { - debug('error', err); - dispatch('RESET_PASSWORD_ERROR', res.body); - } else if (res.ok) { - dispatch('CHANGE_PASS_SUCCESS'); - async.parallel([ - function(callback) { - logout(JWT, function(outErr, outRes) { - if (outErr) { - debug('outErr', outErr); - dispatch('LOGOUT_ERROR', outErr); - } else if (outRes.ok) { - dispatch('CHANGE_PASS_CLEAR', {}); - history.pushState(null, '/account/password-reset-confirm/success/'); - dispatch('LOGOUT'); - } - }); - }, - function(callback) { - request.post('/attempt-logout/') - .end(callback); - }], - function(asyncErr, asyncRes) { - - }); - } - } - ); -}; - -module.exports = changePassAction; diff --git a/app/scripts/actions/clearChangePasswordStore.js b/app/scripts/actions/clearChangePasswordStore.js deleted file mode 100644 index 2ec0e9b123..0000000000 --- a/app/scripts/actions/clearChangePasswordStore.js +++ /dev/null @@ -1,8 +0,0 @@ -/* @flow */ -'use strict'; - -import type FluxibleActionContext from '../../../flow-libs/fluxible'; - -module.exports = function(actionContext: FluxibleActionContext) { - actionContext.dispatch('CHANGE_PASS_CLEAR', {}); -}; diff --git a/app/scripts/actions/clearCloudCoupon.js b/app/scripts/actions/clearCloudCoupon.js deleted file mode 100644 index 88147ed0f0..0000000000 --- a/app/scripts/actions/clearCloudCoupon.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -export default (actionContext) => { - actionContext.dispatch('CLEAR_CLOUD_COUPON'); -}; diff --git a/app/scripts/actions/clearLoginForm.js b/app/scripts/actions/clearLoginForm.js deleted file mode 100644 index c677a394a0..0000000000 --- a/app/scripts/actions/clearLoginForm.js +++ /dev/null @@ -1,8 +0,0 @@ -/* @flow */ -'use strict'; - -import type FluxibleActionContext from '../../../flow-libs/fluxible'; - -module.exports = function(actionContext: FluxibleActionContext) { - actionContext.dispatch('LOGIN_CLEAR', {}); -}; diff --git a/app/scripts/actions/clearMemberError.js b/app/scripts/actions/clearMemberError.js deleted file mode 100644 index 6fab18e28e..0000000000 --- a/app/scripts/actions/clearMemberError.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -export default function(actionContext) { - actionContext.dispatch('CLEAR_MEMBER_ERROR'); -} diff --git a/app/scripts/actions/cloudNamespaceChange.js b/app/scripts/actions/cloudNamespaceChange.js deleted file mode 100644 index 2947f1bb80..0000000000 --- a/app/scripts/actions/cloudNamespaceChange.js +++ /dev/null @@ -1,78 +0,0 @@ -'use strict'; - -const debug = require('debug')('hub:actions:cloudNamespaceChange'); -import async from 'async'; -import _ from 'lodash'; - -import { - Billing, - Users - } from 'hub-js-sdk'; - -//GETs current HUB subscription -function _getBillingSubscriptions({JWT, namespace}) { - return (callback) => { - Billing.getBillingSubscriptions(JWT, namespace, (err, res) => { - if(err) { - callback(null, {}); - } else { - let subscriptions = res.body; - - // the assumption is that there is at most one subscription right now - let subscription = _.head(subscriptions); - callback(null, subscription); - } - }); - }; -} - -function _getBillingAccount({JWT, namespace}) { - return (callback) => { - Billing.getBillingAccount(JWT, namespace, (err, res) => { - if(err) { - debug('getBillingAccount', 'no billing account connected'); - callback(null, {}); - } else { - callback(null, res.body); - } - }); - }; -} - -function _getBillingInfo({JWT, namespace}) { - return (callback) => { - Billing.getBillingInfo(JWT, namespace, (err, res) => { - if(err) { - debug('getBillingInfo', 'no billing account connected'); - callback(null, {}); - } else { - callback(null, res.body); - } - }); - }; -} - -export default function billingPlans(actionContext, {JWT, namespace}, done){ - actionContext.dispatch('RESET_CLOUD_BILLING_PLANS'); - async.parallel({ - userPlan: _getBillingSubscriptions({JWT, namespace}), - accountInfo: _getBillingAccount({JWT, namespace}), - billingInfo: _getBillingInfo({JWT, namespace}) - }, function(err, results){ - let { userPlan, accountInfo, billingInfo } = results; - actionContext.dispatch('RECEIVE_CLOUD_BILLING_INFO', { - billingInfo: billingInfo, - accountInfo: accountInfo, - currentPlan: userPlan - }); - let values = _.merge({}, billingInfo, { - account_first: accountInfo.first_name, - account_last: accountInfo.last_name, - company_name: accountInfo.company_name, - email: accountInfo.email - }); - // TODO: Need to differentiate btw billingInfo/accountInfo first/last names - actionContext.dispatch('ENTERPRISE_PAID_POPULATE_FORM', values); - return done(); - }); -} diff --git a/app/scripts/actions/common/onChangeUtil.js b/app/scripts/actions/common/onChangeUtil.js deleted file mode 100644 index 5672dd0bac..0000000000 --- a/app/scripts/actions/common/onChangeUtil.js +++ /dev/null @@ -1,48 +0,0 @@ -'use strict'; - -import updateFormField from './updateFormField'; - -/** - * This function is a generic `onChange` Handler. Typical use is as follows: - * - * ``` - * import onChange from 'this/file/here'; - * - * createClass({ - * _onChange: onChange({ storePrefix: 'ENTERPRISE_TRIAL' }), - * render() { - * return ( - * - * ) - * } - * }); - * ``` - * - * `function setComponentOnChangeHandler` is the one that is `bind`ed. - * - * storePrefix is `ENTERPRISE_TRIAL` in the stores handlers object: - * - * ``` - * handlers: { - * ENTERPRISE_TRIAL_CLEAR_FORM: '_clearForm', - * ENTERPRISE_TRIAL_UPDATE_FIELD_WITH_VALUE: '_updateFieldWithValue', - * ENTERPRISE_TRIAL_ATTEMPT_START: '_enterpriseTrialAttemptStart', - * ENTERPRISE_TRIAL_BAD_REQUEST: '_badRequest', - * ENTERPRISE_TRIAL_SUCCESS: '_enterpriseTrialSuccess' - * } - * ``` - * - * e is the onChange event from the form field. - */ - -export default function({ storePrefix }) { - return function setComponentOnChangeHandler(fieldKey) { - return (e) => { - this.context.executeAction(updateFormField({ storePrefix }), { - fieldKey, - fieldValue: e.target.value - }); - }; - }; -} - diff --git a/app/scripts/actions/common/updateFormField.js b/app/scripts/actions/common/updateFormField.js deleted file mode 100644 index 69eb40e138..0000000000 --- a/app/scripts/actions/common/updateFormField.js +++ /dev/null @@ -1,50 +0,0 @@ -'use strict'; - -/** - * This function dispatches an event that updates a form backed by a form store. - * @param {string} storePrefix - the prefix for the form store events. This - * scopes the event to a particular store. - * - * The storePrefix usually takes the form of a shortened version of the store's - * name. In the case of the `EnterpriseTrialFormStore`, given handlers as such: - * - * ``` - * handlers: { - * ENTERPRISE_TRIAL_UPDATE_FIELD_WITH_VALUE: 'updateFormField' - * } - * ``` - * - * The store prefix for the preceeding example is `ENTERPRISE_TRIAL`. - * - * --- - * - * Usage of this module in a component might look like: - * - * ``` - * import updateFormField from 'wherever'; - * - * - * var Whatever = createClass({ - * _onChange(fieldKey) { - * return (e) => { - * this.context.executeAction(updateFormField({ - * storePrefix: 'ENTERPRISE_TRIAL' - * }), { - * fieldKey, - * fieldValue: e.target.value - * }); - * } - * }, - * render() { - * return ( - * - * ) - * } - * }); - */ -export default function({storePrefix}){ - return (actionContext, { fieldKey, fieldValue}) => { - actionContext.dispatch(`${storePrefix}_UPDATE_FIELD_WITH_VALUE`, { fieldKey, fieldValue }); - }; -} - diff --git a/app/scripts/actions/common/validateBillingInfo.js b/app/scripts/actions/common/validateBillingInfo.js deleted file mode 100644 index 070f6eed95..0000000000 --- a/app/scripts/actions/common/validateBillingInfo.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -export default function({storePrefix}){ - return (actionContext, fieldErrors) => { - actionContext.dispatch(`${storePrefix}_ERRORS`, fieldErrors); - }; -} diff --git a/app/scripts/actions/convertToOrganization.js b/app/scripts/actions/convertToOrganization.js deleted file mode 100644 index 85a4ed4af5..0000000000 --- a/app/scripts/actions/convertToOrganization.js +++ /dev/null @@ -1,33 +0,0 @@ -'use strict'; - -import { Users } from 'hub-js-sdk'; -var debug = require('debug')('hub:actions:convertToOrganization'); - -module.exports = function(actionContext, {jwt, username, newOwner}, done) { - Users.convertToOrganization(jwt, username, newOwner, function(err, res) { - if (err) { - debug('error', err); - if (res.badRequest){ - let message; - if (res.body) { - message = res.body; - } else { - try { - message = JSON.parse(res.text); - } catch(e) { - message = { - error: 'Your account could not be converted. Make sure you are not a member of another group and that the new owner username exists' - }; - } - } - actionContext.dispatch('CONVERT_TO_ORG_BAD_REQUEST', message); - done(); - } else { - done(); - } - } else { - actionContext.history.push('/login/'); - actionContext.dispatch('LOGOUT', null); - } - }); -}; diff --git a/app/scripts/actions/createAutobuild.js b/app/scripts/actions/createAutobuild.js deleted file mode 100644 index 4daa9ee69d..0000000000 --- a/app/scripts/actions/createAutobuild.js +++ /dev/null @@ -1,97 +0,0 @@ -'use strict'; -import { Autobuilds } from 'hub-js-sdk'; -const getRepository = require('hub-js-sdk').Repositories.getRepo; -import async from 'async'; -import has from 'lodash/object/has'; -import omit from 'lodash/object/omit'; -const debug = require('debug')('hub:actions:createAutobuild'); - -/** - * - * @param actionContext - * @param jwt - * @param autobuildConfig - * {name, namespace, description, active, is_automated, - * provider, is_private, dockerfileLocation, sourceName, sourceType} - */ -export default function(actionContext, {JWT, autobuildConfig}) { - /** - * CreateAutoBuildSerializer { - * vcs_repo_name (string), - * provider (choice) = ['github' or 'bitbucket'], - * dockerhub_repo_name (string), - * is_private (boolean), - * build_tags (array[string]) - * description? - * } - * @param cb - * @private - */ - var _createAutobuild = function(cb) { - var bTags = autobuildConfig.tags; - for (var i = 0; i < bTags.length; ++i) { - bTags[i] = omit(bTags[i], 'id'); - } - var ab = { - name: autobuildConfig.name, - namespace: autobuildConfig.namespace, - description: autobuildConfig.description, - vcs_repo_name: autobuildConfig.build_name, - provider: autobuildConfig.provider, - dockerhub_repo_name: autobuildConfig.namespace + '/' + autobuildConfig.name, - is_private: autobuildConfig.is_private, - active: autobuildConfig.active, - build_tags: bTags - }; - Autobuilds.createAutomatedBuild(JWT, ab, function(err, res) { - if (err) { - debug('createAutomatedBuild error', err); - if (err.response.badRequest) { - //Check fields and set a better response for fields - const { detail } = err.response.body; - if(detail) { - actionContext.dispatch('AUTOBUILD_BAD_REQUEST', detail); - } - } else if (err.response.unauthorized) { - actionContext.dispatch('AUTOBUILD_UNAUTHORIZED', err); - } else if (err.response.serverError) { - actionContext.dispatch('AUTOBUILD_ERROR', err); - } - cb(err); - } else if (res.body) { - var repoUrl = res.body.docker_url; - actionContext.dispatch('AUTOBUILD_SUCCESS'); - cb(null, repoUrl); - } - }); - }; - - /** - * - * @param repoUrl something like arunan/d3 - * @param cb - * @private - */ - var _getRepository = function(repoUrl, cb) { - getRepository(JWT, repoUrl, function(err, res) { - if (err) { - debug('getRepository error', err); - actionContext.dispatch('GET_REPOSITORY_ERROR'); - cb(err); - } else if (res.body) { - cb(null, res.body); - } - }); - }; - - actionContext.dispatch('ATTEMPTING_AUTOBUILD_CREATION'); - async.waterfall([ - _createAutobuild, - _getRepository - ], function(err, result) { - if (!err) { - actionContext.dispatch('RECEIVE_REPOSITORY', result); - } - }); - -} diff --git a/app/scripts/actions/createNewLicenseProduction.js b/app/scripts/actions/createNewLicenseProduction.js deleted file mode 100644 index 4638e58142..0000000000 --- a/app/scripts/actions/createNewLicenseProduction.js +++ /dev/null @@ -1,82 +0,0 @@ -'use strict'; - -import { Billing } from 'hub-js-sdk'; -const debug = require('debug')('hub:actions:createNewLicenseProduction'); - -export default function(actionContext, { - address1, - address2, - city, - country, - cvv, - first_name, - JWT, - last_name, - month, - number, - package_name, - partnervalue, - postal_code, - state, - username, - year -}, done) { - actionContext.dispatch('ENTERPRISE_PAID_ATTEMPT_START'); - try { - /** - * This will only run where window is defined. ie: the browser - * It throws an exception in node - */ - window.recurly.configure(process.env.RECURLY_PUBLIC_KEY); - } catch(e) { - debug('error', e); - } - - var recurlyData = { - first_name, - last_name, - month, - year, - cvv, - number, - address1, - address2, - city, - country, - postal_code, - state - }; - - window.recurly.token(recurlyData, function(recurlyErr, token) { - if (recurlyErr) { - debug('recurly error', recurlyErr.fields); - actionContext.dispatch('ENTERPRISE_PAID_GET_RECURLY_ERROR', recurlyErr.fields); - done(); - } else { - debug('creating License'); - Billing.createLicense(JWT, { - username, - package: package_name, - payment_token: token.id, - first_name, - last_name, - postal_code, - partner_value: partnervalue - }, (err, results) => { - if(err) { - if(err.response.badRequest) { - const { detail } = err.response.body; - if(detail) { - actionContext.dispatch('ENTERPRISE_PAID_BAD_REQUEST', detail); - } - } else { - actionContext.dispatch('ENTERPRISE_PAID_API_ERROR'); - } - } else { - actionContext.dispatch('ENTERPRISE_PAID_CLEAR_FORM'); - actionContext.history.push('/account/licenses/'); - } - }); - } - }); -} diff --git a/app/scripts/actions/createNewLicenseTrial.js b/app/scripts/actions/createNewLicenseTrial.js deleted file mode 100644 index 09abbb3360..0000000000 --- a/app/scripts/actions/createNewLicenseTrial.js +++ /dev/null @@ -1,53 +0,0 @@ -'use strict'; - -import { Billing } from 'hub-js-sdk'; -const debug = require('debug')('hub:actions:createNewLicenseTrial'); - -export default function(actionContext, { - JWT, - companyName, - country, - email, - firstName, - jobFunction, - lastName, - namespace, - packageName, - phoneNumber, - state -}) { - actionContext.dispatch('ENTERPRISE_TRIAL_ATTEMPT_START'); - const licenseData = { - company_name: companyName, - country, - email, - first_name: firstName, - job_function: jobFunction, - last_name: lastName, - package: packageName, - phone_number: phoneNumber, - username: namespace - }; - - // state is an optional field - if(state) { - licenseData.state = state; - } - - Billing.createLicense(JWT, licenseData, (err, results) => { - if(err) { - debug('error', err); - if(err.response.badRequest) { - const { detail } = err.response.body; - if(detail) { - actionContext.dispatch('ENTERPRISE_TRIAL_BAD_REQUEST', detail); - } - } else { - actionContext.dispatch('ENTERPRISE_TRIAL_FACEPALM'); - } - } else { - actionContext.dispatch('ENTERPRISE_TRIAL_SUCCESS'); - actionContext.history.push(`/enterprise/trial/success/?namespace=${namespace}&step=1`); - } - }); -} diff --git a/app/scripts/actions/createOrgTeam.js b/app/scripts/actions/createOrgTeam.js deleted file mode 100644 index a5371050ff..0000000000 --- a/app/scripts/actions/createOrgTeam.js +++ /dev/null @@ -1,76 +0,0 @@ -'use strict'; -import { Orgs } from 'hub-js-sdk'; -import async from 'async'; -const debug = require('debug')('hub:actions:createOrgTeam'); - -module.exports = function(actionContext, {jwt, orgName, team}) { - - var _createTeam = function(cb) { - Orgs.createTeam(jwt, orgName, team, function(err, res) { - if (err) { - debug('createTeam error', err); - cb(err); - var errRes = err.response; - if (errRes.badRequest) { - actionContext.dispatch('TEAM_BAD_REQUEST', err); - } else if (errRes.unauthorized) { - actionContext.dispatch('TEAM_UNAUTHORIZED', err); - } else { - actionContext.dispatch('TEAM_ERROR', err); - } - } else { - if (res.body) { - //send team name to get members for the team - actionContext.dispatch('CREATE_ORG_TEAM', res.body); - actionContext.dispatch('RECEIVE_DASHBOARD_ORG_TEAM', res.body); - cb(null, res.body.name); - } - } - }); - }; - - var _getMembers = function(teamName, cb) { - Orgs.getMembers(jwt, orgName, teamName, function(err, res) { - if (err) { - debug('getMembers error', err); - cb(err); - } else { - actionContext.dispatch('RECEIVE_DASHBOARD_TEAM_MEMBERS', res.body); - cb(null, 'done'); - } - }); - }; - - var _createTeamWrapper = function(cb) { - async.waterfall([ - _createTeam, - _getMembers - ], function(err, res) { - cb(null, res); - } - ); - }; - - var _getTeamsForOrg = function(cb) { - Orgs.getTeams(jwt, orgName, function(err, res) { - if (err) { - debug('getTeams error', err); - cb(err); - } else { - if (res.body) { - cb(null, res.body); - } - } - }); - }; - - async.series([ - _createTeamWrapper, - _getTeamsForOrg - ], function(err, results) { - if (results[0] && results[1]) { - actionContext.dispatch('RECEIVE_DASHBOARD_ORG_TEAMS', results[1]); - actionContext.history.push(`/u/${orgName}/dashboard/teams/?team=${team.name}`); - } - }); -}; diff --git a/app/scripts/actions/createOrganization.js b/app/scripts/actions/createOrganization.js deleted file mode 100644 index 4e2e9d49bd..0000000000 --- a/app/scripts/actions/createOrganization.js +++ /dev/null @@ -1,65 +0,0 @@ -'use strict'; - -var debug = require('debug')('hub:actions:createOrganization'); -import async from 'async'; -import { Orgs, Users } from 'hub-js-sdk'; -//Organization Object -/* - { - id (string), - orgname (regex), - full_name (string), - location (string): Your Location on the world, - company (string): Your organization's name, - profile_url (url): Your place on the web, - gravatar_email (email): This address will define which picture of you is shown, - is_active (boolean): Designates whether user is active. Unselect this instead of deleting accounts., - date_joined (datetime), - gravatar_url (string) - } - */ -export default function(actionContext, {jwt, organization}) { - - var _createOrg = function(cb) { - Orgs.createOrg(jwt, organization, function(err, res) { - if (err) { - if(res && res.badRequest) { - debug('createOrg error', err); - actionContext.dispatch('ADD_ORG_BAD_REQUEST', res.body); - cb(err, res); - } else { - actionContext.dispatch('ADD_ORG_FACEPALM'); - cb(err, res); - } - } else { - cb(null, res.body); - } - }); - }; - - //Get orgs for user - var _getOrgsForUser = function(cb) { - Users.getOrgsForUser(jwt, function(err, res) { - if (err) { - debug('getOrgsForUser error', err); - cb(err, {}); - } else { - actionContext.dispatch('CURRENT_USER_ORGS', res.body.results); - cb(null, res.body.results); - } - }); - return {}; - }; - - async.series([ - _createOrg, - _getOrgsForUser - ], function (err, results) { - if(err) { - debug('final callback error', err); - } else { - actionContext.dispatch('CREATED_ORGANIZATION', {newOrg: results[0], userOrgs: results[1]}); - actionContext.history.push(`/u/${organization.orgname}/dashboard/teams/`); - } - }); -} diff --git a/app/scripts/actions/createRepository.js b/app/scripts/actions/createRepository.js deleted file mode 100644 index f2463a93dc..0000000000 --- a/app/scripts/actions/createRepository.js +++ /dev/null @@ -1,30 +0,0 @@ -/* @flow */ -'use strict'; - -var createRepo = require('hub-js-sdk').Repositories.createRepository; -var debug: Function = require('debug')('hub:actions:createRepository'); - -var createRepository = function(actionContext: {dispatch: Function}, - {jwt, repository}: {jwt: string; repository: any}) { - createRepo(jwt, repository, (err, res) => { - if (err) { - - if(res && res.badRequest) { - actionContext.dispatch('CREATE_REPO_BAD_REQUEST', res.body); - } else { - actionContext.dispatch('CREATE_REPO_ERROR', err); - } - - } else { - - if (res && res.ok) { - actionContext.dispatch('RECEIVE_REPOSITORY', res.body); - actionContext.dispatch('CREATE_REPO_CLEAR_FORM'); - actionContext.history.push(`/r/${repository.namespace}/${repository.name}/`); - } - - } - }); -}; - -module.exports = createRepository; diff --git a/app/scripts/actions/createSubscription.js b/app/scripts/actions/createSubscription.js deleted file mode 100644 index 1c817d3ab3..0000000000 --- a/app/scripts/actions/createSubscription.js +++ /dev/null @@ -1,374 +0,0 @@ -'use strict'; -const request = require('superagent'); -import { Billing } from 'hub-js-sdk'; -/*global UpdateBillingInfoPayload */ -import map from 'lodash/collection/map'; -import has from 'lodash/object/has'; -import merge from 'lodash/object/merge'; -import isString from 'lodash/lang/isString'; -import async from 'async'; -var debug = require('debug')('hub:actions:createBillingSubscription'); - -import _encodeForm from '../components/utils/encodeForm.js'; -import { - ACCOUNT, - BILLING, - BILLFORWARD_ACCOUNT_ID, - STRIPE_URL, - STRIPE_STAGE_TOKEN, - STRIPE_PROD_TOKEN, - BF_STAGE_URL, - BF_PROD_URL, - BF_STAGE_TOKEN, - BF_PROD_TOKEN, - v4BillingProfile -} from 'stores/common/Constants.js'; - -const handleResponse = ({ callback, dispatch, type }) => (err, res) => { - if (err) { - let message = 'There was an error creating your subscription. Please check your information and try again.'; - if (res && res.body) { - message = isString(res.body.detail) ? res.body.detail : res.body.message; - } - dispatch('BILLING_SUBMIT_ERROR', message); - callback(err, res); - } else if (res.ok) { - if (type === ACCOUNT) { - dispatch('BILLING_ACCOUNT_EXISTS'); - } else if (type === BILLING) { - dispatch('BILLING_INFO_EXISTS'); - } - const billforward_id = res.header[BILLFORWARD_ACCOUNT_ID]; - callback(null, { billforward_id }); - } -}; - -//-------------------------------------------------------------------------- -// CREATE A BILLING PAYMENT METHOD ON BILLFORWAD WITH STRIPE -//-------------------------------------------------------------------------- -/* - NOTE: Stripe's api only accepts x-www-form-urlencoded data - NOTE: 'billforwardCreatePayment' is chained to this function and requires - `billforward-id`. The `billforward-id` is being passed through to the - create payment function via the META here. -*/ -function _createCardToken({ - cvc, - exp_month, - exp_year, - name_first, - name_last, - number -}, cb) { - const stripeToken = process.env.ENV === 'production' ? - STRIPE_PROD_TOKEN : STRIPE_STAGE_TOKEN; - const card = { - name: `${name_first} ${name_last}`, - cvc, - number, - exp_month, - exp_year - }; - const encoded = _encodeForm({ card }); - request.post(STRIPE_URL) - .accept('application/json') - .type('application/x-www-form-urlencoded') - .set('Authorization', 'Bearer ' + stripeToken) - .send(encoded) - .end(cb); -} - -/* - NOTE: This is the call to billforward that actually adds a payment method - to a user's billing profile. - This call requires a billforward-id (accountID) which is DIFFERENT than the - docker_id - Hence why 'billingCreatePaymentMethod' is NOT being wrapped by - the getAccountFromNamespace decorator. -*/ -function _billforwardAddPaymentMethod({ - '@type': type, - accountID, - cardID, - defaultPaymentMethod, - gateway, - stripeToken -}, cb) { - const billforwardUrl = process.env.ENV === 'production' ? - BF_PROD_URL : BF_STAGE_URL; - const billforwardToken = process.env.ENV === 'production' ? - BF_PROD_TOKEN : BF_STAGE_TOKEN; - - request.post(billforwardUrl) - .accept('application/json') - .type('application/json') - .set('Authorization', 'Bearer ' + billforwardToken) - .send({ - '@type': type, - accountID, - cardID, - defaultPaymentMethod, - gateway, - stripeToken - }) - .end(cb); -} - -function billingStripeCreatePaymentMethod(dispatch, { - billforward_id, - cvc, - exp_month, - exp_year, - name_first, - name_last, - number -}, cb) { - const cardData = { - cvc, - exp_month, - exp_year, - name_first, - name_last, - number - }; - /* - NOTE: - Creating a payment method requires 2 parts - 1 - Generating a token from Stripe's api - 2 - Sending generated token to Billforward's api to attach payment method to - a relevant billing profile. - */ - _createCardToken(cardData, (stripeErr, stripeRes) => { - if (!stripeRes.ok) { - let message = 'There was an error submitting your card information. Please check your information and try again.'; - if (stripeRes.error && stripeRes.error.message) { - message = stripeRes.error.message; - } - dispatch('BILLING_SUBMIT_ERROR', message); - cb(message); - } else { - const tokenObject = stripeRes && stripeRes.body; - const stripeToken = tokenObject.id; - const cardID = tokenObject.card.id; - const accountID = billforward_id; - const bfData = { - '@type': 'StripeAuthCaptureRequest', - accountID, - cardID, - defaultPaymentMethod: true, - gateway: 'Stripe', - stripeToken - }; - _billforwardAddPaymentMethod(bfData, handleResponse({ callback: cb, dispatch, type: BILLING })); - } - }); -} - -//-------------------------------------------------------------------------- -// SAVE ADDRESS INFORMATION IN BILLFORWARD -//-------------------------------------------------------------------------- -const updateV4BillingProfile = ({ JWT, profileData, docker_id }, cb) => { - const v4BillingAPI = v4BillingProfile(docker_id); - request - .patch(v4BillingAPI) - .accept('application/json') - .type('application/json') - .set('Authorization', 'Bearer ' + JWT) - .send(profileData) - .end(cb); -}; - -//-------------------------------------------------------------------------- -// CREATE NEW BILLING ACCOUNT/PROFILE & SUBSCRIPTION -//-------------------------------------------------------------------------- -function createSubscription(actionContext, { - JWT, - user, - accountInfo, - billingInfo, - card, - isNewBillingAccount, - billforwardId: existingBfId, - plan_code, - package_code -}, done) { - actionContext.dispatch('BILLING_SUBMIT_START'); - const { - first_name, - last_name, - address1, - address2, - country, - state, - zip, - city - } = billingInfo; - const { - number, - cvv, - month, - year, - last_four, - type, - coupon_code, - coupon - } = card; - - let isOrg = false; - let username = ''; - if (has(user, 'username')) { - username = user.username; - } else if (has(user, 'orgname')) { - username = user.orgname; - isOrg = true; - } - - var subscriptionData = { - first_name, - last_name, - email: accountInfo.email, - username, - plan: plan_code, - package: package_code - }; - if (coupon_code) { - // coupon code is an optional field - subscriptionData.coupon_code = coupon_code; - } - - async.waterfall([ - function(callback) { // create billing profile - const account = merge({}, accountInfo, {username}); - /* - NOTE: - Can only get to this action IF - 1) You don't have a billing profile account (Create the billing account) - 2) You don't have any billing payment information - but you have a billing profile account (Update the account) - */ - if (isNewBillingAccount) { - Billing.createBillingAccount(JWT, account, handleResponse({callback, dispatch: actionContext.dispatch, type: ACCOUNT})); - // on success - callback(null, { billforward_id }) - } else { - Billing.updateBillingAccount(JWT, username, account, handleResponse({callback, dispatch: actionContext.dispatch, type: ACCOUNT})); - } - }, - function({ billforward_id }, callback) { - const bfId = billforward_id || existingBfId; - if (bfId) { - // NOTE: Save billing address information - const profileData = { - first_name, - last_name, - addresses: [ - { - address_line_1: address1, - address_line_2: address2, - city, - province: state, - country, - post_code: zip, - primary_address: true - } - ] - }; - updateV4BillingProfile({ - JWT, - profileData, - docker_id: user.id - }, (err, res) => { - if (err) { - let message = 'There was an error saving your address information. Please check your information and try again.'; - if (res && res.body) { - message = isString(res.body.detail) ? res.body.detail : res.body.message; - } - actionContext.dispatch('BILLING_SUBMIT_ERROR', message); - callback(null); - return; - } - callback(null, {...res.body, billforward_id }); - }); - return; - } - // NOTE: Unecessary for non-migrated accounts - Creation of billingprofile will update the account data - callback(null, { billforward_id }); - }, - function({ billforward_id }, callback) { - const bfId = billforward_id || existingBfId; - if (bfId) { - // NOTE: If we have a billforward id - create payment Method via stripe - billingStripeCreatePaymentMethod(actionContext.dispatch, { - billforward_id: bfId, - cvc: cvv, - exp_month: month, - exp_year: year, - name_first: first_name, - name_last: last_name, - number - }, callback); - return; - } - // NOTE: If we do NOT have a billforward id - tokenize via recurly - const recurlyData = { - first_name, - last_name, - address1, - address2, - country, - state, - zip, - city, - number, - cvv, - month, - year, - coupon_code - }; - try { - /** - * This will only run where window is defined. ie: the browser - * It throws an exception in node - */ - window.recurly.configure(process.env.RECURLY_PUBLIC_KEY); - } catch(e) { - debug('error', e); - } - window.recurly.token(recurlyData, function(recurlyErr, token) { - if (recurlyErr) { - debug('recurly token error', recurlyErr.message); - actionContext.dispatch('GET_RECURLY_ERROR', recurlyErr); - callback(recurlyErr); - return; - } - callback(null, { recurlyToken: token.id }); - }); - }, - function({ recurlyToken }, callback) { - // NOTE: append the recurly token to the subscriptionData object; - subscriptionData.payment_token = recurlyToken; - /* - NOTE: Creating billing subscription will either - A) Use default card if billing account is migrated and we get a billforward id - B) Subscription Data will have a recurly token if no billforward id - IF Billing Info already exists: - - Stripe: Adds a new default card - - Recurly: we're posting with the recurly token which will update it - */ - Billing.createBillingSubscription(JWT, subscriptionData, handleResponse({callback, dispatch: actionContext.dispatch, type: BILLING})); - } - ], - function(err, res) { - if (err) { - debug(err); - done(); - } else { - if (isOrg) { - actionContext.history.push(`/u/${username}/dashboard/billing/`); - } else { - actionContext.history.push('/account/billing-plans/'); - } - actionContext.dispatch('BILLING_SUBMIT_SUCCESS'); - done(); - } - }); -} - -module.exports = createSubscription; diff --git a/app/scripts/actions/createTeamMembers.js b/app/scripts/actions/createTeamMembers.js deleted file mode 100644 index eee9225bad..0000000000 --- a/app/scripts/actions/createTeamMembers.js +++ /dev/null @@ -1,66 +0,0 @@ -'use strict'; - -var debug = require('debug')('hub:actions:createTeamMembers'); -import async from 'async'; -import { Orgs } from 'hub-js-sdk'; - -export default function(actionContext, {jwt, orgname, teamname, members}) { - - var _createMember = function(cb) { - var _makeMemberFuncArray = function(member) { - return function() { - // member.username can be either a valid email or a username - Orgs.createMember(jwt, orgname, teamname, member.username, function(err, res) { - if (err) { - debug('createMember error', err); - if (res.badRequest) { - actionContext.dispatch('TEAM_MEMBER_BAD_REQUEST', err); - } else if (res.unauthorized) { - actionContext.dispatch('TEAM_MEMBER_UNAUTHORIZED', err); - } else { - actionContext.dispatch('TEAM_MEMBER_ERROR', err); - } - } else { - if (res.ok) { - actionContext.dispatch('ORG_TEAM_CLEAR_ERROR_STATES'); - cb(null, res.body); - } - } - }); - }; - }; - var funcArray = []; - for(var i = 0; i < members.length; ++i) { - funcArray.push(_makeMemberFuncArray(members[i])); - } - async.parallel(funcArray, function(err, results) { - if (err) { - cb(err); - } else { - cb(null, results); - } - }); - }; - - //Get members for team - var _getMembersForTeam = function(cb) { - Orgs.getMembers(jwt, orgname, teamname, function(err, res) { - if (err) { - debug('getMembers error', err); - cb(err, {}); - } else { - actionContext.dispatch('RECEIVE_DASHBOARD_TEAM_MEMBERS', res.body); - cb(null, res.body.results); - } - }); - }; - - async.series([ - _createMember, - _getMembersForTeam - ], function (err, results) { - if(err) { - debug('final callback error', err); - } - }); -} diff --git a/app/scripts/actions/createWebhook.js b/app/scripts/actions/createWebhook.js deleted file mode 100644 index 0915fe4f11..0000000000 --- a/app/scripts/actions/createWebhook.js +++ /dev/null @@ -1,27 +0,0 @@ -'use strict'; -import async from 'async'; -import request from 'superagent'; -const debug = require('debug')('createWebhook'); - -// TODO: REMOVE. This is deprecated in favor of AddPipeline -module.exports = function(actionContext, { JWT, namespace, name, webhookName }) { - - request.post(`${process.env.REGISTRY_API_BASE_URL}/v2/repositories/${namespace}/${name}/webhooks/`) - .accept('application/json') - .set('Authorization', `JWT ${JWT}`) - .send({ - name: webhookName - }) - .end((err, results) => { - if(err) { - debug(err); - if(err.response.badRequest) { - debug('badrequest'); - } else { - debug('facepalm'); - } - } else { - actionContext.history.push(`/r/${namespace}/${name}/~/settings/webhooks/`); - } - }); -}; diff --git a/app/scripts/actions/delCollaborator.js b/app/scripts/actions/delCollaborator.js deleted file mode 100644 index 3ffce1abb2..0000000000 --- a/app/scripts/actions/delCollaborator.js +++ /dev/null @@ -1,24 +0,0 @@ -'use strict'; -import { - Repositories as R - } from 'hub-js-sdk'; - -export default function delCollaborator(actionContext, { JWT, namespace, name, username }, done) { - actionContext.dispatch('DEL_COLLABORATORS_SET_LOADING', username); - R.delCollaborator(JWT, { namespace, name, username }, (err, res) => { - if(err) { - actionContext.dispatch('DEL_COLLABORATORS_SET_ERROR', username); - } else { - actionContext.dispatch('DEL_COLLABORATORS_SET_SUCCESS', username); - R.getCollaboratorsForRepo(JWT, `${namespace}/${name}`, (getErr, getRes) => { - if(getErr) { - // 'Org repositories do not have collaborators.' - actionContext.dispatch('COLLAB_RECEIVE_COLLABORATORS', {}); - } else { - actionContext.dispatch('COLLAB_RECEIVE_COLLABORATORS', getRes.body); - } - }); - } - done(); - }); -} diff --git a/app/scripts/actions/delTeamCollaborator.js b/app/scripts/actions/delTeamCollaborator.js deleted file mode 100644 index cda330a123..0000000000 --- a/app/scripts/actions/delTeamCollaborator.js +++ /dev/null @@ -1,24 +0,0 @@ -'use strict'; -import { - Repositories as R - } from 'hub-js-sdk'; - -export default function delCollaborator(actionContext, { JWT, namespace, name, group_id }, done) { - actionContext.dispatch('DEL_COLLABORATORS_SET_LOADING', group_id); - R.delTeamCollaborator(JWT, { namespace, name, group_id }, (err, res) => { - if(err) { - actionContext.dispatch('DEL_COLLABORATORS_SET_ERROR', group_id); - } else { - actionContext.dispatch('DEL_COLLABORATORS_SET_SUCCESS', group_id); - R.getTeamCollaboratorsForRepo(JWT, `${namespace}/${name}`, (getErr, getRes) => { - if (getErr) { - // 'User repository does not have any teams yet' - actionContext.dispatch('COLLAB_RECEIVE_TEAMS', {}); - } else { - actionContext.dispatch('COLLAB_RECEIVE_TEAMS', getRes.body); - } - }); - } - done(); - }); -} diff --git a/app/scripts/actions/deleteAutoBuildPushTriggerItem.js b/app/scripts/actions/deleteAutoBuildPushTriggerItem.js deleted file mode 100644 index e3ff3c61bb..0000000000 --- a/app/scripts/actions/deleteAutoBuildPushTriggerItem.js +++ /dev/null @@ -1,11 +0,0 @@ -'use strict'; - -var debug = require('debug')('hub:actions:deleteAutoBuildPushTriggerItem'); - -export default function(actionContext, {isNew, index}) { - if (isNew) { - actionContext.dispatch('DELETE_AUTOBUILD_NEW_TAG_ITEM', index); - } else { - actionContext.dispatch('DELETE_AUTOBUILD_PUSH_TRIGGER_ITEM', index); - } -} diff --git a/app/scripts/actions/deleteEmail.js b/app/scripts/actions/deleteEmail.js deleted file mode 100644 index aa8db4b2f0..0000000000 --- a/app/scripts/actions/deleteEmail.js +++ /dev/null @@ -1,38 +0,0 @@ -'use strict'; - -import sortByOrder from 'lodash/collection/sortByOrder'; -import { series, each } from 'async'; -import { - Emails - } from 'hub-js-sdk'; -var debug = require('debug')('hub:actions:deleteEmail'); - -function updateEmailSettings({ dispatch }, - {JWT, delEmailID, username}, - done) { - dispatch('START_SAVE_ACTION'); - Emails.deleteEmailByID(JWT, - delEmailID, - (err, res) => { - if (err) { - return debug('deleteEmailByID error', err); - } - Emails.getEmailsForUser(JWT, username, function(emailErr, emailRes){ - if (emailErr) { - debug('getEmailsForUser error', emailErr); - dispatch('FINISH_SAVE_ACTION'); - return done(); - } - var emails = emailRes.body.results; - var sortedEmails = sortByOrder(emails, - ['primary', 'verified'], - [false, false]); - dispatch('RECEIVE_EMAILS', { - emails: sortedEmails - }); - dispatch('FINISH_SAVE_ACTION'); - }); - }); -} - -module.exports = updateEmailSettings; diff --git a/app/scripts/actions/deleteEmailNotifs.js b/app/scripts/actions/deleteEmailNotifs.js deleted file mode 100644 index 3cae021514..0000000000 --- a/app/scripts/actions/deleteEmailNotifs.js +++ /dev/null @@ -1,46 +0,0 @@ -'use strict'; - -var debug = require('debug')('hub:actions:deleteEmailNotifs'); -import async from 'async'; - -import { Notifications } from 'hub-js-sdk'; - -var deleteEmailNotifs = function(actionContext, {jwt, notificationID}) { - var _delNotificationSettings = function(cb) { - Notifications.deleteNotificationSubscription(jwt, notificationID, function(err, res) { - if (err) { - debug('deleteNotificationSubscription error', err); - cb(err); - } else if (res.ok) {//TODO:Weird that 204 no content is sent on success - return cb(null, res); - } - }); - }; - - var _getNotificationSettings = function(cb) { - //all good, do the next call to get the notifications - Notifications.getNotificationSubscriptions(jwt, function(err, res) { - if (err) { - debug('getNotificationSubscriptions error', err); - cb(err); - } else { - cb(null, res.body.results); - } - }); - }; - - async.series([ - _delNotificationSettings, - _getNotificationSettings - ], function (err, results) { - if (err) { - actionContext.dispatch('SAVE_NOTIFICATIONS_ERROR'); - debug('final callback error', err); - } else if (results[1]) { - actionContext.dispatch('SAVE_NOTIFICATIONS_SUCCESS'); - actionContext.dispatch('RECEIVE_NOTIFICATIONS', results[1]); - } - }); -}; - -module.exports = deleteEmailNotifs; diff --git a/app/scripts/actions/deletePipeline.js b/app/scripts/actions/deletePipeline.js deleted file mode 100644 index e04e8be1cb..0000000000 --- a/app/scripts/actions/deletePipeline.js +++ /dev/null @@ -1,25 +0,0 @@ -'use strict'; - -import request from 'superagent'; - -export default function deletePipeline({ - dispatch, history -}, { - jwt, namespace, name, slug -}, done) { - dispatch('DELETE_PIPELINE_ATTEMPTING'); - request.del(`${process.env.HUB_API_BASE_URL}/v2/repositories/${namespace}/${name}/webhook_pipeline/${slug}/`) - .set('Authorization', `JWT ${jwt}`) - .type('json') - .accept('json') - .end((err, res) => { - if(err) { - dispatch('DELETE_PIPELINE_FACEPALM'); - done(); - } else { - dispatch('DELETE_PIPELINE_SUCCESS'); - history.push(`/r/${namespace}/${name}/~/settings/webhooks/`); - done(); - } - }); -} diff --git a/app/scripts/actions/deleteRepo.js b/app/scripts/actions/deleteRepo.js deleted file mode 100644 index 7f44b65c9e..0000000000 --- a/app/scripts/actions/deleteRepo.js +++ /dev/null @@ -1,22 +0,0 @@ -'use strict'; - -import { Repositories as Repos } from 'hub-js-sdk'; -const debug = require('debug')('hub:actions:deleteRepo'); - -export default function(actionContext, {jwt, repoShortName}) { - actionContext.dispatch('DELETE_REPO_ATTEMPT_START'); - Repos.deleteRepository(jwt, repoShortName, (err, res) => { - if (err) { - const { badRequest, body } = err.response; - if(badRequest) { - actionContext.dispatch('DELETE_REPO_BAD_REQUEST', body); - } else { - actionContext.dispatch('DELETE_REPO_ERROR', err); - } - } else { - if (res && res.ok) { - actionContext.history.push('/'); - } - } - }); -} diff --git a/app/scripts/actions/deleteRepoComment.js b/app/scripts/actions/deleteRepoComment.js deleted file mode 100644 index 14b6c5e39d..0000000000 --- a/app/scripts/actions/deleteRepoComment.js +++ /dev/null @@ -1,24 +0,0 @@ -'use strict'; - -var debug = require('debug')('hub:actions:deleteRepoComment'); - -import { Repositories } from 'hub-js-sdk'; - -var deleteRepoComment = function(actionContext, {jwt, repoShortName, commentid}) { - Repositories.deleteRepoComment(jwt, repoShortName, commentid, function(delErr, delRes) { - if (delErr) { - debug('deleteRepoComment error', delErr); - } else if (delRes.ok) { - Repositories.getCommentsForRepo(jwt, repoShortName, function(getErr, getRes) { - if (getErr) { - debug('getCommentsForRepo error', getErr); - } else { - actionContext.dispatch('RECEIVE_REPO_COMMENTS', getRes.body); - } - }); - } - }); - -}; - -module.exports = deleteRepoComment; diff --git a/app/scripts/actions/downloadInvoice.js b/app/scripts/actions/downloadInvoice.js deleted file mode 100644 index edbd33b746..0000000000 --- a/app/scripts/actions/downloadInvoice.js +++ /dev/null @@ -1,24 +0,0 @@ -'use strict'; -// Blob is a polyfill -require('vendor/Blob'); -import { saveAs } from 'vendor/FileSaver'; - -const debug = require('debug')('hub:actions:downloadInvoice'); - -module.exports = function(actionContext, { JWT, username, invoiceId }) { - const xhr = new XMLHttpRequest(); - xhr.open('GET', process.env.REGISTRY_API_BASE_URL + '/api/billing/v3/account/' + username + '/invoices/' + invoiceId + '/'); - xhr.setRequestHeader('Authorization', 'JWT ' + JWT); - xhr.responseType = 'blob'; - xhr.onload = function() { - if (xhr.status === 200) { - const blob = new Blob([xhr.response], { - type: 'application/pdf' - }); - saveAs(blob, 'docker_invoice_' + invoiceId + '.pdf'); - } else { - debug('error'); - } - }; - xhr.send(); -}; diff --git a/app/scripts/actions/downloadLicenseContent.js b/app/scripts/actions/downloadLicenseContent.js deleted file mode 100644 index fb823166d0..0000000000 --- a/app/scripts/actions/downloadLicenseContent.js +++ /dev/null @@ -1,31 +0,0 @@ -'use strict'; - -const debug = require('debug')('hub:actions:downloadLicenseContent'); -import { Billing } from 'hub-js-sdk'; -// Blob is a polyfill -require('vendor/Blob'); -import { saveAs } from 'vendor/FileSaver'; - -export default function downloadLicenseContent(actionContext, { jwt, namespace, keyId }) { - actionContext.dispatch('ATTEMPTING_LICENSE_DOWNLOAD_START'); - Billing.getLicenseDownloadContent(jwt, { keyId, namespace }, (err, res) => { - if (err) { - debug('error', err); - if(err.response.badRequest) { - const { detail } = err.response.body; - if(detail) { - actionContext.dispatch('DOWNLOAD_LICENSE_CONTENT_BAD_REQUEST', detail); - } - } else { - actionContext.dispatch('DOWNLOAD_LICENSE_CONTENT_FACEPALM'); - } - } else { - actionContext.dispatch('RECEIVE_LICENSE_DOWNLOAD_CONTENT'); - //perform download as result of clicking download button - const blob = new Blob([res.text], { - type: 'text/plain;charset=utf-8' - }); - saveAs(blob, `docker_subscription.lic`); - } - }); -} diff --git a/app/scripts/actions/enterpriseAttemptLogin.js b/app/scripts/actions/enterpriseAttemptLogin.js deleted file mode 100644 index f8bbaa055d..0000000000 --- a/app/scripts/actions/enterpriseAttemptLogin.js +++ /dev/null @@ -1,155 +0,0 @@ -'use strict'; - -import { parallel, waterfall } from 'async'; -import sortBy from 'lodash/collection/sortBy'; -import { Auth, - Repositories as Repos, - Billing - } from 'hub-js-sdk'; -var debug = require('debug')('hub:actions:enterpriseAttemptLogin'); -import { getActivityFeed } from 'hub-js-sdk/src/Hub/SDK/Notifications'; -import { getUser } from 'hub-js-sdk/src/Hub/SDK/JWT'; -import { - getNamespacesForUser -} from 'hub-js-sdk/src/Hub/SDK/Users'; -import { getToken } from 'hub-js-sdk/src/Hub/SDK/Auth'; -import request from 'superagent'; - -//Get orgs for user -function _getOrgsForCurrentUser({jwt, username, dispatch}) { - return function(user, cb) { - getNamespacesForUser(jwt, function(err, res) { - if (err) { - debug('getNamespacesForUser', err); - cb(null); - } else { - // brute force the namespace reception so we can use a single action for now - dispatch('ENTERPRISE_TRIAL_RECEIVE_ORGS', res.body.namespaces); - dispatch('ENTERPRISE_PAID_RECEIVE_ORGS', res.body.namespaces); - cb(null, user); - } - }); - }; -} - -function _getBillingPlans({jwt, dispatch}) { - return function(user, cb) { - Billing.getPlans(jwt, 'personal', (err, res) => { - if(err) { - debug('getPlans error', err); - cb(null); - } else { - let plansList = res.body; - let sortedPlans = sortBy(plansList, 'display_order'); - dispatch('RECEIVE_BILLING_PLANS', { - plansList: sortedPlans - }); - cb(null, user); - } - }); - }; -} -function _getBillingAccount({jwt, dispatch}) { - return function(user, cb) { - Billing.getBillingAccount(jwt, user.username, (err, res) => { - if(err) { - debug('no billing account connected'); - cb(err, {}); - } else { - dispatch('RECEIVE_BILLING_INFO', { - accountInfo: res.body - }); - cb(null, user); - } - }); - }; -} - -function _getBillingInfo({jwt, dispatch}) { - return (user, cb) => { - Billing.getBillingInfo(jwt, user.username, (err, res) => { - if(err) { - debug('no billing account connected'); - cb(err, {}); - } else { - dispatch('RECEIVE_BILLING_INFO', { - billingInfo: res.body - }); - cb(null, user); - } - }); - }; -} - - -function handleGetUserInfo({jwt, username, dispatch}, callback) { - waterfall([ - function(cb){ - getUser(jwt, function(err, res) { - if (err) { - cb(err, {}); - } else { - dispatch('RECEIVE_USER', res.body); //LOGIN USING JWT.getUser - cb(null, res.body); - } - }); - }, - _getOrgsForCurrentUser({jwt, username, dispatch}), - _getBillingPlans({jwt, dispatch}), - _getBillingAccount({jwt, dispatch}), - _getBillingInfo({jwt, dispatch}) //Waterfalling the user through each call. - ], function(err, user) { - callback(err, { user }); - }); -} - -module.exports = function({ dispatch }, - { username, password }, - done) { - dispatch('LOGIN_ATTEMPT_START'); - getToken(username, - password, - function(err, res) { - if (err) { - debug('getToken error', err); - if (res.unauthorized) { - if(res.body && res.body.detail) { - /** - * This can happen if the user has not verified their email - */ - dispatch('LOGIN_UNAUTHORIZED_DETAIL', res.body); - } else { - dispatch('LOGIN_UNAUTHORIZED'); - } - } else if (res.badRequest){ - try { - dispatch('LOGIN_BAD_REQUEST', JSON.parse(res.text)); - } catch (error) { - dispatch('LOGIN_ERROR'); - } - } else { - // unhandled login error - dispatch('LOGIN_ERROR'); - } - } else { - if (res.body.token) { - request.post('/attempt-login/') - .send({jwt: res.body.token}) - .end((cookieErr, cookieRes) => { - handleGetUserInfo({ - jwt: res.body.token, - username, - dispatch - }, function(userErr, userRes) { - /** - * CreateBillingSubscription requires having allPlans - * If loggedOut and JWT is populated first, it will attempt to populate form, BEFORE plans have been dispatched - */ - dispatch('RECEIVE_JWT', res.body.token); - dispatch('LOGIN_CLEAR'); - }); - }); - } - } - }); -}; diff --git a/app/scripts/actions/forgotPasswordSubmit.js b/app/scripts/actions/forgotPasswordSubmit.js deleted file mode 100644 index ae953cbe3a..0000000000 --- a/app/scripts/actions/forgotPasswordSubmit.js +++ /dev/null @@ -1,18 +0,0 @@ -/* @flow */ -'use strict'; -import { - Users - } from 'hub-js-sdk'; -const debug = require('debug')('hub:actions:forgotPasswordSubmit'); - -var forgotPasswordSubmit = function(actionContext:{ dispatch : Function }, { email }) { - Users.forgotPassword(email, function(err, res) { - if (err) { - debug('forgotPassword error', err); - } else { - actionContext.dispatch('FORGOT_PASSWORD_SENT', res.body); - } - }); -}; - -module.exports = forgotPasswordSubmit; diff --git a/app/scripts/actions/getAllReposForFiltering.js b/app/scripts/actions/getAllReposForFiltering.js deleted file mode 100644 index 84b6662d0c..0000000000 --- a/app/scripts/actions/getAllReposForFiltering.js +++ /dev/null @@ -1,40 +0,0 @@ -'use strict'; -var debug = require('debug')('hub:actions:getAllReposForFiltering'); -import async from 'async'; -import isArray from 'lodash/lang/isArray'; -import { - Repositories as Repos -} from 'hub-js-sdk'; - -export default function getAllReposForFiltering(actionContext, {jwt, user}) { - - actionContext.dispatch('DASHBOARD_REPOS_STORE_ATTEMPTING_GET_ALL_REPOS'); - var _getAllRepos = function (cb) { - Repos.getAllReposForUser(jwt, user, function (err, res) { - if (err) { - cb(err); - } else { - cb(null, isArray(res.body) && res.body.length); - } - }); - }; - - //Get repos for user or org - var _getReposForUserOrOrg = function (pageSize, cb) { - Repos.getReposForUser(jwt, user, function (err, res) { - if (err) { - actionContext.dispatch('ERROR_RECEIVING_REPOS', err); - cb(); - } else { - actionContext.dispatch('DASHBOARD_REPOS_STORE_RECEIVE_ALL_REPOS_SUCCESS', res.body); - cb(); - } - }, 1, pageSize); - }; - - async.waterfall([ - _getAllRepos, - _getReposForUserOrOrg - ], function(error, response) { - }); -} diff --git a/app/scripts/actions/getPipelineHistory.js b/app/scripts/actions/getPipelineHistory.js deleted file mode 100644 index a1beeb9292..0000000000 --- a/app/scripts/actions/getPipelineHistory.js +++ /dev/null @@ -1,22 +0,0 @@ -'use strict'; - -import request from 'superagent'; - -export default function getPipelineHistory({ - dispatch, history -}, { - jwt, namespace, name, slug -}, done) { - request.get(`${process.env.HUB_API_BASE_URL}/v2/repositories/${namespace}/${name}/webhook_pipeline/${slug}/history/`) - .set('Authorization', `JWT ${jwt}`) - .type('json') - .accept('json') - .end((err, res) => { - if (err) { - return done(); - } else { - dispatch('RECEIVE_PIPELINE_HISTORY', {slug, payload: res.body}); - return done(); - } - }); -} diff --git a/app/scripts/actions/getRepoComments.js b/app/scripts/actions/getRepoComments.js deleted file mode 100644 index d87ee52987..0000000000 --- a/app/scripts/actions/getRepoComments.js +++ /dev/null @@ -1,23 +0,0 @@ -'use strict'; - -import _ from 'lodash'; -import { - Repositories as Repos - } from 'hub-js-sdk'; - -export default function repoComments(actionContext, payload) { - var token = payload.JWT; - - var namespace = payload.namespace; - if(payload.namespace === '_') { - namespace = 'library'; - } - var repoShortName = namespace + '/' + payload.repoName; - Repos.getCommentsForRepo(token, repoShortName, function(err, res) { - if (err) { - actionContext.dispatch('ERROR_RECEIVING_REPO_COMMENTS'); - } else { - actionContext.dispatch('RECEIVE_REPO_COMMENTS', res.body); - } - }, payload.pageNumber); -} diff --git a/app/scripts/actions/getSettingsData.js b/app/scripts/actions/getSettingsData.js deleted file mode 100644 index d8ae3fcf88..0000000000 --- a/app/scripts/actions/getSettingsData.js +++ /dev/null @@ -1,28 +0,0 @@ -'use strict'; -import _ from 'lodash'; -import { - Users - } from 'hub-js-sdk'; -var debug = require('debug')('hub:actions:getSettingsData'); - -var getSettingsData = function(actionContext, {JWT, username, repoType}) { - Users.getUserSettings(JWT, username, function(err, res) { - if (err){ - debug('getUserSettings', err); - } else { - if (repoType === 'regular') { - actionContext.dispatch('CREATE_REPO_UPDATE_FIELD_WITH_VALUE', { - fieldKey: 'is_private', - fieldValue: res.body.default_repo_visibility - }); - } else if (repoType === 'autobuild') { - actionContext.dispatch('AUTOBUILD_FORM_UPDATE_FIELD_WITH_VALUE', { - fieldKey: 'isPrivate', - fieldValue: res.body.default_repo_visibility - }); - } - } - }); -}; - -module.exports = getSettingsData; diff --git a/app/scripts/actions/getTeamMembers.js b/app/scripts/actions/getTeamMembers.js deleted file mode 100644 index 9a88acb6a7..0000000000 --- a/app/scripts/actions/getTeamMembers.js +++ /dev/null @@ -1,17 +0,0 @@ -'use strict'; - -import _ from 'lodash'; -import { - Orgs - } from 'hub-js-sdk'; -var debug = require('debug')('hub:actions:getTeamMembers'); - -export default function(actionContext, {jwt, orgname, teamname}) { - Orgs.getMembers(jwt, orgname, teamname, function (err, res) { - if (err) { - debug('error', err); - } else { - actionContext.dispatch('RECEIVE_TEAM_MEMBERS', res.body); - } - }); -} diff --git a/app/scripts/actions/githubOauth.js b/app/scripts/actions/githubOauth.js deleted file mode 100644 index fada58ae49..0000000000 --- a/app/scripts/actions/githubOauth.js +++ /dev/null @@ -1,12 +0,0 @@ -'use strict'; - -const debug = require('debug')('hub:actions:githubOauth'); -const _ = require('lodash'); -const request = require('superagent'); - -module.exports = function(actionContext, {stateString}) { - request.post('/oauth/github-attempt/') - .send( {ghk: stateString} ) - .end(function(err, res) { - }); -}; diff --git a/app/scripts/actions/linkBitbucket.js b/app/scripts/actions/linkBitbucket.js deleted file mode 100644 index ab634d805a..0000000000 --- a/app/scripts/actions/linkBitbucket.js +++ /dev/null @@ -1,15 +0,0 @@ -'use strict'; - -import { Builds } from 'hub-js-sdk'; -const debug = require('debug')('hub:actions:linkBitbucket'); - -module.exports = function(actionContext, jwt) { - Builds.getBitbucketAuthUrl(jwt, function(err, res) { - if (err) { - debug('error', err); - actionContext.dispatch('BITBUCKET_AUTH_URL_ERROR', err); - } else if (res.ok) { - actionContext.dispatch('RECEIVE_BITBUCKET_AUTH_URL', res.body); - } - }); -}; diff --git a/app/scripts/actions/linkGithub.js b/app/scripts/actions/linkGithub.js deleted file mode 100644 index 2e410330f9..0000000000 --- a/app/scripts/actions/linkGithub.js +++ /dev/null @@ -1,15 +0,0 @@ -'use strict'; - -import { Builds } from 'hub-js-sdk'; -const debug = require('debug')('hub:actions:linkGithub'); - -module.exports = function(actionContext, jwt) { - Builds.getGithubClientID(jwt, function(err, res) { - if (err) { - debug('error', err); - actionContext.dispatch('GITHUB_ID_ERROR', err); - } else if (res.ok) { - actionContext.dispatch('RECEIVE_GITHUB_ID', res.body); - } - }); -}; diff --git a/app/scripts/actions/loginUpdateFormField.js b/app/scripts/actions/loginUpdateFormField.js deleted file mode 100644 index d2a993ac58..0000000000 --- a/app/scripts/actions/loginUpdateFormField.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -export default function({ dispatch }, - { fieldKey, fieldValue }, - done) { - dispatch('LOGIN_UPDATE_FIELD_WITH_VALUE', { fieldKey, fieldValue }); -} diff --git a/app/scripts/actions/logout.js b/app/scripts/actions/logout.js deleted file mode 100644 index abf325ae5a..0000000000 --- a/app/scripts/actions/logout.js +++ /dev/null @@ -1,29 +0,0 @@ -/* @flow */ -'use strict'; - -import type FluxibleActionContext from '../../../flow-libs/fluxible'; - -import { Auth } from 'hub-js-sdk'; -import request from 'superagent'; -import async from 'async'; -const debug = require('debug')('hub:actions:logout'); - -module.exports = function(actionContext: FluxibleActionContext, jwt) { - async.parallel([ - function(callback) { - Auth.logout(jwt, function(err, res) { - if (err) { - debug('error', err); - actionContext.dispatch('LOGOUT_ERROR', err); - } else if (res.ok) { - actionContext.dispatch('LOGOUT'); - actionContext.history.push('/'); - } - }); - }, - function(callback) { - request.post('/attempt-logout/') - .end(callback); - }], - function(err, results) {}); -}; diff --git a/app/scripts/actions/longDescriptionUpdateFormField.js b/app/scripts/actions/longDescriptionUpdateFormField.js deleted file mode 100644 index f3cad471e7..0000000000 --- a/app/scripts/actions/longDescriptionUpdateFormField.js +++ /dev/null @@ -1,12 +0,0 @@ -'use strict'; - -export default function({ dispatch }, - { - fieldKey, - fieldValue - }, - done) { - dispatch('LONG_DESCRIPTION_UPDATE_FIELD_WITH_VALUE', { - fieldKey, fieldValue - }); -} diff --git a/app/scripts/actions/navigate.js b/app/scripts/actions/navigate.js deleted file mode 100644 index 6be4f002be..0000000000 --- a/app/scripts/actions/navigate.js +++ /dev/null @@ -1,186 +0,0 @@ -'use strict'; - -var debug = require('debug')('hub:actions:navigate'); -import _ from 'lodash'; -import { - JWT, - Notifications, - Repositories as Repos, - Search, - Users, - Billing -} from 'hub-js-sdk'; -import accountSettings from './navigate/accountSettings'; -import addRepo from './navigate/addRepo'; -import billingPlans from './navigate/billingPlans'; -import bitbucketRedirect from './navigate/bitbucketRedirect'; -import bitbucketUsersAndRepos from './navigate/bitbucketUsersAndRepos'; -import buildsMain from './navigate/buildsMain'; -import buildLogs from './navigate/buildLogs'; -import autoBuildSettings from './navigate/autoBuildSettings'; -import collaborators from './navigate/repoSettingsCollaborators'; -import dashStars from './navigate/dashStars'; -import dashContribs from './navigate/dashContribs'; -import dockerfile from './navigate/dockerfile'; -import explore from './navigate/explore'; -import serverTrial from './navigate/serverTrial'; -import serverTrialSuccess from './navigate/serverTrialSuccess'; -import serverBilling from './navigate/serverBilling'; -import cloudBilling from './navigate/cloudBilling'; -import getNamespaces from './navigate/getNamespaces'; -import githubUsersAndRepos from './navigate/githubUsersAndRepos'; -import githubRedirect from './navigate/githubRedirect'; -import home from './navigate/home'; -import licenses from './navigate/licenses'; -import linkedAccountSettings from './navigate/linkedAccountsSettings'; -import notificationSettings from './navigate/notificationSettings'; -import orgDashBilling from './navigate/orgBilling'; -import orgDashTeams from './navigate/orgDashTeams'; -import orgHome from './navigate/orgHome'; -import orgSummary from './navigate/orgSummary'; -import orgSettings from './navigate/orgSettings'; -import repo from './navigate/repo'; -import repoDetailsTags from './navigate/repoDetailsTags'; -import repoDetailsScannedTag from './navigate/repoDetailsScannedTag'; -import repoOfficial from './navigate/repoOfficial'; -import repoSettings from './navigate/repoSettings'; -import resetPass from './navigate/resetPass'; -import search from './navigate/search'; -import toOrg from './navigate/toOrg.js'; -import UserStore from '../stores/UserStore'; -import user from './navigate/user'; -import userStars from './navigate/userStars'; -import webhooks from './navigate/webhooks'; - -function noop({actionContext, payload, done, maybeData}) { - done(); -} - -function routesHaveHandlerFor(route, routes){ - return _.has(routes, route); -} - -function withUser(actionContext, payload, cb) { - /** - * If we are on the server and payload.cookies.jwt is a - * jwt, use it - */ - if (payload.cookies && payload.cookies.jwt) { - let token = payload.cookies.jwt; - actionContext.dispatch('RECEIVE_JWT', token); - /** - * Use the JWT to get the JWT's user's data. - */ - JWT.getUser(token, function(err, res) { - if (err) { - debug('NOT REALLY EXPIRED. JUST AN ERROR'); - actionContext.dispatch('EXPIRED_SIGNATURE', null); - return cb(null, err); - } else { - var cbData = res.body; - cbData.isAdmin = res.body.is_admin; - actionContext.dispatch('RECEIVE_USER', res.body); - cb(null, {token: token, user: cbData}); - } - }); - } else if (payload.jwt) { - debug('payload has jwt'); - /** - * if we have access to a jwt already, use it instead and assume - * we already have the user data since we're likely on the client - * (and we fill in the user data when a user logs in on the client) - */ - cb(null, { - token: payload.jwt, - user: actionContext.getStore(UserStore).getState() - }); - } else { - debug('no jwt and payload has no cookies; This should not happen'); - /** - * We have no jwt and no error? This shouldn't happen. - */ - cb(null, {}); - } -} - -module.exports = function(actionContext, payload, done) { - var _done = done; - done = function() { - _done.apply(this, arguments); - }; - - if (!payload.location.pathname) { - /** - * if we don't have a pathname, react-router doesn't have a route. - * ignore it. There's nothing we can do. - */ - return done(); - } - - withUser(actionContext, payload, function(err, maybeData) { - if (err) { - debug(err); - return done(); - } - - let routeName = payload.routes[payload.routes.length - 1].name; - debug('routeName', routeName); - let routes = { - 'accountSettings': accountSettings, - 'addRepo': addRepo, - 'addWebhook': noop, - 'addAutoBuild': linkedAccountSettings, // Questionable navigate Route - 'authServicesRoot': linkedAccountSettings, - 'autobuildBitbucket': getNamespaces, - 'autobuildBitbucketOrgs': bitbucketUsersAndRepos, - 'autobuildGithub': getNamespaces, - 'autobuildGithubOrgs': githubUsersAndRepos, - 'autobuildSettings': autoBuildSettings, - 'billingPlans': billingPlans, - 'bitbucketRedirect': bitbucketRedirect, - 'buildLogs': buildLogs, - 'buildsMain': buildsMain, - 'cloudBilling': cloudBilling, - 'collaborators': collaborators, - 'createOrgSubscription': orgDashBilling, - 'createSubscription': billingPlans, - 'dashboardHome': home, - 'dashContribs': dashContribs, - 'dashStars': dashStars, - 'dockerfile': dockerfile, - 'explore': explore, - 'githubRedirect': githubRedirect, - 'licenses': licenses, - 'notifications': notificationSettings, - 'orgDashBilling': orgDashBilling, - 'orgDashHome': orgHome, - 'orgDashSettings': orgSettings, - 'orgDashTeams': orgDashTeams, - 'orgSummary': orgSummary, - 'repoDetailsInfo': repo, - 'repoDetailsTags': repoDetailsTags, - 'repoDetailsScannedTag': repoDetailsScannedTag, - 'repoOfficial': repoOfficial, - 'repoSettingsMain': repoSettings, - 'resetPass': resetPass, - 'search': search, - 'serverBilling': serverBilling, - 'serverTrial': serverTrial, - 'serverTrialSuccess': serverTrialSuccess, - 'toOrg': toOrg, - 'updateBillingInfo': billingPlans, - 'updateOrgBillingInfo': orgDashBilling, - 'user': user, - 'userRepos': user, //This route is a clone of /u/:user/ WHY DO WE HAVE THIS? - 'userStars': userStars, - 'webhooks': webhooks - }; - actionContext.dispatch('CHANGE_ROUTE', payload); - if(routesHaveHandlerFor(routeName, routes)){ - routes[routeName]({ actionContext, payload, done, maybeData }); - } else { - debug(`no handler for ${routeName}`, payload.routes); - done(); - } - }); -}; diff --git a/app/scripts/actions/navigate/accountSettings.js b/app/scripts/actions/navigate/accountSettings.js deleted file mode 100644 index e10642d3b9..0000000000 --- a/app/scripts/actions/navigate/accountSettings.js +++ /dev/null @@ -1,79 +0,0 @@ -'use strict'; -const debug = require('debug')('navigate::accountSettings'); -import { - Emails, - Users -} from 'hub-js-sdk'; -import async from 'async'; -import _ from 'lodash'; - -function sortEmails(emails) { - return _.sortByOrder(emails, - ['primary', 'verified'], - [false, false]); -} - -function parseRes({res, actionContext}) { - let emails = res.body.results; - let sortedEmails = _.sortByOrder(emails, - ['primary', 'verified'], - [false, false]); - return sortedEmails; -} - -export default function accountSettings({ - actionContext, payload, done, maybeData -}){ - actionContext.dispatch('CHANGE_PASS_CLEAR'); - if (_.has(maybeData, 'token')) { - var { token, user } = maybeData; - async.parallel({ - emails: function(callback) { - debug('ACCOUNT SETTINGS EMAILS'); - if (user && user.isAdmin) { - Emails.getEmailsForUser(token, user.username, function(err, res){ - if (err) { - callback(); - } else { - let emails = parseRes({res, actionContext}); - actionContext.dispatch('RECEIVE_EMAILS', {emails: emails}); - callback(null, emails); - } - }); - } else { - Emails.getEmailsJWT(token, function(err, res){ - if (err) { - callback(); - } else { - let emails = parseRes({res, actionContext}); - actionContext.dispatch('RECEIVE_EMAILS', {emails: emails}); - callback(null, emails); - } - }); - } - }, - repoStats: function(callback) { - debug('GET REPO STATS'); - Users.getUserSettings(token, user.username, function(err, res) { - if (err) { - callback(); - } else { - actionContext.dispatch('RECEIVE_PRIVATE_REPOSTATS', res.body); - callback(null, res.body); - } - }); - } - }, function(err, res) { - if (err) { - debug('ERROR', err); - done(); - } else { - let { emails, repoStats } = res; - debug('SUCCESS'); - done(); - } - }); - } else { - done(); - } -} diff --git a/app/scripts/actions/navigate/addRepo.js b/app/scripts/actions/navigate/addRepo.js deleted file mode 100644 index b70b6bb913..0000000000 --- a/app/scripts/actions/navigate/addRepo.js +++ /dev/null @@ -1,66 +0,0 @@ -'use strict'; - -import has from 'lodash/object/has'; -import { - Users -} from 'hub-js-sdk'; -import async from 'async'; -var debug = require('debug')('navigate::ADD REPO'); - -export default function repo({actionContext, payload, done, maybeData}){ - - // Defining functions here so we have access to payload - const getUserSettings = (callback) => { - // Users.getUserSettings === Orgs.getOrgSettings - equivalent calls - let username = maybeData.user.username; - if (payload.location.query.namespace) { - username = payload.location.query.namespace; - } - Users.getUserSettings(maybeData.token, username, function(getErr, getRes) { - // This is to get default visibility. If this fails, we shouldn't block - if (getErr){ - callback(null, getErr); - } else { - callback(null, getRes.body); - } - }); - }; - - const getNamespace = (callback) => { - Users.getNamespacesForUser(maybeData.token, function(namespaceErr, namespaceRes) { - if (namespaceErr) { - // If we don't get back namespaces, we can't do anything, so no point in continuing with the other calls - callback(namespaceErr); - } else { - callback(null, namespaceRes.body); - } - }); - }; - - if (has(maybeData, 'token')) { - async.parallel({ - getNamespace, - getUserSettings - }, - function(err, res) { - actionContext.dispatch('CREATE_REPO_CLEAR_FORM'); - if (err) { - done(); - } else { - const is_private = has(res.getUserSettings, 'default_repo_visibility') ? res.getUserSettings.default_repo_visibility : true; - actionContext.dispatch('CREATE_REPO_UPDATE_FIELD_WITH_VALUE', {fieldKey: 'is_private', fieldValue: is_private}); - actionContext.dispatch('RECEIVE_PRIVATE_REPOSTATS', res.getUserSettings); - if (has(res.getNamespace, 'namespaces')) { - actionContext.dispatch('CREATE_REPO_RECEIVE_NAMESPACES', { - namespaces: res.getNamespace, - selectedNamespace: maybeData.user.username - }); - } - // No namespaces is already handled in AddRepo.jsx - Dispatch is unecessary - done(); - } - }); - } else { - done(); - } -} diff --git a/app/scripts/actions/navigate/autoBuildSettings.js b/app/scripts/actions/navigate/autoBuildSettings.js deleted file mode 100644 index 3d13720ad6..0000000000 --- a/app/scripts/actions/navigate/autoBuildSettings.js +++ /dev/null @@ -1,136 +0,0 @@ -'use strict'; -const debug = require('debug')('navigate::repoBuildSettings'); -import { parallel, waterfall } from 'async'; -import { PENDING_DELETE } from 'common/enums/RepoStatus'; -import _ from 'lodash'; -import { - Repositories as Repos, - Autobuilds as AutoBuild - } from 'hub-js-sdk'; - -function getRepo({maybeToken, actionContext, user, splat}) { - return function(callback){ - Repos.getRepo(maybeToken, `${user}/${splat}`, function(err, res) { - let status; - if (res && res.body) { - status = res.body.status; - } - - if (err || status === PENDING_DELETE) { - debug('GET REPO ERR::', err); - actionContext.dispatch('REPO_NOT_FOUND', err); - return callback(err); - } else { - debug('GETTING REPOSITORY::', res.body); - actionContext.dispatch('RECEIVE_REPOSITORY', res.body); - return callback(null, res.body); - } - }); - }; -} - -function getAutobuildSettings({maybeToken, actionContext, user, splat}) { - return function(callback){ - AutoBuild.getAutomatedBuildSettings(maybeToken, user, splat, function(err, res) { - if (err) { - debug('GET AUTOBUILD SETTINGS ERR::', err); - return callback(null, null); - } - debug('AUTOBUILDSETTINGS', res.body); - actionContext.dispatch('RECEIVE_AUTOBUILD_SETTINGS', res.body); - //also dispatch to the triggerByTag store to initialize the status - const {build_tags} = res.body; - if (build_tags) { - actionContext.dispatch('INITIALIZE_AB_TRIGGERS', build_tags); - } - return callback(null, res.body); - }); - }; -} - -function getAutobuildLinks({maybeToken, actionContext, user, splat}) { - return function(callback) { - AutoBuild.getAutomatedBuildLinks(maybeToken, user, splat, function(err, res) { - if (err) { - debug('GET AUTOBUILD LINKS ERR::', err); - return callback(null, null); - } - debug('AUTOBUILDLINKS', res.body); - actionContext.dispatch('RECEIVE_AUTOBUILD_LINKS', res.body.results); - return callback(null, res.body); - }); - }; -} - -function getTriggerStatus({maybeToken, actionContext, user, splat}) { - return function(callback) { - AutoBuild.getTriggerStatus(maybeToken, user, splat, function(err, res) { - if (err) { - debug('GET TRIGGER STATUS ERR::', err); - const defaultStatus = { - token: '', - trigger_url: '', - active: false - }; - actionContext.dispatch('RECEIVE_TRIGGER_STATUS', defaultStatus); - return callback(null, null); - } - debug('AUTOBUILDTRIGGERS', res.body); - actionContext.dispatch('RECEIVE_TRIGGER_STATUS', res.body); - return callback(null, res.body); - }); - }; -} - -function getTriggerLogs({maybeToken, actionContext, user, splat}) { - return function(callback) { - AutoBuild.getTriggerLogs(maybeToken, user, splat, function(err, res) { - if (err) { - debug('GET TRIGGER LOGS ERROR', err.res); - return callback(null, null); - } - debug('AUTOBUILDTRIGGERLOGS', res.body); - actionContext.dispatch('RECEIVE_TRIGGER_LOGS', res.body.results); - return callback(null, res.body.results); - }); - }; -} - -function getRest(args) { - return function(repoDetails, cbk) { - if (repoDetails) { - parallel({ - getAutoBuild: getAutobuildSettings(args), - getAutoLinks: getAutobuildLinks(args), - getTriggerStatus: getTriggerStatus(args), - getTriggerLogs: getTriggerLogs(args) - }, function (err, res) { - cbk(null, res); - }); - } else { - cbk(null); - } - }; -} - -export default function repoSettingsBuilds({actionContext, payload, done, maybeData}) { - debug('maybeData:', maybeData); - if (_.has(maybeData, 'token')) { - let args = { - actionContext, - maybeToken: maybeData.token, - user: payload.params.user, - splat: payload.params.splat - }; - - waterfall([ - getRepo(args), - getRest(args) - ], function (e, r) { - done(); - }); - } else { - actionContext.dispatch('REPO_NOT_FOUND', null); - done(); - } -} diff --git a/app/scripts/actions/navigate/billingPlans.js b/app/scripts/actions/navigate/billingPlans.js deleted file mode 100644 index 857edd4778..0000000000 --- a/app/scripts/actions/navigate/billingPlans.js +++ /dev/null @@ -1,145 +0,0 @@ -'use strict'; - -const debug = require('debug')('navigate::billingPlans'); -import async from 'async'; -import _ from 'lodash'; -import { - BILLFORWARD_ACCOUNT_ID -} from 'stores/common/Constants.js'; - -import { - Billing -} from 'hub-js-sdk'; - -function _getPersonalPlans({token}) { - return (callback) => { - Billing.getPlans(token, 'personal', (err, res) => { - if(err) { - debug(err); - callback(null, []); - } else { - let plansList = res.body; - let sortedPlans = _.sortBy(plansList, 'display_order'); - callback(null, sortedPlans); - } - }); - }; -} - -function _getBillingSubscriptions({token, user}) { - return (callback) => { - Billing.getBillingSubscriptions(token, user.username, (err, res) => { - if(!res || res.status === 500) { - debug('SERVER ISSUE: getting subscriptions'); - callback('SERVER ISSUE'); - } else if (err) { - callback(null, res.body); - } else { - debug('GET USER PLANS', res.body); - let subscriptions = res.body; - - // the assumption is that there is at most one subscription right now - let subscription = _.head(subscriptions); - callback(err, subscription); - } - }); - }; -} - -function _getBillingAccount({token, user}) { - return (callback) => { - Billing.getBillingAccount(token, user.username, (err, res) => { - if(!res || res.status === 500) { - debug('SERVER ISSUE: getting billing account info'); - // NOTE: If this is a brand new billing account - set newBilling to true - callback(null, {account: { newBilling: true }}); - } else if (err) { - debug('NO BILLING ACCOUNT CONNECTED'); - // NOTE: If this is a brand new billing account - set newBilling to true - callback(null, {account: { newBilling: true }}); - } else { - debug('GET BILLING ACCOUNT', res.body); - const account = { ...res.body, newBilling: false }; - callback(err, { account, billforwardId: res.header[BILLFORWARD_ACCOUNT_ID] }); - } - }); - }; -} - -function _getBillingInfo({token, user}) { - return (callback) => { - Billing.getBillingInfo(token, user.username, (err, res) => { - if(!res || res.status === 500) { - debug('SERVER ISSUE: getting billing info'); - // NOTE: If this is a brand new billing profile - set newBilling to true - callback(null, { newBilling: true }); - } else if (err) { - debug('NO BILLING INFO CONNECTED'); - // NOTE: If this is a brand new billing profile - set newBilling to true - callback(null, { newBilling: true }); - } else { - debug('GET BILLING INFO', res.body); - callback(err, { ...res.body, newBilling: false }); - } - }); - }; -} - -function _getBillingInvoices({token, user}) { - return (callback) => { - Billing.getBillingInvoices(token, user.username, (err, res) => { - if(err) { - debug('NO BILLING ACCOUNT CONNECTED'); - callback(null, []); - } else { - debug('GET BILLING INVOICES', res.body); - callback(err, res.body); - } - }); - }; -} - -export default function billingPlans({actionContext, payload, done, maybeData}){ - if (maybeData.token && maybeData.user) { - let {token, user} = maybeData; - actionContext.dispatch('RESET_BILLING_PLANS'); - /* - NOTE: - None of the functions should pass an error into the callback or else it will - kill the rest of the calls and return before we're able to fetch all the data - */ - async.parallel({ - allPlans: _getPersonalPlans({token}), - userPlan: _getBillingSubscriptions({token, user}), - accountInfo: _getBillingAccount({token, user}), - billingInfo: _getBillingInfo({token, user}), - invoiceList: _getBillingInvoices({token, user}) - }, function(err, results){ - const { - allPlans, - userPlan, - accountInfo, - billingInfo, - invoiceList - } = results; - debug('BILLING PLANS', results); - // IF AN ACCOUNT HAS BEEN MIGRATED - ITS ACCOUNT INFO WILL HAVE PARAMETER 'payment_gateway' === 'stripe' - const gateway = accountInfo && accountInfo.account && accountInfo.account.payment_gateway; - const billforwardId = accountInfo && accountInfo.billforwardId; - actionContext.dispatch('RECEIVE_BILLING_PLANS', { - plansList: allPlans - }); - actionContext.dispatch('RECEIVE_BILLING_INFO', { - billingInfo: billingInfo, - accountInfo: accountInfo && accountInfo.account, - currentPlan: userPlan, - gateway, - billforwardId - }); - actionContext.dispatch('RECEIVE_INVOICES', {invoices: invoiceList}); - return done(); - }); - } else { - done(); - } -} diff --git a/app/scripts/actions/navigate/bitbucketRedirect.js b/app/scripts/actions/navigate/bitbucketRedirect.js deleted file mode 100644 index fc63beeea9..0000000000 --- a/app/scripts/actions/navigate/bitbucketRedirect.js +++ /dev/null @@ -1,72 +0,0 @@ -'use strict'; - -import async from 'async'; -import has from 'lodash/object/has'; -import { Builds } from 'hub-js-sdk'; -import linkedAccountSettingsAction from './linkedAccountsSettings'; -var debug = require('debug')('navigate::bitbucketRedirect'); - -/** - * This action is hit when the site gets redirected from the github oauth workflow - * @param actionContext - * @param payload - * @param done - * @param maybeData - */ -export default function bitbucketRedirect({actionContext, payload, done, maybeData}){ - - const SOURCES = { - GITHUB: 'github', - BITBUCKET: 'bitbucket' - }; - - debug('In Bitbucket Redirect Route Handler !'); - //If token is available the user is already logged in - var token; - if (has(maybeData, 'token')) { - token = maybeData.token; - var oauthVerifier = payload.location.query.oauth_verifier; - var oauthToken = payload.location.query.oauth_token; - - var _associateBitbucketAccount = function(cb) { - Builds.associateBitbucketAccount(token, {oauth_verifier: oauthVerifier, oauth_token: oauthToken}, function(err, res) { - if (err) { - debug(JSON.stringify(err)); - debug('ERROR ASSOCIATING BITBUCKET ACCOUNT: ' + err); - actionContext.dispatch('BITBUCKET_ASSOCIATE_ERROR', res.body); - cb(err); - } else { - if (res.body) { - debug('Bitbucket account association Success: ' + res.body); - actionContext.dispatch('BITBUCKET_ASSOCIATE_SUCCESS', res.body); - cb(null, res.body); - } - } - }); - }; - - var _getLinkedAccounts = function(callback) { - debug('Getting linked account settings state.'); - linkedAccountSettingsAction( - { - actionContext: actionContext, - payload: payload, - done: callback, - maybeData: maybeData - } - ); - }; - - async.series([ - _associateBitbucketAccount, - _getLinkedAccounts - ], function(err, results) { - done(); - } - ); - } else { - token = ''; - //TODO: redirect to login page or test redirect happens automatically - done(); - } -} diff --git a/app/scripts/actions/navigate/bitbucketUsersAndRepos.js b/app/scripts/actions/navigate/bitbucketUsersAndRepos.js deleted file mode 100644 index 365a8f28d6..0000000000 --- a/app/scripts/actions/navigate/bitbucketUsersAndRepos.js +++ /dev/null @@ -1,49 +0,0 @@ -'use strict'; - -var debug = require('debug')('navigate::bitbucketRepos'); -import async from 'async'; -import { - Builds - } from 'hub-js-sdk'; -import has from 'lodash/object/has'; -import linkedAccountAction from './linkedAccountsSettings'; -var debug = require('debug')('navigate::bitbucketUsersAndRepos'); - -export default function getBitbucketRepos({actionContext, payload, done, maybeData}) { - debug('GET BITBUCKET REPOS'); - var _getLinkedAccountStatus = function(cb) { - linkedAccountAction({ - actionContext: actionContext, - payload: payload, - done: cb, - maybeData: maybeData}); - }; - - var _getSourceRepos = function(cb) { - Builds.getSourceRepos('bitbucket', maybeData.token, function (err, res) { - if (err) { - const { detail } = err.response.body; - if (detail) { - actionContext.dispatch('LINKED_REPO_SOURCES_ERROR', detail); - } - cb(null); - } else{ - cb(null, res.body); - } - }); - }; - - - if (has(maybeData, 'token')) { - async.parallel([ - _getLinkedAccountStatus, - _getSourceRepos - ], function(err, results) { - actionContext.dispatch('SET_LINKED_REPO_TYPE', 'bitbucket'); - actionContext.dispatch('RECEIVE_LINKED_REPO_SOURCES', results[1]); - done(); - }); - } else { - done(); - } -} diff --git a/app/scripts/actions/navigate/buildLogs.js b/app/scripts/actions/navigate/buildLogs.js deleted file mode 100644 index 21f0240a8e..0000000000 --- a/app/scripts/actions/navigate/buildLogs.js +++ /dev/null @@ -1,105 +0,0 @@ -'use strict'; - -import has from 'lodash/object/has'; -import { parallel, waterfall } from 'async'; -import request from 'superagent'; -import { PENDING_DELETE } from 'common/enums/RepoStatus'; -import { - Repositories as Repos, - Autobuilds -} from 'hub-js-sdk'; -const debug = require('debug')('buildLogs'); - -export default function buildLogs({actionContext, payload, done, maybeData}) { - var token; - if (has(maybeData, 'token')) { - token = maybeData.token; - } else { - token = ''; - } - - var namespace = payload.params.user; - if (payload.params.user === '_') { - namespace = 'library'; - } - var repoShortName = namespace + '/' + payload.params.splat; - const build_code = payload.params.build_code; - - var _getRepo = function (callback) { - Repos.getRepo(token, repoShortName, function (err, res) { - let status; - if (res && res.body) { - status = res.body.status; - } - - if (err || status === PENDING_DELETE) { - actionContext.dispatch('REPO_NOT_FOUND', err); - callback(err); - } else { - actionContext.dispatch('RECEIVE_REPOSITORY', res.body); - callback(null, res.body); - } - }); - }; - - var _getRest = function (repoDetail, cb) { - if (repoDetail) { - parallel([ - function (callback) { - Repos.getCommentsForRepo(token, repoShortName, function (err, res) { - if (err) { - callback(err); - } else { - callback(null, res.body); - } - }); - }, function (callback) { - request.get(process.env.REGISTRY_API_BASE_URL + '/v2/repositories/' + repoShortName + '/buildhistory/' + build_code + '/') - .accept('application/json') - .set('Authorization', 'JWT ' + token) - .end((err, res) => { - if(err) { - callback(); - } else { - debug('BUILD LOGS RECEIVE', res.body); - actionContext.dispatch('BUILD_LOGS_RECEIVE', res.body); - callback(); - } - }); - }, function (callback) { - if (repoDetail.is_automated) { - Autobuilds.getAutomatedBuildSettings(token, namespace, payload.params.splat, function (err, res) { - if (err) { - actionContext.dispatch('AUTOBUILD_REPO_NOT_FOUND'); - callback(err); - } else { - actionContext.dispatch('RECEIVE_AUTOBUILD_SETTINGS', res.body); - callback(); - } - }); - } else { - callback(); - } - } - ], - function (error, results) { - if (error) { - cb(); - } else { - actionContext.dispatch('RECEIVE_REPO_COMMENTS', results[0]); - cb(); - } - }); - } else { - cb(); - } - }; - - waterfall([ - _getRepo, - _getRest - ], function(err, res) { - done(); - }); - -} diff --git a/app/scripts/actions/navigate/buildsMain.js b/app/scripts/actions/navigate/buildsMain.js deleted file mode 100644 index 5e2bc2b681..0000000000 --- a/app/scripts/actions/navigate/buildsMain.js +++ /dev/null @@ -1,99 +0,0 @@ -'use strict'; - -import has from 'lodash/object/has'; -import { parallel, waterfall } from 'async'; -import { PENDING_DELETE } from 'common/enums/RepoStatus'; -import { - Repositories as Repos, - Autobuilds -} from 'hub-js-sdk'; - -export default function buildsMain({actionContext, payload, done, maybeData}) { - var token; - if (has(maybeData, 'token')) { - token = maybeData.token; - } else { - token = ''; - } - - var namespace = payload.params.user; - if (payload.params.user === '_') { - namespace = 'library'; - } - var repoShortName = namespace + '/' + payload.params.splat; - - var _getRepo = function (callback) { - Repos.getRepo(token, repoShortName, function (err, res) { - let status; - if (res && res.body) { - status = res.body.status; - } - - if (err || status === PENDING_DELETE) { - actionContext.dispatch('REPO_NOT_FOUND', err); - callback(err); - } else { - actionContext.dispatch('RECEIVE_REPOSITORY', res.body); - callback(null, res.body); - } - }); - }; - - var _getRest = function (repoDetail, cb) { - if (repoDetail) { - parallel([ - function (callback) { - Repos.getBuildHistory(token, { - namespace, - name: payload.params.splat - }, function (err, res) { - if (err) { - callback(); - } else { - actionContext.dispatch('RECEIVE_BUILD_HISTORY_FOR_REPOSITORY', res.body); - callback(); - } - }); - }, function(callback) { - if (repoDetail.is_automated) { - Autobuilds.getAutomatedBuildSettings(token, namespace, payload.params.splat, function (err, res) { - if (err) { - actionContext.dispatch('AUTOBUILD_REPO_NOT_FOUND'); - callback(null); - } else { - callback(null, res.body); - } - }); - } else { - callback(null); - } - } - ], - function (error, results) { - if (error) { - cb(); - } else { - if (results[1]) { - actionContext.dispatch('RECEIVE_AUTOBUILD_SETTINGS', results[1]); - //also dispatch to the triggerByTag store to initialize the status - const {build_tags} = results[1]; - if (build_tags) { - actionContext.dispatch('INITIALIZE_AB_TRIGGERS', build_tags); - } - } - cb(); - } - }); - } else { - cb(); - } - }; - - waterfall([ - _getRepo, - _getRest - ], function(err, res) { - done(); - }); - -} diff --git a/app/scripts/actions/navigate/cloudBilling.js b/app/scripts/actions/navigate/cloudBilling.js deleted file mode 100644 index 4fbb8e1368..0000000000 --- a/app/scripts/actions/navigate/cloudBilling.js +++ /dev/null @@ -1,109 +0,0 @@ -'use strict'; - -const debug = require('debug')('navigate::billingPlans'); -import async from 'async'; -import _ from 'lodash'; - -import { - Billing, - Users - } from 'hub-js-sdk'; - -//GETs current HUB subscription -function _getBillingSubscriptions({token, user}) { - return (callback) => { - Billing.getBillingSubscriptions(token, user.username, (err, res) => { - if(err) { - callback(null, {}); - } else { - debug('GET USER PLANS', res.body); - let subscriptions = res.body; - - // the assumption is that there is at most one subscription right now - let subscription = _.head(subscriptions); - callback(err, subscription); - } - }); - }; -} - -function _getBillingAccount({token, user}) { - return (callback) => { - Billing.getBillingAccount(token, user.username, (err, res) => { - if(err) { - debug('NO BILLING ACCOUNT CONNECTED'); - callback(null, {}); - } else { - debug('GET BILLING ACCOUNT', res.body); - callback(null, res.body); - } - }); - }; -} - -function _getBillingInfo({token, user}) { - return (callback) => { - Billing.getBillingInfo(token, user.username, (err, res) => { - if(err) { - debug('NO BILLING ACCOUNT CONNECTED'); - callback(null, {}); - } else { - debug('GET BILLING INFO', res.body); - callback(null, res.body); - } - }); - }; -} -/** - * ============================================= - * ^ GET SUBSCRIPTIONS/ACCOUNTINFO/BILLINGINFO - * Must re-get on change of namespace - * ============================================= - */ - -//GET namespaces for user -function _getNamespaces({token}) { - return (callback) => { - Users.getNamespacesForUser(token, function(err, res) { - if (err) { - callback(null, {}); - } else { - callback(null, res.body.namespaces); - } - }); - }; -} - -export default function billingPlans({actionContext, payload, done, maybeData}){ - if (maybeData.token && maybeData.user) { - const {token, user} = maybeData; - actionContext.dispatch('RESET_CLOUD_BILLING_PLANS'); - async.parallel({ - userPlan: _getBillingSubscriptions({token, user}), - accountInfo: _getBillingAccount({token, user}), - billingInfo: _getBillingInfo({token, user}), - namespaces: _getNamespaces({token}) - }, function(err, results){ - const { userPlan, accountInfo, billingInfo, namespaces } = results; - debug('CLOUD BILLING PLANS', results); - actionContext.dispatch('RECEIVE_CLOUD_BILLING_INFO', { - billingInfo: billingInfo, - accountInfo: accountInfo, - currentPlan: userPlan - }); - actionContext.dispatch('ENTERPRISE_PAID_RECEIVE_ORGS', namespaces); - const values = _.merge({}, billingInfo, { - account_first: accountInfo.first_name, - account_last: accountInfo.last_name, - company_name: accountInfo.company_name, - email: accountInfo.email - }); - debug('INITIALIZE ENTERPRISE BILLING FORM: ', values); - // Need to differentiate btw billingInfo/accountInfo first/last names - actionContext.dispatch('ENTERPRISE_PAID_POPULATE_FORM', values); - return done(); - }); - } else { - done(); - } -} diff --git a/app/scripts/actions/navigate/dashContribs.js b/app/scripts/actions/navigate/dashContribs.js deleted file mode 100644 index 45f607930e..0000000000 --- a/app/scripts/actions/navigate/dashContribs.js +++ /dev/null @@ -1,78 +0,0 @@ -'use strict'; -var debug = require('debug')('navigate::dashStars'); -import async from 'async'; -import _ from 'lodash'; -import { - Repositories as Repos, - Notifications, - Orgs, - Users - } from 'hub-js-sdk'; - -export default function home({actionContext, payload, done, maybeData}){ - if (_.has(maybeData, 'token')) { - - //This is always for current user - //Get contributed repos - var _getReposByFilterTypeContrib = function(cb) { - var username = maybeData.user.username; - Repos.getContributedReposForUser(maybeData.token, username, function (err, res) { - if (err) { - cb(); - } else { - actionContext.dispatch('RECEIVE_CONTRIB', res.body); - cb(); - } - }, payload.location.query.page); - }; - - - //Get orgs for user - var _getOrgsForCurrentUser = function(cb) { - Users.getOrgsForUser(maybeData.token, function(err, res) { - if (err) { - debug(err); - cb(); - } else { - actionContext.dispatch('RECEIVE_DASHBOARD_NAMESPACES', { - orgs: res.body, - user: maybeData.user.username - }); - cb(); - } - }); - }; - - //Get user settings for private repo stats - var _getUserSettings = function(cb) { - Users.getUserSettings(maybeData.token, maybeData.user.username, function(err, res) { - if (err) { - debug(err); - cb(); - } else { - actionContext.dispatch('RECEIVE_PRIVATE_REPOSTATS', res.body); - cb(); - } - }); - }; - - //This is executed only for the currently logged in user, so put in starred, contributed only here - var _doParallelCalls = function() { - async.parallel([ - _getOrgsForCurrentUser, - _getReposByFilterTypeContrib, - _getUserSettings - ], function(err, results) { - if (err) { - debug(err); - } - return done(); - }); - }; - - actionContext.dispatch('CURRENT_USER_CONTEXT', { username: maybeData.user.username }); - _doParallelCalls(); - } else { - done(); - } -} diff --git a/app/scripts/actions/navigate/dashRepos.js b/app/scripts/actions/navigate/dashRepos.js deleted file mode 100644 index 3aeffbdf48..0000000000 --- a/app/scripts/actions/navigate/dashRepos.js +++ /dev/null @@ -1,138 +0,0 @@ -'use strict'; -var debug = require('debug')('navigate::dashRepos'); -import async from 'async'; -import _ from 'lodash'; -import { - Repositories as Repos, - Notifications, - Orgs, - Users -} from 'hub-js-sdk'; - -export default function home({actionContext, payload, done, maybeData}){ - if (_.has(maybeData, 'token')) { - - //Get repos for user or org - var _getReposForUserOrOrg = function(cb, userType) { - var userOrOrgName = payload.params.user || maybeData.user.username; - actionContext.dispatch('DASHBOARD_REPOS_STORE_ATTEMPTING_GET_REPOS'); - Repos.getReposForUser(maybeData.token, userOrOrgName, function(err, res) { - if (err) { - actionContext.dispatch('ERROR_RECEIVING_REPOS'); - cb(); - } else { - actionContext.dispatch('RECEIVE_REPOS', res.body); - cb(); - } - }, payload.location.query.page); - }; - - //Get orgs for user - var _getOrgsForCurrentUser = function(cb) { - Users.getOrgsForUser(maybeData.token, function(err, res) { - if (err) { - debug(err); - cb(); - } else { - actionContext.dispatch('CURRENT_USER_ORGS', res.body); - cb(); - } - }); - }; - - //Get user settings for private repo stats - var _getUserSettings = function(cb) { - Users.getUserSettings(maybeData.token, maybeData.user.username, function(err, res) { - if (err) { - debug(err); - cb(); - } else { - actionContext.dispatch('RECEIVE_PRIVATE_REPOSTATS', res.body); - cb(); - } - }); - }; - - //This is executed only for the currently logged in user, so put in starred, contributed only here - var _doParallelCalls = function() { - async.parallel([ - _getReposForUserOrOrg, - _getOrgsForCurrentUser, - _getUserSettings, - function(callback) { - Notifications.getActivityFeed(maybeData.token, function(err, res) { - if (res) { - actionContext.dispatch('RECEIVE_ACTIVITY_FEED', res.body); - } - callback(); - }); - } - ], function(err, results) { - if (err) { - debug(err); - } - return done(); - }); - }; - - //Get Organization by name - var _getOrgByName = function() { - Orgs.getOrg(maybeData.token, payload.params.user, function(err, res) { - if (err) { - debug(err); - } else { - var org = res.body; - if (!_.isEmpty(org)) { - return org; - } - } - }); - return {}; - }; - - //Get user by name - var _getUserByName = function() { - Users.getUser(maybeData.token, payload.params.user, function(err, res) { - if (err) { - debug(err); - } else { - var user = res.body; - if (!_.isEmpty(user)) { - return user; - } - } - }); - return {}; - }; - - if (payload.params.user) { - if (payload.params.user === maybeData.user.username) { - actionContext.dispatch('CURRENT_USER_CONTEXT', { username: payload.params.user }); - _doParallelCalls(); - } else { - //get Org by name, if success set userOrOrg = `org` else set it to `user` - async.series([ - function (callback) { - callback(null, _getOrgByName(payload.params.user)); - }, - function (callback) { - callback(null, _getUserByName(payload.params.user)); - } - ], function (err, results) { - if (err) { - debug(err); - } else { - debug('Results of Series Call: ' + JSON.stringify(results)); - actionContext.dispatch('CURRENT_USER_CONTEXT', { username: payload.params.user }); - _getReposForUserOrOrg(done); - } - }); - } - } else { - actionContext.dispatch('CURRENT_USER_CONTEXT', { username: maybeData.user.username }); - _doParallelCalls(); - } - } else { - done(); - } -} diff --git a/app/scripts/actions/navigate/dashStars.js b/app/scripts/actions/navigate/dashStars.js deleted file mode 100644 index 5744f62161..0000000000 --- a/app/scripts/actions/navigate/dashStars.js +++ /dev/null @@ -1,77 +0,0 @@ -'use strict'; -var debug = require('debug')('navigate::dashStars'); -import async from 'async'; -import _ from 'lodash'; -import { - Repositories as Repos, - Notifications, - Orgs, - Users -} from 'hub-js-sdk'; - -export default function home({actionContext, payload, done, maybeData}){ - if (_.has(maybeData, 'token')) { - - //This is always for current user - //Get starred repos - var _getReposByFilterTypeStarred = function(cb) { - var username = maybeData.user.username; - Repos.getStarredReposForUser(maybeData.token, username, function (err, res) { - if (err) { - cb(); - } else { - actionContext.dispatch('RECEIVE_STARRED', res.body); - cb(); - } - }, payload.location.query.page); - }; - - //Get orgs for user - var _getOrgsForCurrentUser = function(cb) { - Users.getOrgsForUser(maybeData.token, function(err, res) { - if (err) { - debug(err); - cb(); - } else { - actionContext.dispatch('RECEIVE_DASHBOARD_NAMESPACES', { - orgs: res.body, - user: maybeData.user.username - }); - cb(); - } - }); - }; - - //Get user settings for private repo stats - var _getUserSettings = function(cb) { - Users.getUserSettings(maybeData.token, maybeData.user.username, function(err, res) { - if (err) { - debug(err); - cb(); - } else { - actionContext.dispatch('RECEIVE_PRIVATE_REPOSTATS', res.body); - cb(); - } - }); - }; - - //This is executed only for the currently logged in user, so put in starred, contributed only here - var _doParallelCalls = function() { - async.parallel([ - _getOrgsForCurrentUser, - _getReposByFilterTypeStarred, - _getUserSettings - ], function(err, results) { - if (err) { - debug(err); - } - return done(); - }); - }; - - actionContext.dispatch('CURRENT_USER_CONTEXT', { username: maybeData.user.username }); - _doParallelCalls(); - } else { - done(); - } -} diff --git a/app/scripts/actions/navigate/dockerfile.js b/app/scripts/actions/navigate/dockerfile.js deleted file mode 100644 index d43d6afda5..0000000000 --- a/app/scripts/actions/navigate/dockerfile.js +++ /dev/null @@ -1,90 +0,0 @@ -'use strict'; - -import has from 'lodash/object/has'; -import { parallel, waterfall } from 'async'; -import { PENDING_DELETE } from 'common/enums/RepoStatus'; -import { - Repositories as Repos, - Autobuilds -} from 'hub-js-sdk'; - -export default function dockerfile({actionContext, payload, done, maybeData}){ - var token; - if (has(maybeData, 'token')) { - token = maybeData.token; - } else { - token = ''; - } - - var namespace = payload.params.user; - if(payload.params.user === '_') { - namespace = 'library'; - } - var repoShortName = namespace + '/' + payload.params.splat; - - var _getRepo = function (callback) { - Repos.getRepo(token, repoShortName, function (err, res) { - let status; - if (res && res.body) { - status = res.body.status; - } - - if (err || status === PENDING_DELETE) { - actionContext.dispatch('REPO_NOT_FOUND', err); - callback(err); - } else { - actionContext.dispatch('RECEIVE_REPOSITORY', res.body); - callback(null, res.body); - } - }); - }; - - var _getRest = function (repoDetail, cb) { - if (repoDetail) { - parallel([ - function (callback) { - Repos.getDockerfile(token, repoShortName, function (err, res) { - if (err) { - callback(); - } else { - actionContext.dispatch('RECEIVE_DOCKERFILE_FOR_REPOSITORY', res.body); - callback(); - } - }); - }, function(callback) { - if (repoDetail.is_automated) { - Autobuilds.getAutomatedBuildSettings(token, namespace, payload.params.splat, function (err, res) { - if (err) { - actionContext.dispatch('AUTOBUILD_REPO_NOT_FOUND'); - callback(null); - } else { - callback(null, res.body); - } - }); - } else { - callback(null); - } - } - ], - function (error, results) { - if (error) { - cb(); - } else { - if (results[1]) { - actionContext.dispatch('RECEIVE_AUTOBUILD_SETTINGS', results[1]); - } - cb(); - } - }); - } else { - cb(); - } - }; - - waterfall([ - _getRepo, - _getRest - ], function(err, res) { - done(); - }); -} diff --git a/app/scripts/actions/navigate/explore.js b/app/scripts/actions/navigate/explore.js deleted file mode 100644 index 1167f1ef23..0000000000 --- a/app/scripts/actions/navigate/explore.js +++ /dev/null @@ -1,26 +0,0 @@ -'use strict'; -var debug = require('debug')('navigate::home'); -import async from 'async'; -import _ from 'lodash'; -import { - Repositories as Repos, - Notifications, - Orgs, - Users -} from 'hub-js-sdk'; - -export default function explore({actionContext, payload, done, maybeData}){ - - //Get repos for library - // We have, hijacked the repos store. This might not be good - // in the long run - Repos.getReposForUser(maybeData.token, 'library', function(err, res) { - if (err) { - actionContext.dispatch('ERROR_RECEIVING_REPOS'); - done(); - } else { - actionContext.dispatch('RECEIVE_REPOS', res.body); - done(); - } - }, payload.location.query.page); -} diff --git a/app/scripts/actions/navigate/getNamespaces.js b/app/scripts/actions/navigate/getNamespaces.js deleted file mode 100644 index 99376c1547..0000000000 --- a/app/scripts/actions/navigate/getNamespaces.js +++ /dev/null @@ -1,38 +0,0 @@ -'use strict'; - -import _ from 'lodash'; -import { - Users - } from 'hub-js-sdk'; -var debug = require('debug')('navigate::getNamespaces'); - -export default function getNamespaces({actionContext, payload, done, maybeData}){ - var initialRepoName = payload.params.sourceRepoName; - var initialNamespace = payload.location.query.namespace || maybeData.user.username; - if (_.has(maybeData, 'token')) { - Users.getNamespacesForUser(maybeData.token, function(err, res) { - if (err) { - return done(); - } - Users.getUserSettings(maybeData.token, maybeData.user.username, function(settingsErr, settingsRes) { - if (settingsRes.body) { - actionContext.dispatch('RECEIVE_PRIVATE_REPOSTATS', settingsRes.body); - actionContext.dispatch('RECEIVE_NAMESPACES', res.body); - actionContext.dispatch('INITIALIZE_AUTOBUILD_FORM', {name: initialRepoName, namespace: initialNamespace}); - actionContext.dispatch('CLEAR_AUTOBUILD_FORM_ERRORS'); - if (payload.routes[payload.routes.length - 1].name === 'autobuildGithub') { - actionContext.dispatch('SET_LINKED_REPO_TYPE', 'github'); - } else if (payload.routes[payload.routes.length - 1].name === 'autobuildBitbucket') { - actionContext.dispatch('SET_LINKED_REPO_TYPE', 'bitbucket'); - } - return done(); - } else if (settingsErr) { - debug(settingsErr); - return done(); - } - }); - }); - } else { - done(); - } -} diff --git a/app/scripts/actions/navigate/githubRedirect.js b/app/scripts/actions/navigate/githubRedirect.js deleted file mode 100644 index d3878ee164..0000000000 --- a/app/scripts/actions/navigate/githubRedirect.js +++ /dev/null @@ -1,84 +0,0 @@ -'use strict'; - -import _ from 'lodash'; -import async from 'async'; -import { Builds } from 'hub-js-sdk'; -import request from 'superagent'; -var debug = require('debug')('navigate::githubRedirect'); -import GithubLinkStore from '../../stores/GithubLinkStore'; -import linkedAccountSettingsAction from './linkedAccountsSettings'; - -/** - * This action is hit when the site gets redirected from the github oauth workflow - * @param actionContext - * @param payload - * @param done - * @param maybeData - */ -export default function githubRedirect({actionContext, payload, done, maybeData}){ - - const SOURCES = { - GITHUB: 'github', - BITBUCKET: 'bitbucket' - }; - - debug('In Gihub Redirect Route Handler !'); - //If token is available the user is already logged in - var token; - if (_.has(maybeData, 'token')) { - token = maybeData.token; - var code = payload.location.query.code; - var state = payload.location.query.state; - - var _associateGithubAccount = function(cb) { - Builds.associateGithubAccount(token, code, function(err, res) { - if (err) { - debug(JSON.stringify(err)); - debug('ERROR ASSOCIATING GITHUB ACCOUNT: ' + err); - actionContext.dispatch('GITHUB_ASSOCIATE_ERROR', res.body); - cb(err); - } else { - if (res.body) { - debug('GitHub account association Success: ' + res.body); - actionContext.dispatch('GITHUB_ASSOCIATE_SUCCESS', res.body); - cb(null, res.body); - } - } - }); - }; - - var _getLinkedAccounts = function(callback) { - debug('Getting linked account settings state.'); - linkedAccountSettingsAction( - { - actionContext: actionContext, - payload: payload, - done: callback, - maybeData: maybeData - } - ); - }; - - debug('Payload Cookies: ' + payload.cookies); - //TODO: validate state before linking - if (payload.cookies && payload.cookies.ghOauthKey === state) { - async.series([ - _associateGithubAccount, - _getLinkedAccounts - ], function(err, results) { - request.post('/oauth/github-done/') - .end(function(e, r) { debug('github-oauth done or exited.'); }); - done(); - } - ); - } else { - //The validation of the state failed - actionContext.dispatch('GITHUB_SECURITY_ERROR', 'There was a security issue with your request. Please try again later.'); - done(); - } - } else { - token = ''; - actionContext.dispatch('GITHUB_ASSOCIATE_ERROR'); - done(); - } -} diff --git a/app/scripts/actions/navigate/githubUsersAndRepos.js b/app/scripts/actions/navigate/githubUsersAndRepos.js deleted file mode 100644 index da5bb49ded..0000000000 --- a/app/scripts/actions/navigate/githubUsersAndRepos.js +++ /dev/null @@ -1,48 +0,0 @@ -'use strict'; - -var debug = require('debug')('navigate::githubRepos'); -import async from 'async'; -import { - Builds - } from 'hub-js-sdk'; -import has from 'lodash/object/has'; -import linkedAccountAction from './linkedAccountsSettings'; - -export default function getGithubRepos({actionContext, payload, done, maybeData}) { - - var _getLinkedAccountStatus = function(cb) { - linkedAccountAction({ - actionContext: actionContext, - payload: payload, - done: cb, - maybeData: maybeData}); - }; - - var _getSourceRepos = function(cb) { - Builds.getSourceRepos('github', maybeData.token, function (err, res) { - if (err) { - const { detail } = err.response.body; - if (detail) { - actionContext.dispatch('LINKED_REPO_SOURCES_ERROR', detail); - } - cb(null); - } else{ - cb(null, res.body); - } - }); - }; - - - if (has(maybeData, 'token')) { - async.parallel([ - _getLinkedAccountStatus, - _getSourceRepos - ], function(err, results) { - actionContext.dispatch('SET_LINKED_REPO_TYPE', 'github'); - actionContext.dispatch('RECEIVE_LINKED_REPO_SOURCES', results[1]); - done(); - }); - } else { - done(); - } -} diff --git a/app/scripts/actions/navigate/home.js b/app/scripts/actions/navigate/home.js deleted file mode 100644 index 144c26efe9..0000000000 --- a/app/scripts/actions/navigate/home.js +++ /dev/null @@ -1,132 +0,0 @@ -'use strict'; -var debug = require('debug')('navigate::home'); -import async from 'async'; -import _ from 'lodash'; -import { - Repositories as Repos, - Notifications, - Orgs, - Users -} from 'hub-js-sdk'; - -export default function home({actionContext, payload, done, maybeData}){ - if (_.has(maybeData, 'token')) { - - //Get repos for user or org - var _getReposForUserOrOrg = function(cb, userType) { - var userOrOrgName = payload.params.user || maybeData.user.username; - actionContext.dispatch('DASHBOARD_REPOS_STORE_ATTEMPTING_GET_REPOS'); - Repos.getReposForUser(maybeData.token, userOrOrgName, function(err, res) { - if (err) { - actionContext.dispatch('ERROR_RECEIVING_REPOS'); - cb(); - } else { - actionContext.dispatch('RECEIVE_REPOS', res.body); - cb(); - } - }, payload.location.query.page); - }; - - //Get orgs for user - var _getOrgsForCurrentUser = function(cb) { - Users.getOrgsForUser(maybeData.token, function(err, res) { - if (err) { - debug(err); - cb(); - } else { - actionContext.dispatch('RECEIVE_DASHBOARD_NAMESPACES', { - orgs: res.body, - user: maybeData.user.username - }); - cb(); - } - }); - }; - - //Get user settings for private repo stats - var _getUserSettings = function(cb) { - Users.getUserSettings(maybeData.token, maybeData.user.username, function(err, res) { - if (err) { - debug(err); - cb(); - } else { - actionContext.dispatch('RECEIVE_PRIVATE_REPOSTATS', res.body); - cb(); - } - }); - }; - - var _doParallelCalls = function() { - async.parallel([ - _getReposForUserOrOrg, - _getOrgsForCurrentUser, - _getUserSettings - ], function(err, results) { - if (err) { - debug(err); - } - return done(); - }); - }; - - //Get Organization by name - var _getOrgByName = function() { - Orgs.getOrg(maybeData.token, payload.params.user, function(err, res) { - if (err) { - debug(err); - } else { - var org = res.body; - if (!_.isEmpty(org)) { - return org; - } - } - }); - return {}; - }; - - //Get user by name - var _getUserByName = function() { - Users.getUser(maybeData.token, payload.params.user, function(err, res) { - if (err) { - debug(err); - } else { - var user = res.body; - if (!_.isEmpty(user)) { - return user; - } - } - }); - return {}; - }; - - if (payload.params.user) { - if (payload.params.user === maybeData.user.username) { - actionContext.dispatch('CURRENT_USER_CONTEXT', { username: payload.params.user }); - _doParallelCalls(); - } else { - async.series([ - function (callback) { - callback(null, _getOrgByName(payload.params.user)); - }, - function (callback) { - callback(null, _getUserByName(payload.params.user)); - } - ], function (err, results) { - if (err) { - debug(err); - } else { - debug('Results of Series Call: ' + JSON.stringify(results)); - //User context is defined as `type`, `name` and `status flag` - actionContext.dispatch('CURRENT_USER_CONTEXT', {username: payload.params.user }); - _getReposForUserOrOrg(done); - } - }); - } - } else { - actionContext.dispatch('CURRENT_USER_CONTEXT', { username: maybeData.user.username }); - _doParallelCalls(); - } - } else { - done(); - } -} diff --git a/app/scripts/actions/navigate/licenses.js b/app/scripts/actions/navigate/licenses.js deleted file mode 100644 index 2735150419..0000000000 --- a/app/scripts/actions/navigate/licenses.js +++ /dev/null @@ -1,57 +0,0 @@ -'use strict'; -var debug = require('debug')('navigate::licenses'); -import async from 'async'; -import request from 'superagent'; -import _ from 'lodash'; -import { - Repositories as Repos, - Notifications, - Orgs, - Users -} from 'hub-js-sdk'; - -function getLicenses({ userID, token, actionContext}, done) { - request(process.env.REGISTRY_API_BASE_URL + '/api/licensing/v3/license/' + userID + '/') - .accept('application/json') - .set('Authorization', 'JWT ' + token) - .end((err, res) => { - if (err) { - done(null, null); - } else { - - let licenses = _.map(res.body.licenses, function(obj) { - return _.merge({}, - obj, - { - orgname: userID - }); - }); - done(null, licenses); - } - }); -} - -export default function licensesFn({ - actionContext, payload, done, maybeData -}){ - - if(maybeData.token) { - Users.getNamespacesForUser(maybeData.token, function(err, res){ - async.map(res.body.namespaces, - function(item, cb) { - getLicenses({ - userID: item, - token: maybeData.token, - actionContext - }, cb); - }, - function(error, results) { - actionContext.dispatch('RECEIVE_LICENSES', _.compact(results)); - done(); - }); - }); - } else { - // user must be logged in; they aren't - done(); - } -} diff --git a/app/scripts/actions/navigate/linkedAccountsSettings.js b/app/scripts/actions/navigate/linkedAccountsSettings.js deleted file mode 100644 index 5f93a8be21..0000000000 --- a/app/scripts/actions/navigate/linkedAccountsSettings.js +++ /dev/null @@ -1,118 +0,0 @@ -'use strict'; - -var debug = require('debug')('navigate::linkedAccounts'); -import async from 'async'; -import { - Builds - } from 'hub-js-sdk'; -import _ from 'lodash'; - -const SOURCES = { - GITHUB: 'github', - BITBUCKET: 'bitbucket' -}; - -export default function linked({actionContext, payload, done, maybeData}){ - if (_.has(maybeData, 'token')) { - - var _checkGithub = function(cb) { - Builds.checkGithub(maybeData.token, function(err, res) { - if(err) { - debug(err); - cb(null, false); - } else { - debug('Github account exists'); - cb(null, true); - } - }); - }; - - var _checkBitbucket = function(cb) { - Builds.checkBitbucket(maybeData.token, function(err, res) { - if(err) { - debug(err); - cb(null, false); - } else { - cb(null, true); - } - }); - }; - - var _getGithubAccount = function(accountExists, cb) { - if(accountExists) { - Builds.getSourceAccount(SOURCES.GITHUB, maybeData.token, function (err, res) { - if (err) { - cb(null, err); - } else { - cb(null, res.body); - } - }); - } else { - cb(null, {detail: 'No associated Github user'}); - } - }; - - var _getBitbucketAccount = function(accountExists, cb) { - if (accountExists) { - Builds.getSourceAccount(SOURCES.BITBUCKET, maybeData.token, function (err, res) { - if(err) { - cb(null, err); - } else { - cb(null, res.body); - } - }); - } else { - Builds.getBitbucketAuthUrl(maybeData.token, function(err, res) { - if (err) { - debug(err); - actionContext.dispatch('BITBUCKET_AUTH_URL_ERROR', err); - } else if (res.ok) { - actionContext.dispatch('RECEIVE_BITBUCKET_AUTH_URL', res.body); - } - }); - cb(null, {detail: 'No associated Bitbucket user'}); - } - }; - - var _wfGetGithubAccount = function(cb) { - async.waterfall([ - _checkGithub, - _getGithubAccount - ], function(err, result) { - debug('Github WF - result', result); - if (!err) { - cb(null, result); - } - }); - }; - - var _wfGetBitbucketAccount = function(cb) { - async.waterfall([ - _checkBitbucket, - _getBitbucketAccount - ], function(err, result) { - debug('Bitbucket WF - result', result); - if (!err) { - cb(null, result); - } - }); - }; - - //Check github and bitbucket and then get the account - async.parallel({ - _wfGetGithubAccount, - _wfGetBitbucketAccount - }, function(err, results) { - debug('results: ', results); - let accounts = { - github: results._wfGetGithubAccount, - bitbucket: results._wfGetBitbucketAccount, - gitlab: {detail: 'No associated GitLab user'} - }; - actionContext.dispatch('RECEIVE_SOURCE_ACCOUNTS', accounts); - return done(); - }); - } else { - done(); - } -} diff --git a/app/scripts/actions/navigate/notificationSettings.js b/app/scripts/actions/navigate/notificationSettings.js deleted file mode 100644 index 787ee68396..0000000000 --- a/app/scripts/actions/navigate/notificationSettings.js +++ /dev/null @@ -1,62 +0,0 @@ -'use strict'; -const debug = require('debug')('navigate::notificationSettings'); -import _ from 'lodash'; -import async from 'async'; -import { - Emails, Notifications - } from 'hub-js-sdk'; - -export default function notificationSettings({actionContext, payload, done, maybeData}){ - if (_.has(maybeData, 'token')) { - var {token, user} = maybeData; - async.parallel({ - subscriptions: function(callback) { - Emails.getEmailSubscriptions(token, user.username, function(err, res){ - if (err) { - debug(err); - callback(); - } else { - callback(null, res.body); - } - }); - }, - notifications: function(callback) { - Notifications.getNotificationSubscriptions(token, function(err, res) { - if (err) { - debug(err); - callback(); - } else { - callback(null, res.body.results); - } - }); - }, - emails: function(callback) { - Emails.getEmailsForUser(token, user.username, function(err, res){ - if (err) { - debug(err); - callback(); - } else { - let emails = res.body.results; - let sortedEmails = _.sortByOrder(emails, ['primary', 'verified'], [false, false]); - callback(null, sortedEmails); - } - }); - } - }, function(err, res) { - let {subscriptions, notifications, emails} = res; - var weeklyDigest, betaGroup; - if (subscriptions) { - weeklyDigest = subscriptions.DockerNewsMailingList; - betaGroup = subscriptions.DockerBetaGroupMailingList; - actionContext.dispatch('RECEIVE_EMAIL_SUBSCRIPTIONS', {weeklyDigest: weeklyDigest, betaGroup: betaGroup}); - } - if (notifications) { - actionContext.dispatch('RECEIVE_NOTIFICATIONS', notifications); - } - actionContext.dispatch('RECEIVE_EMAILS', {emails: emails}); - done(); - }); - } else { - done(); - } -} diff --git a/app/scripts/actions/navigate/orgBilling.js b/app/scripts/actions/navigate/orgBilling.js deleted file mode 100644 index d85e68da1d..0000000000 --- a/app/scripts/actions/navigate/orgBilling.js +++ /dev/null @@ -1,222 +0,0 @@ -'use strict'; - -const debug = require('debug')('navigate::OrgBilling'); -import async from 'async'; -import _ from 'lodash'; -import { - BILLFORWARD_ACCOUNT_ID -} from 'stores/common/Constants.js'; - -import { - Billing, - Users, - Orgs - } from 'hub-js-sdk'; - -function _getOrgPlans(token) { - return (callback) => { - Billing.getPlans(token, 'personal', (err, res) => { - if(err) { - debug(err); - callback(null, []); - } else { - let plansList = res.body; - let sortedPlans = _.sortBy(plansList, 'display_order'); - debug(sortedPlans); - callback(null, sortedPlans); - } - }); - }; -} - -function _getBillingSubscriptions(token, username) { - return (callback) => { - Billing.getBillingSubscriptions(token, username, (err, res) => { - if(!res || res.status === 500) { - debug('SERVER ISSUE: getting subscriptions'); - callback('SERVER ISSUE'); - } else if (err) { - callback(null, res.body); - } else { - debug('GET USER PLANS', res.body); - let subscriptions = res.body; - - // the assumption is that there is at most one subscription right now - let subscription = _.head(subscriptions); - callback(err, subscription); - } - }); - }; -} - -function _getBillingAccount(token, username) { - return (callback) => { - Billing.getBillingAccount(token, username, (err, res) => { - if(!res || res.status === 500) { - debug('SERVER ISSUE: getting billing account info'); - // NOTE: If this is a brand new billing account - set newBilling to true - callback(null, {account: { newBilling: true }}); - } else if (err) { - debug('NO BILLING ACCOUNT CONNECTED'); - // NOTE: If this is a brand new billing account - set newBilling to true - callback(null, {account: { newBilling: true }}); - } else { - debug('GET BILLING ACCOUNT', res.body); - const account = { ...res.body, newBilling: false }; - callback(err, { account, billforwardId: res.header[BILLFORWARD_ACCOUNT_ID] }); - } - }); - }; -} - -function _getBillingInfo(token, username) { - return (callback) => { - Billing.getBillingInfo(token, username, (err, res) => { - if(!res || res.status === 500) { - debug('SERVER ISSUE: getting billing info'); - // NOTE: If this is a brand new billing profile - set newBilling to true - callback(null, { newBilling: true }); - } else if (err) { - debug('NO BILLING INFO CONNECTED'); - // NOTE: If this is a brand new billing profile - set newBilling to true - callback(null, { newBilling: true }); - } else { - debug('GET BILLING INFO', res.body); - callback(err, { ...res.body, newBilling: false }); - } - }); - }; -} - -function _getBillingInvoices(token, username) { - return (callback) => { - Billing.getBillingInvoices(token, username, (err, res) => { - if(err) { - debug('NO BILLING ACCOUNT INVOICES'); - callback(null, []); - } else { - debug('GET BILLING INVOICES', res.body); - callback(err, res.body); - } - }); - }; -} - -//Get orgs for user -function _getOrgsForCurrentUser(token) { - return (callback) => { - Users.getOrgsForUser(token, function(err, res) { - if (err) { - debug(err); - callback(); - } else { - debug('GET Orgs for current User', res.body); - callback(null, res.body); - } - }); - }; -} - -//Get org's settings since we are in the organization's home -function _getOrgSettings(token, username) { - return (callback) => { - Orgs.getOrg(token, username, function (err, res) { - if (err) { - callback(); - } else { - debug('GET Orgs Settings', res.body); - callback(null, res.body); - } - }); - }; -} - -//Get user settings for private repo stats -var _getOrgPrivateRepoSettings = function(ac, token, username) { - return (cb) => { - Orgs.getOrgSettings(token, username, function (err, res) { - if (err) { - debug(err); - ac.dispatch('PRIVATE_REPOSTATS_NO_PERMISSIONS', err); - cb(null, err); - } else { - ac.dispatch('RECEIVE_PRIVATE_REPOSTATS', res.body); - cb(null, res.body); - } - }); - }; -}; - -var _getNamespaces = function(actionContext, token, profileuser) { - return (callback) => { - Users.getNamespacesForUser(token, function(err, res) { - if (err) { - callback(); - } else { - callback(null, res.body); - actionContext.dispatch('CREATE_REPO_RECEIVE_NAMESPACES', { - namespaces: res.body, - selectedNamespace: profileuser - }); - } - }); - }; -}; - -export default function billingOrgPlans({actionContext, payload, done, maybeData}){ - if (maybeData.token && maybeData.user) { - let {token, user} = maybeData; - let username = payload.params.user; - actionContext.dispatch('RESET_BILLING_PLANS'); - /* - NOTE: - None of the functions should pass an error into the callback or else it will - kill the rest of the calls and return before we're able to fetch all the data - */ - async.parallel({ - allPlans: _getOrgPlans(token), - userPlan: _getBillingSubscriptions(token, username), - accountInfo: _getBillingAccount(token, username), - billingInfo: _getBillingInfo(token, username), - invoiceList: _getBillingInvoices(token, username), - getOrgs: _getOrgsForCurrentUser(token), - getOrgSettings: _getOrgSettings(token, username), - getPrivateRepoStats: _getOrgPrivateRepoSettings(actionContext, token, username), - getNamespaces: _getNamespaces(actionContext, token, user.username) - }, function(err, results){ - const { - allPlans, - userPlan, - accountInfo, - billingInfo, - invoiceList, - getOrgs, - getOrgSettings - } = results; - debug('BILLING PLANS', results); - const gateway = accountInfo && accountInfo.account && accountInfo.account.payment_gateway; - const billforwardId = accountInfo && accountInfo.billforwardId; - - actionContext.dispatch('CURRENT_USER_CONTEXT', { username: username }); - actionContext.dispatch('RECEIVE_BILLING_PLANS', { - plansList: allPlans - }); - actionContext.dispatch('RECEIVE_BILLING_INFO', { - billingInfo: billingInfo, - accountInfo: accountInfo && accountInfo.account, - currentPlan: userPlan, - gateway, - billforwardId - }); - actionContext.dispatch('RECEIVE_INVOICES', {invoices: invoiceList}); - actionContext.dispatch('RECEIVE_DASHBOARD_NAMESPACES', { - orgs: getOrgs, - user: user.username - }); - actionContext.dispatch('RECEIVE_ORGANIZATION', getOrgSettings); - return done(); - }); - } else { - done(); - } -} diff --git a/app/scripts/actions/navigate/orgDashTeams.js b/app/scripts/actions/navigate/orgDashTeams.js deleted file mode 100644 index 41987a8e12..0000000000 --- a/app/scripts/actions/navigate/orgDashTeams.js +++ /dev/null @@ -1,146 +0,0 @@ -'use strict'; -var debug = require('debug')('navigate orgHome'); -import async from 'async'; -import _ from 'lodash'; -import { - Repositories as Repos, - Notifications, - Orgs, - Users -} from 'hub-js-sdk'; - -export default function home({actionContext, payload, done, maybeData}){ - if (_.has(maybeData, 'token')) { - const currentOrg = payload.params.user; - - //Get orgs for user - var _getOrgsForCurrentUser = function(cb) { - Users.getOrgsForUser(maybeData.token, function(err, res) { - if (err) { - debug(err); - cb(); - } else { - actionContext.dispatch('RECEIVE_DASHBOARD_NAMESPACES', { - orgs: res.body, - user: maybeData.user.username - }); - cb(); - } - }); - }; - - //Get user settings for private repo stats - var _getOrgPrivateRepoSettings = function(cb) { - Orgs.getOrgSettings(maybeData.token, currentOrg, function(err, res) { - if (err) { - debug(err); - actionContext.dispatch('PRIVATE_REPOSTATS_NO_PERMISSIONS', err); - actionContext.dispatch('TEAM_READ_ONLY', true); - cb(); - } else { - actionContext.dispatch('RECEIVE_PRIVATE_REPOSTATS', res.body); - actionContext.dispatch('TEAM_READ_ONLY', false); - cb(); - } - }); - }; - - //Get Teams for an org - var _getTeamsForOrg = function(cb) { - Orgs.getTeams(maybeData.token, currentOrg, function(err, res) { - if (err) { - debug(err); - cb(); - } else { - actionContext.dispatch('RECEIVE_DASHBOARD_ORG_TEAMS', res.body); - cb(); - } - }); - }; - - var _getNamespaces = function(cb) { - Users.getNamespacesForUser(maybeData.token, function(err, res) { - if (err) { - cb(); - } else { - cb(null, res.body); - actionContext.dispatch('CREATE_REPO_RECEIVE_NAMESPACES', { - namespaces: res.body, - selectedNamespace: maybeData.user.username - }); - } - }); - }; - - const currentTeam = payload.location.query.team; - var _getTeam = function(cb) { - if (currentTeam) { - Orgs.getTeam(maybeData.token, currentOrg, currentTeam, function(err, res) { - if (err) { - actionContext.dispatch('ORG_DASHBOARD_MEMBERS_ERROR', err); - cb(null, err); - } else { - actionContext.dispatch('RECEIVE_DASHBOARD_ORG_TEAM', res.body); - cb(null, res.body); - } - }); - } else { - cb(null, null); - } - }; - - var _getMembers = function(cb) { - if (currentTeam) { - Orgs.getMembers(maybeData.token, currentOrg, currentTeam, function(err, res) { - if (err) { - actionContext.dispatch('ORG_DASHBOARD_MEMBERS_ERROR', err); - cb(null, err); - } else { - actionContext.dispatch('RECEIVE_DASHBOARD_TEAM_MEMBERS', res.body); - cb(null, res.body); - } - }); - } else { - cb(null, null); - } - }; - - //This is executed only for the currently logged in user, so put in starred, contributed only here - var _doParallelCalls = function() { - async.parallel([ - _getOrgsForCurrentUser, - _getOrgPrivateRepoSettings, - _getTeamsForOrg, - _getNamespaces, - _getTeam, - _getMembers - ], function(err, results) { - if (err) { - debug(err); - } - return done(); - }); - }; - - //Get Organization by name - var _getOrgByName = function(name, cb) { - Orgs.getOrg(maybeData.token, name, function(err, res) { - if (err) { - debug(err); - cb({}); - } else { - var org = res.body; - cb(org); - } - }); - }; - - actionContext.dispatch('CURRENT_USER_CONTEXT', { - username: payload.params.user - }); - _doParallelCalls(); - - } else { - done(); - } -} diff --git a/app/scripts/actions/navigate/orgHome.js b/app/scripts/actions/navigate/orgHome.js deleted file mode 100644 index dc2a9bd106..0000000000 --- a/app/scripts/actions/navigate/orgHome.js +++ /dev/null @@ -1,143 +0,0 @@ -'use strict'; -var debug = require('debug')('navigate orgHome'); -import async from 'async'; -import _ from 'lodash'; -import { - Repositories as Repos, - Notifications, - Orgs, - Users -} from 'hub-js-sdk'; - -export default function home({actionContext, payload, done, maybeData}){ - if (_.has(maybeData, 'token')) { - - //Get repos for user or org - var _getReposForUserOrOrg = function(cb, userType) { - actionContext.dispatch('DASHBOARD_REPOS_STORE_ATTEMPTING_GET_REPOS'); - Repos.getReposForUser(maybeData.token, payload.params.user, function(err, res) { - if (err) { - actionContext.dispatch('ERROR_RECEIVING_REPOS'); - cb(); - } else { - actionContext.dispatch('RECEIVE_REPOS', res.body); - cb(); - } - }, payload.location.query.page); - }; - - //Get contributed repos - var _getReposByFilterTypeContrib = function(cb) { - var username = maybeData.user.username; - Repos.getContributedReposForUser(maybeData.token, username, function (err, res) { - if (err) { - cb(); - } else { - var resultPayload = {type: 'contrib', results: res.body.results}; - actionContext.dispatch('RECEIVE_CONTRIB', resultPayload); - cb(); - } - }); - }; - - //Get orgs for user - var _getOrgsForCurrentUser = function(cb) { - Users.getOrgsForUser(maybeData.token, function(err, res) { - if (err) { - debug(err); - cb(); - } else { - actionContext.dispatch('RECEIVE_DASHBOARD_NAMESPACES', { - orgs: res.body, - user: maybeData.user.username - }); - cb(); - } - }); - }; - - //Get user settings for private repo stats - var _getOrgPrivateRepoSettings = function(cb) { - Orgs.getOrgSettings(maybeData.token, payload.params.user, function(err, res) { - if (err) { - debug(err); - actionContext.dispatch('PRIVATE_REPOSTATS_NO_PERMISSIONS', err); - actionContext.dispatch('TEAM_READ_ONLY', true); - cb(); - } else { - actionContext.dispatch('RECEIVE_PRIVATE_REPOSTATS', res.body); - actionContext.dispatch('TEAM_READ_ONLY', false); - cb(); - } - }); - }; - - //Get org's settings since we are in the organization's home - var _getOrgSettings = function(cb) { - Orgs.getOrg(maybeData.token, payload.params.user, function (err, res) { - if (err) { - cb(); - } else { - actionContext.dispatch('RECEIVE_ORGANIZATION', res.body); - cb(); - } - }); - }; - - var _getNamespaces = function(cb) { - Users.getNamespacesForUser(maybeData.token, function(err, res) { - if (err) { - cb(); - } else { - cb(null, res.body); - actionContext.dispatch('CREATE_REPO_RECEIVE_NAMESPACES', { - namespaces: res.body, - selectedNamespace: maybeData.user.username - }); - } - }); - }; - - //This is executed only for the currently logged in user, so put in starred, contributed only here - var _doParallelCalls = function() { - async.parallel([ - _getReposForUserOrOrg, - _getOrgsForCurrentUser, - _getReposByFilterTypeContrib, - _getOrgSettings, - _getOrgPrivateRepoSettings, - _getNamespaces - ], function(err, results) { - if (err) { - debug(err); - } - return done(); - }); - }; - - //Get Organization by name - var _getOrgByName = function(name, cb) { - Orgs.getOrg(maybeData.token, name, function(err, res) { - if (err) { - debug(err); - cb({}); - } else { - var org = res.body; - cb(org); - } - }); - }; - - if (payload.params.user) { - actionContext.dispatch('CURRENT_USER_CONTEXT', { username: payload.params.user }); - _doParallelCalls(); - } else { - debug('mark 5'); - actionContext.dispatch('CURRENT_USER_CONTEXT', { username: payload.params.user }); - _doParallelCalls(); - } - } else { - debug('mark 6'); - done(); - } -} diff --git a/app/scripts/actions/navigate/orgSettings.js b/app/scripts/actions/navigate/orgSettings.js deleted file mode 100644 index e0ff148a60..0000000000 --- a/app/scripts/actions/navigate/orgSettings.js +++ /dev/null @@ -1,66 +0,0 @@ -'use strict'; - -import _ from 'lodash'; -import { - Users - } from 'hub-js-sdk'; -import async from 'async'; -var debug = require('debug')('navigate::orgSettings'); - -export default function orgs({actionContext, payload, done, maybeData}){ - debug('Organization Settings Navigate Token -> ' + maybeData.token); - debug('ORG SETTINGS PAYLOAD', payload); - let orgName = payload.params.user; - if (_.has(maybeData, 'token')) { - async.parallel({ - getOrgs: function(callback) { - Users.getOrgsForUser(maybeData.token, function(getErr, getRes) { - if (getErr) { - debug(getErr); - callback(); - } else { - actionContext.dispatch('RECEIVE_DASHBOARD_NAMESPACES', { - orgs: getRes.body, - user: maybeData.user.username - }); - actionContext.dispatch('CURRENT_USER_ORGS', getRes.body); - actionContext.dispatch('SELECT_ORGANIZATION', orgName); - actionContext.dispatch('CURRENT_USER_CONTEXT', { username: orgName }); - callback(null, getRes.body); - } - }); - }, - getUserSettings: function(callback) { - let username = payload.params.user; - Users.getUserSettings(maybeData.token, username, function(getErr, getRes) { - if (getErr){ - debug(getErr); - callback(); - } else { - let is_private = (getRes.default_repo_visibility); - actionContext.dispatch('CREATE_REPO_UPDATE_FIELD_WITH_VALUE', {fieldKey: 'is_private', fieldValue: is_private}); - actionContext.dispatch('RECEIVE_PRIVATE_REPOSTATS', getRes.body); - callback(null, getRes.body); - } - }); - }, - getNamespaces: function(callback) { - Users.getNamespacesForUser(maybeData.token, function(err, res) { - if (err) { - callback(); - } else { - callback(null, res.body); - actionContext.dispatch('CREATE_REPO_RECEIVE_NAMESPACES', { - namespaces: res.body, - selectedNamespace: maybeData.user.username - }); - } - }); - } - }, function(err, res){ - done(); - }); - } else { - done(); - } -} diff --git a/app/scripts/actions/navigate/orgSummary.js b/app/scripts/actions/navigate/orgSummary.js deleted file mode 100644 index e385c69e4a..0000000000 --- a/app/scripts/actions/navigate/orgSummary.js +++ /dev/null @@ -1,24 +0,0 @@ -'use strict'; - -import _ from 'lodash'; -import { - Users - } from 'hub-js-sdk'; -var debug = require('debug')('navigate::orgSummary'); - -export default function orgs({actionContext, payload, done, maybeData}){ - debug('Organization Settings Navigate Token -> ' + maybeData.token); - if (_.has(maybeData, 'token')) { - Users.getOrgsForUser(maybeData.token, function(err, res) { - if (err) { - debug(err); - done(); - } else { - actionContext.dispatch('CURRENT_USER_ORGS', res.body); - done(); - } - }); - } else { - done(); - } -} diff --git a/app/scripts/actions/navigate/repo.js b/app/scripts/actions/navigate/repo.js deleted file mode 100644 index 6680ef4b72..0000000000 --- a/app/scripts/actions/navigate/repo.js +++ /dev/null @@ -1,100 +0,0 @@ -'use strict'; - -import _ from 'lodash'; -import async from 'async'; -import { PENDING_DELETE } from 'common/enums/RepoStatus'; -import { - Repositories as Repos, - Autobuilds -} from 'hub-js-sdk'; - -export default function repo({actionContext, payload, done, maybeData}){ - var token; - if (_.has(maybeData, 'token')) { - token = maybeData.token; - } else { - token = ''; - } - - var namespace = payload.params.user; - if(payload.params.user === '_') { - namespace = 'library'; - } - var repoShortName = namespace + '/' + payload.params.splat; - - //1. Get repository details - //2. If successful, set valid repo and pass it along for the next set of calls - //3. If not valid, set repo to be not valid and dispatch repo not found - var _getRepo = function(cb) { - Repos.getRepo(token, repoShortName, function(err, res) { - var repoInfo = {}; - let status; - if (res && res.body) { - status = res.body.status; - } - - if (err || status === PENDING_DELETE) { - repoInfo.error = err; - repoInfo.isValid = false; - cb(null, repoInfo); - actionContext.dispatch('REPO_NOT_FOUND', err); - } else { - repoInfo.info = res.body; - actionContext.dispatch('RECEIVE_REPOSITORY', res.body); - repoInfo.isValid = true; - cb(null, repoInfo); - } - }); - }; - - var _getRepoDetails = function(repoInfo, cb) { - if (repoInfo.isValid) { - async.parallel([ - function(callback) { - Repos.getCommentsForRepo(token, repoShortName, function(err, res) { - if (err) { - callback(err); - } else { - callback(null, res.body); - } - }, 1); - }, function(callback) { - if (repoInfo.info.is_automated) { - Autobuilds.getAutomatedBuildSettings(token, namespace, payload.params.splat, function (err, res) { - if (err) { - actionContext.dispatch('AUTOBUILD_REPO_NOT_FOUND'); - callback(null); - } else { - callback(null, res.body); - } - }); - } else { - callback(null); - } - } - ], - function(error, results) { - if (error) { - cb(error); - } else { - cb(null, results); - } - }); - } else { - cb('repo not found'); - } - }; - - async.waterfall([ - _getRepo, - _getRepoDetails - ], function(e, finalResults) { - if (finalResults) { - actionContext.dispatch('RECEIVE_REPO_COMMENTS', finalResults[0]); - if (finalResults[1]) { - actionContext.dispatch('RECEIVE_AUTOBUILD_SETTINGS', finalResults[1]); - } - } - done(); - }); -} diff --git a/app/scripts/actions/navigate/repoDetailsScannedTag.js b/app/scripts/actions/navigate/repoDetailsScannedTag.js deleted file mode 100644 index dd7e9803d4..0000000000 --- a/app/scripts/actions/navigate/repoDetailsScannedTag.js +++ /dev/null @@ -1,114 +0,0 @@ -'use strict'; - -import { parallel } from 'async'; -import { PENDING_DELETE } from 'common/enums/RepoStatus'; -import has from 'lodash/object/has'; -import merge from 'lodash/object/merge'; -import { Repositories as Repos } from 'hub-js-sdk'; -import { - RECEIVE_REPO, - RECEIVE_SCANNED_TAG_DATA, - ERROR -} from 'reduxConsts'; -const debug = require('debug')('navigate::repoDetailsScannedTagData'); -import request from 'superagent'; -import { normalize, arrayOf } from 'normalizr'; -import { scan } from 'normalizers'; - -const getRepo = ({maybeToken, actionContext, user, splat}) => (callback) => { - Repos.getRepo(maybeToken, `${user}/${splat}`, function(err, res) { - let status; - if (res && res.body) { - status = res.body.status; - } - - if (err || status === PENDING_DELETE) { - actionContext.dispatch('REPO_NOT_FOUND', err); - return callback(err); - } else { - return callback(null, res.body); - } - }); -}; - -/* - * Get nautilus scan info for the tag. - * TODO: Once this API is in it's final form for the jan release, move it to the SDK - */ -const getScanForTag = ({actionContext, maybeToken, payload, user, splat, tagname, done}) => (callback) => { - const namespace = user; - const name = splat; - const req = request.get(`${process.env.NAUTILUS_API_BASE_URL}/repositories/result?namespace=${namespace}&reponame=${name}&tag=${tagname}&detailed=1`); - if (maybeToken) { - req.set('Authorization', 'JWT ' + maybeToken); - } - req.timeout(7000); - req.end((err, res) => { - if (err) { - // NOTE: Suffixing the dispatch type with _STATUS means the status - // reducer will record this in the same way as our SDK calls - // via the middleware. - // When we move this to the SDK, the error will be dispatched automatically - actionContext.reduxStore.dispatch({ - type: `${RECEIVE_SCANNED_TAG_DATA}_STATUS`, - payload: { - status: ERROR, - statusKey: ['getScanForTag', namespace, name, tagname], - error: err - }, - error: true - }); - return callback(err); - } else { - // The API response contains a 'scan' resource within an object - // inside 'scan_details' - const { scan_details, image: { reponame, tag } } = res.body; - const { latest_scan_status } = res.body; - const result = { latest_scan_status, reponame, tag, ...scan_details }; - const normalized = normalize(result, scan); - return callback(null, normalized); - } - }); -}; - -export default function repoDetailsScannedTag({actionContext, payload, done, maybeData}){ - let token = ''; - if (has(maybeData, 'token')) { - token = maybeData.token; - } - const args = { - actionContext, - maybeToken: token, - user: payload.params.user, - splat: payload.params.splat, - tagname: payload.params.tagname - }; - - parallel({ - repo: getRepo(args), - tagScan: getScanForTag(args) - }, function(err, res){ - if (err) { - actionContext.dispatch('REPO_NOT_FOUND', err); - } else { - const { repo, tagScan } = res; - /* REPOS */ - //required for repository page header to display - actionContext.dispatch('RECEIVE_REPOSITORY', repo); - // We also need to dispatch to Redux; this will store the current repo - // within the repos reducer allowing us to find the namespace and repo - // name for the current route. - actionContext.reduxStore.dispatch({ - type: RECEIVE_REPO, - payload: repo - }); - - /* SCANS */ - actionContext.reduxStore.dispatch({ - type: RECEIVE_SCANNED_TAG_DATA, - payload: tagScan - }); - } - done(); - }); -} diff --git a/app/scripts/actions/navigate/repoDetailsTags.js b/app/scripts/actions/navigate/repoDetailsTags.js deleted file mode 100644 index 576505e142..0000000000 --- a/app/scripts/actions/navigate/repoDetailsTags.js +++ /dev/null @@ -1,147 +0,0 @@ -'use strict'; -const debug = require('debug')('navigate::repo'); -import { parallel } from 'async'; -import { PENDING_DELETE } from 'common/enums/RepoStatus'; -import has from 'lodash/object/has'; -import merge from 'lodash/object/merge'; -import request from 'superagent'; -import { - RECEIVE_NAUTILUS_TAGS_FOR_REPOSITORY, - RECEIVE_TAGS_FOR_REPOSITORY, - RECEIVE_REPO -} from 'reduxConsts.js'; -import { normalize, arrayOf } from 'normalizr'; -import { tag } from 'normalizers'; -import { - Repositories as Repos -} from 'hub-js-sdk'; - -const getRepo = ({maybeToken, actionContext, user, splat}) => (callback) => { - Repos.getRepo(maybeToken, `${user}/${splat}`, function(err, res) { - let status; - if (res && res.body) { - status = res.body.status; - } - - if (err || status === PENDING_DELETE) { - return callback(err); - } else { - return callback(null, res.body); - } - }); -}; - -// getTagsForRepo uses the hub API for loading tag information. This is used to -// show information about tags that are not scanned. -// -// We use this and the nautilus API because each API has incomplete information: -// - The nautilus API has vulnerability information -// - This API has the image size -// -// NOTE: This dispatches to Redux reducers and fluxible stores in the final callback -const getTagsForRepo = ({actionContext, maybeToken, user, splat}) => (callback) => { - const namespace = user; - const reponame = splat; - Repos.getTagsForRepo(maybeToken, `${user}/${splat}`, function(err, res) { - if (err) { - return callback(err); - } - const { results } = res.body; - // TODO: Assert normalize works as expected via jest/mocha - const tags = normalize(results, arrayOf(tag)); - return callback(null, { namespace, reponame, tags }); - }); -}; - -// getNautilusTagsForRepo uses the nautilus API to load tags and their -// vulnerability information via the nautilus API. -// -// NOTE: This dispatches to Redux reducers, not fluxible stores -const getNautilusTagsForRepo = ({actionContext, maybeToken, user, splat}) => (callback) => { - const namespace = user; - const reponame = splat; - const req = request.get(`${process.env.NAUTILUS_API_BASE_URL}/repositories/summaries/${namespace}/${reponame}`); - if (maybeToken) { - req.set('Authorization', 'JWT ' + maybeToken); - } - req.timeout(7000); - req.end((err, res) => { - if (err) { - // Nautilus call does NOT trigger an error page - return callback(null, null); - } - // TODO: Assert normalize works as expected via jest/mocha - const tags = normalize( - res.body, - arrayOf(tag), - { - // TODO: Add records - // NOTE: The nautius API uses a field called 'tag' to represent the - // tag name, whereas the HUB api uses 'name'. - // - // Our record, frontend code and normalizr key expects us to use - // the 'name' field. This normalizes the record to tag. - assignEntity: (obj, key, val) => { - obj[key] = val; - if (key === 'tag') { - obj.name = val; - delete obj.tag; - } - } - } - ); - return callback(null, { namespace, reponame, tags }); - }); -}; - -export default function repoDetailsTags({actionContext, payload, done, maybeData}) { - debug('maybeData:', maybeData); - let token = ''; - if (has(maybeData, 'token')) { - token = maybeData.token; - } - const { user, splat } = payload.params; - const args = { - actionContext, - maybeToken: token, - user, - splat - }; - - parallel({ - repo: getRepo(args), - tags: getTagsForRepo(args), - scans: getNautilusTagsForRepo(args) - }, (err, res) => { - if (err) { - // Tags or repo error - actionContext.dispatch('REPO_NOT_FOUND', err); - } else { - const { repo, tags, scans } = res; - /* REPO */ - actionContext.dispatch('RECEIVE_REPOSITORY', repo); - // We also need to dispatch to Redux; this will store the current repo - // within the repos reducer allowing us to find the namespace and repo - // name for the current route. - actionContext.reduxStore.dispatch({ - type: RECEIVE_REPO, - payload: repo - }); - - /* TAGS */ - actionContext.reduxStore.dispatch({ - type: RECEIVE_TAGS_FOR_REPOSITORY, - payload: tags - }); - - /* SCANS */ - if (scans) { - actionContext.reduxStore.dispatch({ - type: RECEIVE_NAUTILUS_TAGS_FOR_REPOSITORY, - payload: scans - }); - } - } - done(); - }); -} diff --git a/app/scripts/actions/navigate/repoOfficial.js b/app/scripts/actions/navigate/repoOfficial.js deleted file mode 100644 index 9fcf0e3dba..0000000000 --- a/app/scripts/actions/navigate/repoOfficial.js +++ /dev/null @@ -1,48 +0,0 @@ -'use strict'; - -import _ from 'lodash'; -import async from 'async'; -import { PENDING_DELETE } from 'common/enums/RepoStatus'; -import { - Repositories as Repos -} from 'hub-js-sdk'; - -export default function repo({actionContext, payload, done, maybeData}){ - var token; - if (_.has(maybeData, 'token')) { - token = maybeData.token; - } else { - token = ''; - } - var repoShortName = 'library/' + payload.params.splat; - async.series([ - function(callback) { - Repos.getRepo(token, repoShortName, function(err, res) { - let status; - if (res && res.body) { - status = res.body.status; - } - - if (err || status === PENDING_DELETE) { - actionContext.dispatch('REPO_NOT_FOUND', err); - callback(err); - } else { - actionContext.dispatch('RECEIVE_REPOSITORY', res.body); - callback(null, res.body); - } - }); - }, function(callback) { - Repos.getCommentsForRepo(token, repoShortName, function(err, res) { - if (err) { - callback(err); - } else { - actionContext.dispatch('RECEIVE_REPO_COMMENTS', res.body); - callback(null, res.body); - } - }); - } - ], - function(error, results) { - done(); - }); -} diff --git a/app/scripts/actions/navigate/repoSettings.js b/app/scripts/actions/navigate/repoSettings.js deleted file mode 100644 index 0af30fd929..0000000000 --- a/app/scripts/actions/navigate/repoSettings.js +++ /dev/null @@ -1,67 +0,0 @@ -'use strict'; -const debug = require('debug')('navigate::repo'); -import { parallel, waterfall } from 'async'; -import { PENDING_DELETE } from 'common/enums/RepoStatus'; -import _ from 'lodash'; -import { - Repositories as Repos, - Users -} from 'hub-js-sdk'; - -function getRepo({maybeToken, actionContext, user, splat}) { - return function(callback){ - Repos.getRepo(maybeToken, `${user}/${splat}`, function(err, res) { - let status; - if (res && res.body) { - status = res.body.status; - } - - if (err || status === PENDING_DELETE) { - actionContext.dispatch('REPO_NOT_FOUND', res.body); - return callback(null, null); - } else { - actionContext.dispatch('RECEIVE_REPOSITORY', res.body); - return callback(null, res.body); - } - }); - }; -} - -function handleGetPrivateRepoStats({maybeToken, user, actionContext}) { - return function(repoDetails, callback) { - if (repoDetails) { - Users.getUserSettings(maybeToken, user, function (err, res) { - if (err) { - callback(); - } else { - actionContext.dispatch('RECEIVE_PRIVATE_REPOSTATS', res.body); - callback(); - } - }); - } else { - callback(null, null); - } - }; -} - -export default function repoSettingsMain({actionContext, payload, done, maybeData}){ - debug('maybeData:', maybeData); - if (_.has(maybeData, 'token')) { - let args = { - actionContext, - maybeToken: maybeData.token, - user: payload.params.user, - splat: payload.params.splat - }; - - waterfall([ - getRepo(args), - handleGetPrivateRepoStats(args) - ], function(err, res){ - done(); - }); - } else { - actionContext.dispatch('REPO_NOT_FOUND', null); - done(); - } -} diff --git a/app/scripts/actions/navigate/repoSettingsCollaborators.js b/app/scripts/actions/navigate/repoSettingsCollaborators.js deleted file mode 100644 index d6b5878d91..0000000000 --- a/app/scripts/actions/navigate/repoSettingsCollaborators.js +++ /dev/null @@ -1,97 +0,0 @@ -'use strict'; -const debug = require('debug')('navigate::repo'); -import { parallel } from 'async'; -import { PENDING_DELETE } from 'common/enums/RepoStatus'; -import _ from 'lodash'; -import { - Repositories as Repos, - Orgs -} from 'hub-js-sdk'; - -function getRepo({maybeToken, actionContext, user, splat}) { - return function(callback){ - Repos.getRepo(maybeToken, `${user}/${splat}`, function(err, res) { - let status; - if (res && res.body) { - status = res.body.status; - } - - if (err || status === PENDING_DELETE) { - actionContext.dispatch('REPO_NOT_FOUND', null); - return callback(err); - } - actionContext.dispatch('RECEIVE_REPOSITORY', res.body); - return callback(); - }); -}; -} - -// GET's the collaborators for a user repo (which should be individuals) -function getCollaborators({maybeToken, actionContext, user, splat}) { - return function(cb) { - Repos.getCollaboratorsForRepo(maybeToken, `${user}/${splat}`, (err, res) => { - if(err) { - // 'Org repositories do not have collaborators.' - actionContext.dispatch('COLLAB_RECEIVE_COLLABORATORS', {}); - } else { - actionContext.dispatch('COLLAB_RECEIVE_COLLABORATORS', res.body); - } - cb(); - }); - }; -} - - //GET's the collaborators for an organization repo (which should be teams) -function getTeamCollaborators({maybeToken, actionContext, user, splat}) { - return function(cb) { - Repos.getTeamCollaboratorsForRepo(maybeToken, `${user}/${splat}`, (err, res) => { - if (err) { - // 'User repository does not have any teams yet' - actionContext.dispatch('COLLAB_RECEIVE_TEAMS', {}); - } else { - actionContext.dispatch('COLLAB_RECEIVE_TEAMS', res.body); - } - cb(); - }); - }; -} - -// GET's all teams for the organization -function getOrgTeams({maybeToken, actionContext, user, splat}) { - return function(cb) { - Orgs.getTeams(maybeToken, user, (err, res) => { - if (err) { - // 'No such organization' - actionContext.dispatch('COLLAB_RECEIVE_TEAMS', {}); - actionContext.dispatch('COLLAB_RECEIVE_ALL_TEAMS', {results: []}); - } else { - actionContext.dispatch('COLLAB_RECEIVE_ALL_TEAMS', res.body); - } - cb(); - }); - }; -} - -export default function repoSettingsMain({actionContext, payload, done, maybeData}){ - debug('maybeData:', maybeData); - if (_.has(maybeData, 'token')) { - let args = { - actionContext, - maybeToken: maybeData.token, - user: payload.params.user, - splat: payload.params.splat - }; - - parallel([ - getRepo(args), - getCollaborators(args), - getTeamCollaborators(args), - getOrgTeams(args) - ], function(err, res){ - done(); - }); - } else { - actionContext.dispatch('REPO_NOT_FOUND', null); - done(); - } -} diff --git a/app/scripts/actions/navigate/resetPass.js b/app/scripts/actions/navigate/resetPass.js deleted file mode 100644 index fa68db137a..0000000000 --- a/app/scripts/actions/navigate/resetPass.js +++ /dev/null @@ -1,6 +0,0 @@ -'use strict'; - -export default function resetPass({actionContext, payload, done, maybeData}){ - actionContext.dispatch('CHANGE_PASS_CLEAR'); - done(); -} diff --git a/app/scripts/actions/navigate/search.js b/app/scripts/actions/navigate/search.js deleted file mode 100644 index d0652a2ce4..0000000000 --- a/app/scripts/actions/navigate/search.js +++ /dev/null @@ -1,44 +0,0 @@ -'use strict'; -var debug = require('debug')('navigate::search'); - -import { - Search -} from 'hub-js-sdk'; - -export default function search({actionContext, payload, done, maybeData}){ - debug('Hit /search:: Query = ' + JSON.stringify(payload.location.query)); - debug('Searching for: ' + payload.location.query.q); - //the filter param values are `0` because the python api accepts either `0` or `False`, we decided to use `0` - var searchQueryParams = { - query: payload.location.query.q || '', - page: payload.location.query.page || '', - isAutomated: payload.location.query.isAutomated || 0, - isOfficial: payload.location.query.isOfficial || 0, - starCount: payload.location.query.starCount || 0, - pullCount: payload.location.query.pullCount || 0 - }; - - //TODO: Maybe we should have a single dispatch here? - actionContext.dispatch('SUBMIT_SEARCH_QUERY', searchQueryParams.query); - actionContext.dispatch('UPDATE_SEARCH_PAGE', searchQueryParams.page); - actionContext.dispatch('UPDATE_SEARCH_OTHERFILTERS', searchQueryParams); - - //This is to search repositories - Search.searchRepos(maybeData.token, searchQueryParams, function(err, res) { - if (err) { - debug(err); - actionContext.dispatch('SEARCH_ERROR', err); - done(); - } else { - debug(res); - var queryResult = res.body; - //Query Result details (for paging) - if (queryResult) { - actionContext.dispatch('PROCESS_SEARCH_RESULTS', queryResult); - done(); - } else { - done(); - } - } - }); -} diff --git a/app/scripts/actions/navigate/serverBilling.js b/app/scripts/actions/navigate/serverBilling.js deleted file mode 100644 index 00f6fcfb78..0000000000 --- a/app/scripts/actions/navigate/serverBilling.js +++ /dev/null @@ -1,31 +0,0 @@ -'use strict'; -var debug = require('debug')('navigate::home'); -import async from 'async'; -import _ from 'lodash'; -import { - Users -} from 'hub-js-sdk'; - -export default function enterpriseTrial({actionContext, payload, done, maybeData}){ - - if(payload.location.query.partnervalue) { - actionContext.dispatch('ENTERPRISE_PARTNER_RECEIVE_CODE', { - code: payload.location.query.partnervalue - }); - } - - if(_.has(maybeData, 'token')){ - Users.getNamespacesForUser(maybeData.token, function(err, res) { - if (err) { - done(); - } else { - if(res.body && res.body.namespaces) { - actionContext.dispatch('ENTERPRISE_PAID_RECEIVE_ORGS', res.body.namespaces); - } - done(); - } - }); - } else { - done(); - } -} diff --git a/app/scripts/actions/navigate/serverTrial.js b/app/scripts/actions/navigate/serverTrial.js deleted file mode 100644 index 7aae21f284..0000000000 --- a/app/scripts/actions/navigate/serverTrial.js +++ /dev/null @@ -1,31 +0,0 @@ -'use strict'; -var debug = require('debug')('navigate::home'); -import async from 'async'; -import _ from 'lodash'; -import { - Users -} from 'hub-js-sdk'; - -export default function enterpriseTrial({actionContext, payload, done, maybeData}){ - - if(payload.location.query.partnervalue) { - actionContext.dispatch('ENTERPRISE_PARTNER_RECEIVE_CODE', { - code: payload.location.query.partnervalue - }); - } - - if(_.has(maybeData, 'token')){ - Users.getNamespacesForUser(maybeData.token, function(err, res) { - if (err) { - done(); - } else { - if(res.body && res.body.namespaces) { - actionContext.dispatch('ENTERPRISE_TRIAL_RECEIVE_ORGS', res.body.namespaces); - } - done(); - } - }); - } else { - done(); - } -} diff --git a/app/scripts/actions/navigate/serverTrialSuccess.js b/app/scripts/actions/navigate/serverTrialSuccess.js deleted file mode 100644 index 6c4bc1f200..0000000000 --- a/app/scripts/actions/navigate/serverTrialSuccess.js +++ /dev/null @@ -1,39 +0,0 @@ -'use strict'; -const debug = require('debug')('navigate::serverTrialSuccess'); -import merge from 'lodash/object/merge'; -import find from 'lodash/collection/find'; -import { Billing } from 'hub-js-sdk'; - -export default function serverTrialSuccess({ - actionContext, payload, done, maybeData -}){ - const { namespace } = payload.location.query; - if(maybeData.token) { - Billing.getLicensesForNamespace(maybeData.token, { namespace }, (err, res) => { - if (err) { - debug(err); - if(err.response.badRequest) { - const { detail } = err.response.body; - if(detail) { - actionContext.dispatch('RECEIVE_TRIAL_LICENSE_BAD_REQUEST', detail); - } - } else { - actionContext.dispatch('RECEIVE_TRIAL_LICENSE_FACEPALM', err); - } - done(); - } else { - let license = find(res.body.licenses, (obj) => { - return obj.tier === 'Trial' || obj.alias === 'Trial'; - }); - license = merge({}, license, { namespace }); - actionContext.dispatch('RECEIVE_TRIAL_LICENSE', license); - done(); - } - }); - } else { - // user must be logged in; they aren't - const err = `You must be logged in to access your trial license`; - actionContext.dispatch('RECEIVE_TRIAL_LICENSE_BAD_REQUEST', err); - done(); - } -} diff --git a/app/scripts/actions/navigate/toOrg.js b/app/scripts/actions/navigate/toOrg.js deleted file mode 100644 index f1497b3af1..0000000000 --- a/app/scripts/actions/navigate/toOrg.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; -var debug = require('debug')('navigate::toOrg'); - -export default function updateOrgOwner({actionContext, payload, done, maybeData}){ - actionContext.dispatch('UPDATE_TO_ORG_OWNER', {owner: ''}); - done(); -} diff --git a/app/scripts/actions/navigate/user.js b/app/scripts/actions/navigate/user.js deleted file mode 100644 index 8dfe8eea64..0000000000 --- a/app/scripts/actions/navigate/user.js +++ /dev/null @@ -1,58 +0,0 @@ -'use strict'; -var debug = require('debug')('navigate::home'); -import async from 'async'; -import _ from 'lodash'; -import { - Repositories as Repos, - Users -} from 'hub-js-sdk'; - -export default function home({actionContext, payload, done, maybeData}){ - // This works without a jwt - var token = null; - - if (_.has(maybeData, 'token')) { - token = maybeData.token; - } - - //Get repos for user or org - var _getReposForUser = function(cb) { - actionContext.dispatch('DASHBOARD_REPOS_STORE_ATTEMPTING_GET_REPOS'); - Repos.getReposForUser(token, payload.params.user, function(err, res) { - if (err) { - cb(); - } else { - actionContext.dispatch('RECEIVE_PROFILE_REPOS', res.body); - cb(); - } - }, payload.location.query.page); - }; - - var _getUserByName = function(cb) { - Users.getUser(token, payload.params.user, function(err, res) { - if (err) { - if(res && res.notFound) { - actionContext.dispatch('USER_PROFILE_404'); - cb(err, null); - } else { - debug(err); - cb(); - } - } else { - actionContext.dispatch('RECEIVE_PROFILE_USER', res.body); - cb(); - } - }); - }; - - //Get user by name - async.parallel([ - _getReposForUser, - _getUserByName - ], function(err, results) { - if (err) { - debug(err); - } - return done(); - }); -} diff --git a/app/scripts/actions/navigate/userStars.js b/app/scripts/actions/navigate/userStars.js deleted file mode 100644 index 4e5e1d8f42..0000000000 --- a/app/scripts/actions/navigate/userStars.js +++ /dev/null @@ -1,57 +0,0 @@ -'use strict'; -var debug = require('debug')('navigate::userStars'); -import async from 'async'; -import _ from 'lodash'; -import { - Repositories as Repos, - Users -} from 'hub-js-sdk'; - -export default function userStars({actionContext, payload, done, maybeData}){ - // This works without a jwt - var token = null; - - if (_.has(maybeData, 'token')) { - token = maybeData.token; - } - - //Get repos for user or org - var _getStarredReposForUser = function(cb) { - Repos.getStarredReposForUser(token, payload.params.user, function(err, res) { - if (err) { - cb(); - } else { - actionContext.dispatch('RECEIVE_PROFILE_STARRED_REPOS', res.body); - cb(); - } - }, payload.location.query.page); - }; - - var _getUserByName = function(cb) { - Users.getUser(token, payload.params.user, function(err, res) { - if (err) { - if(res && res.notFound) { - actionContext.dispatch('USER_PROFILE_404'); - cb(err, null); - } else { - debug(err); - cb(); - } - } else { - actionContext.dispatch('RECEIVE_PROFILE_USER', res.body); - cb(); - } - }); - }; - - //Get user by name - async.parallel([ - _getStarredReposForUser, - _getUserByName - ], function(err, results) { - if (err) { - debug(err); - } - return done(); - }); -} diff --git a/app/scripts/actions/navigate/webhooks.js b/app/scripts/actions/navigate/webhooks.js deleted file mode 100644 index 930d0ce151..0000000000 --- a/app/scripts/actions/navigate/webhooks.js +++ /dev/null @@ -1,76 +0,0 @@ -'use strict'; - -import _ from 'lodash'; -import { parallel } from 'async'; -import { PENDING_DELETE } from 'common/enums/RepoStatus'; -import { - Repositories as Repos -} from 'hub-js-sdk'; -import getPipelines from '@dux/hub-sdk/webhooks/getPipelines'; - -var debug = require('debug')('action::webhooks'); - -const fetchRepo = ({ token, namespace, name }) => callback => { - Repos.getRepo(token, `${namespace}/${name}`, (err, { body }) => { - const { status } = body; - if (err || status === PENDING_DELETE) { - // We should handle other possible errors here (500, etc) - return callback('REPO_NOT_FOUND'); - } else { - return callback(null, body); - } - }); -}; - -const fetchPipelines = ({ token, namespace, name }) => callback => { - getPipelines(token, { - namespace, - name - }, (err, res) => { - if (err) { - return callback(); - } else { - return callback(null, res.body); - } - }); -}; - -export default function fetchWebhooksPageData({ - actionContext: { dispatch }, - payload: { params }, - done, - maybeData: { token, user } -}) { - - if (!token) { - dispatch('REPO_NOT_FOUND', null); - return done(); - } - - debug(params); - const { - user: namespace, - splat: name - } = params; - - parallel({ - repository: fetchRepo({ token, namespace, name }), - pipelines: fetchPipelines({ token, namespace, name }) - }, - (err, { repository, pipelines }) => { - if(err) { - debug('err', err); - /** - * If there's an error, 404 by default, but handle other - * errors in the future - */ - dispatch('REPO_NOT_FOUND', null); - done(); - } else { - debug('receive', repository, pipelines); - dispatch('RECEIVE_REPOSITORY', repository); - dispatch('RECEIVE_WEBHOOKS', pipelines); - done(); - } - }); -} diff --git a/app/scripts/actions/onAddCollaboratorChange.js b/app/scripts/actions/onAddCollaboratorChange.js deleted file mode 100644 index 8fb1d9f315..0000000000 --- a/app/scripts/actions/onAddCollaboratorChange.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -export default function onAddCollaboratorChange(actionContext, { collaborator }) { - actionContext.dispatch('ON_ADD_COLLAB_CHANGE', collaborator); -} diff --git a/app/scripts/actions/redux/tags.js b/app/scripts/actions/redux/tags.js deleted file mode 100644 index 3ae1df4988..0000000000 --- a/app/scripts/actions/redux/tags.js +++ /dev/null @@ -1,22 +0,0 @@ -'use strict'; - -import { Repositories as Repos } from 'hub-js-sdk'; -import { DELETE_REPO_TAG } from 'reduxConsts'; -const debug = require('debug')('hub:actions:redux:deleteRepoTag'); - -export const deleteRepoTag = ({ JWT, namespace, name, tagName }) => ({ - type: DELETE_REPO_TAG, - payload: { - namespace, - reponame: name, - tagName - }, - meta: { - sdk: { - call: Repos.deleteRepoTag, - args: [JWT, { namespace, name, tagName }], - callback: (err, res) => ({}), - statusKey: ['deleteRepoTag', tagName] - } - } -}); diff --git a/app/scripts/actions/regenTriggerToken.js b/app/scripts/actions/regenTriggerToken.js deleted file mode 100644 index d978f2fb2f..0000000000 --- a/app/scripts/actions/regenTriggerToken.js +++ /dev/null @@ -1,27 +0,0 @@ -'use strict'; -const debug = require('debug')('hub:actions:regenTriggerToken'); -import { - Autobuilds as AutoBuild - } from 'hub-js-sdk'; - -function getTriggerStatus(JWT, actionContext, namespace, name) { - AutoBuild.getTriggerStatus(JWT, namespace, name, function(err, res) { - if (err) { - debug('error', err); - } - if (res.ok) { - actionContext.dispatch('RECEIVE_TRIGGER_STATUS', res.body); - } - }); -} - -export default function regenTriggerToken(actionContext, {JWT, namespace, name}) { - AutoBuild.regenBuildTriggerToken(JWT, namespace, name, function(err, res) { - if (err) { - debug('error', err); - } - if (res.ok) { - getTriggerStatus(JWT, actionContext, namespace, name); - } - }); -} diff --git a/app/scripts/actions/removeTeam.js b/app/scripts/actions/removeTeam.js deleted file mode 100644 index 3c506007f7..0000000000 --- a/app/scripts/actions/removeTeam.js +++ /dev/null @@ -1,26 +0,0 @@ -'use strict'; - -var debug = require('debug')('hub:actions:removeTeam'); - -import { Orgs } from 'hub-js-sdk'; - -var removeTeam = function(actionContext, {jwt, orgname, teamname}) { - Orgs.deleteTeam(jwt, orgname, teamname, function(delErr, delRes) { - if (delErr) { - debug('error', delErr); - actionContext.dispatch('TEAM_ERROR', delErr); - } else if (delRes.ok) { - actionContext.dispatch('DELETE_DASHBOARD_TEAM_SUCCESS'); - actionContext.history.push(`/u/${orgname}/dashboard/teams/`); - Orgs.getTeams(jwt, orgname, function(err, res) { - if (err) { - debug('getTeams error', err); - } else { - actionContext.dispatch('RECEIVE_DASHBOARD_ORG_TEAMS', res.body); - } - }); - } - }); -}; - -module.exports = removeTeam; diff --git a/app/scripts/actions/removeTeamMember.js b/app/scripts/actions/removeTeamMember.js deleted file mode 100644 index 5d6b6b298a..0000000000 --- a/app/scripts/actions/removeTeamMember.js +++ /dev/null @@ -1,24 +0,0 @@ -'use strict'; - -var debug = require('debug')('hub:actions:removeTeamMember'); - -import { Orgs } from 'hub-js-sdk'; - -var removeTeamMember = function(actionContext, {jwt, orgname, teamname, membername}) { - Orgs.deleteMember(jwt, orgname, teamname, membername, function(delErr, delRes) { - if (delErr) { - debug('error', delErr); - actionContext.dispatch('TEAM_MEMBER_ERROR', delErr); - } else if (delRes.ok) { - Orgs.getMembers(jwt, orgname, teamname, function(err, res) { - if (err) { - debug('getMembers error', err); - } else { - actionContext.dispatch('RECEIVE_DASHBOARD_TEAM_MEMBERS', res.body); - } - }); - } - }); -}; - -module.exports = removeTeamMember; diff --git a/app/scripts/actions/removeTriggerLink.js b/app/scripts/actions/removeTriggerLink.js deleted file mode 100644 index 3a7d25f527..0000000000 --- a/app/scripts/actions/removeTriggerLink.js +++ /dev/null @@ -1,20 +0,0 @@ -'use strict'; -import _ from 'lodash'; -import { Autobuilds as AutoBuild } from 'hub-js-sdk'; -var debug = require('debug')('hub:actions:removeTriggerLink'); - -export default function(actionContext, { JWT, namespace, name, repo_id }) { - AutoBuild.deleteAutomatedBuildLink(JWT, namespace, name, repo_id, function(err, res) { - if (err) { - debug('error', err); - } else { - AutoBuild.getAutomatedBuildLinks(JWT, namespace, name, function(getErr, getRes){ - if (getErr) { - debug('getAutomatedBuildLinks error', err); - } else { - actionContext.dispatch('RECEIVE_AUTOBUILD_LINKS', getRes.body.results); - } - }); - } - }); -} diff --git a/app/scripts/actions/removeWebhookFromPipeline.js b/app/scripts/actions/removeWebhookFromPipeline.js deleted file mode 100644 index 6f77808a66..0000000000 --- a/app/scripts/actions/removeWebhookFromPipeline.js +++ /dev/null @@ -1,8 +0,0 @@ -'use strict'; - -export default function removeWebhookFromPipeline({ dispatch }, - params, - done) { - dispatch('ADD_WEBHOOK_REMOVE_HOOK'); - done(); -} diff --git a/app/scripts/actions/resendConfirmationEmail.js b/app/scripts/actions/resendConfirmationEmail.js deleted file mode 100644 index 336762c181..0000000000 --- a/app/scripts/actions/resendConfirmationEmail.js +++ /dev/null @@ -1,20 +0,0 @@ -'use strict'; -import { - Emails - } from 'hub-js-sdk'; -const debug = require('debug')('hub:actions:resendConfirmationEmail'); - -var resendConfirmationEmail = function(actionContext, {JWT, emailID}) { - actionContext.dispatch('RESEND_EMAIL_CONFIRMATION_ATTEMPT_START', emailID); - Emails.resendConfirmationEmail(JWT, emailID, function(err, res) { - if (err) { - debug('error', err); - actionContext.dispatch('RESEND_EMAIL_CONFIRMATION_FAILED', emailID); - } else { - actionContext.dispatch('RESEND_EMAIL_CONFIRMATION_SENT', emailID); - } - setTimeout(() => {actionContext.dispatch('RESEND_EMAIL_CONFIRMATION_CLEAR', emailID);}, 4000); - }); -}; - -module.exports = resendConfirmationEmail; diff --git a/app/scripts/actions/resetNotifications.js b/app/scripts/actions/resetNotifications.js deleted file mode 100644 index 0eef639999..0000000000 --- a/app/scripts/actions/resetNotifications.js +++ /dev/null @@ -1,11 +0,0 @@ -'use strict'; -import _ from 'lodash'; - -export default function(actionContext, slateArray) { - if (_.includes(slateArray, 'notifications')) { - actionContext.dispatch('RESET_EMAIL_NOTIFICATIONS_STORE'); - } - if (_.includes(slateArray, 'outbound')) { - actionContext.dispatch('RESET_OUTBOUND_EMAILS_STORE'); - } -} diff --git a/app/scripts/actions/resetPasswordSubmit.js b/app/scripts/actions/resetPasswordSubmit.js deleted file mode 100644 index d44247e627..0000000000 --- a/app/scripts/actions/resetPasswordSubmit.js +++ /dev/null @@ -1,21 +0,0 @@ -/* @flow */ -'use strict'; -import { - Users - } from 'hub-js-sdk'; -const debug = require('debug')('hub:actions:resetPasswordSubmit'); - -var resetPasswordSubmit = function(actionContext:{ dispatch : Function }, { uidb64, reset_token, password_1, password_2 }) { - Users.resetPassword(uidb64, password_1, password_2, reset_token, function(err, res) { - if (err) { - debug('error', err); - actionContext.dispatch('RESET_PASSWORD_ERROR', res.body); - } else if (res.ok) { - actionContext.dispatch('RESET_PASSWORD_SUCCESSFUL'); - actionContext.history.push('/account/password-reset-confirm/success/'); - actionContext.dispatch('CHANGE_PASS_CLEAR', {}); - } - }); -}; - -module.exports = resetPasswordSubmit; diff --git a/app/scripts/actions/resetWebhookForm.js b/app/scripts/actions/resetWebhookForm.js deleted file mode 100644 index 1de31e6100..0000000000 --- a/app/scripts/actions/resetWebhookForm.js +++ /dev/null @@ -1,8 +0,0 @@ -'use strict'; - -export default function resetWebhookForm({ dispatch }, - params, - done) { - dispatch('ADD_WEBHOOK_RESET'); - done(); -} diff --git a/app/scripts/actions/saveEmailNotifs.js b/app/scripts/actions/saveEmailNotifs.js deleted file mode 100644 index 3737bb7380..0000000000 --- a/app/scripts/actions/saveEmailNotifs.js +++ /dev/null @@ -1,51 +0,0 @@ -'use strict'; - -var debug = require('debug')('hub:actions:saveEmailNotifs'); -import async from 'async'; - -import { Notifications } from 'hub-js-sdk'; - -var saveEmailNotifs = function(actionContext, {jwt, notification}) { - actionContext.dispatch('START_SAVE_ACTION'); - var _saveNotificationSettings = function(cb) { - Notifications.setNotificationSubscription(jwt, notification, function(err, res) { - if (err) { - debug('error', err); - cb(err); - } else if (res.body && res.ok) { - return cb(null, res.body); - } - }); - }; - - var _getNotificationSettings = function(cb) { - //all good, do the next call to get the notifications - Notifications.getNotificationSubscriptions(jwt, function(err, res) { - if (err) { - debug('getNotificationSubscriptions error', err); - cb(err); - } else { - cb(null, res.body.results); - } - }); - }; - - async.series([ - function (callback) { - _saveNotificationSettings(callback); - }, - function (callback) { - _getNotificationSettings(callback); - } - ], function (err, results) { - if (err) { - debug('async.series callback error', err); - actionContext.dispatch('SAVE_NOTIFICATIONS_ERROR'); - } else if (results[1]) { - actionContext.dispatch('SAVE_NOTIFICATIONS_SUCCESS'); - actionContext.dispatch('RECEIVE_NOTIFICATIONS', results[1]); - } - }); -}; - -module.exports = saveEmailNotifs; diff --git a/app/scripts/actions/saveOrgProfile.js b/app/scripts/actions/saveOrgProfile.js deleted file mode 100644 index 37c6eed102..0000000000 --- a/app/scripts/actions/saveOrgProfile.js +++ /dev/null @@ -1,60 +0,0 @@ -'use strict'; - -var debug = require('debug')('ACTION::saveOrgProfile'); -import async from 'async'; -import { Orgs } from 'hub-js-sdk'; -//Organization Object -/* - { - id (string), - orgname (regex), - full_name (string), - location (string): Your Location on the world, - company (string): Your organization's name, - profile_url (url): Your place on the web, - gravatar_email (email): This address will define which picture of you is shown, - is_active (boolean): Designates whether user is active. Unselect this instead of deleting accounts., - date_joined (datetime), - gravatar_url (string) - } - */ -export default function(actionContext, {jwt, orgname, organization}) { - - var _updateOrg = function(cb) { - Orgs.updateOrg(jwt, orgname, organization, function(err, res) { - if (err) { - debug(err); - actionContext.dispatch('UPDATE_ORG_ERROR', err); - cb(err, {}); - } else { - if (res.ok) { - cb(null, res.body); - } - } - }); - }; - - //Get orgs for user - var _getUpdatedOrg = function(cb) { - Orgs.getOrg(jwt, orgname, function(err, res) { - if (err) { - debug(err); - cb(err, {}); - } else { - cb(null, res.body); - actionContext.dispatch('UPDATE_ORG_SUCCESS'); - } - }); - }; - - async.series([ - _updateOrg, - _getUpdatedOrg - ], function (err, results) { - if(err) { - debug(err); - } else { - actionContext.dispatch('RECEIVE_ORGANIZATION', results[1]); - } - }); -} diff --git a/app/scripts/actions/saveOutbound.js b/app/scripts/actions/saveOutbound.js deleted file mode 100644 index fbcb25adba..0000000000 --- a/app/scripts/actions/saveOutbound.js +++ /dev/null @@ -1,106 +0,0 @@ -'use strict'; - -import { parallel } from 'async'; -import isEmpty from 'lodash/lang/isEmpty'; -import { - Emails - } from 'hub-js-sdk'; -var debug = require('debug')('hub:actions:saveOutbound'); - -module.exports = function({ dispatch }, - { - JWT, - username, - weeklyDigest, - betaGroup - }) { - /*eslint-disable camelcase */ - var digestSubscribe = weeklyDigest.subscribed_emails; - var digestUnsubscribe = weeklyDigest.unsubscribed_emails; - var betaSubscribe = betaGroup.subscribed_emails; - var betaUnsubscribe = betaGroup.unsubscribed_emails; - /*eslint-enable camelcase */ - parallel({ - digestSubscribed: function (callback) { - Emails.subscribeEmails(JWT, username, { - /*eslint-disable camelcase */ - subscribed_emails: digestSubscribe, - mailing_list: 'DockerNewsMailingList' - /*eslint-enable camelcase*/ - }, function (err, res) { - if (err) { - callback(err); - } else { - callback(null, res); - } - }); - }, - betaSubscribed: function (callback) { - Emails.subscribeEmails(JWT, username, { - /*eslint-disable camelcase */ - subscribed_emails: betaSubscribe, - mailing_list: 'DockerBetaGroupMailingList' - /*eslint-enable camelcase */ - }, function (err, res) { - if (err) { - callback(err); - } else { - callback(null, res); - } - }); - }, - digestUnsubscribed: function (callback) { - if (!isEmpty(digestUnsubscribe)) { - Emails.unsubscribeEmails(JWT, username, { - /*eslint-disable camelcase */ - unsubscribed_emails: digestUnsubscribe, - mailing_list: 'DockerNewsMailingList' - /*eslint-enable camelcase */ - }, function (err, res) { - if (err) { - callback(err); - } else { - callback(null, res.body.unsubscribed); - } - }); - } else { - callback(null); - } - }, - betaUnsubscribed: function (callback) { - if (!isEmpty(betaUnsubscribe)) { - Emails.unsubscribeEmails(JWT, username, { - /*eslint-disable camelcase */ - unsubscribed_emails: betaUnsubscribe, - mailing_list: 'DockerBetaGroupMailingList' - /*eslint-enable camelcase */ - }, function (err, res) { - if (err) { - callback(err); - } else { - callback(null, res.body.unsubscribed); - } - }); - } else { - callback(null); - } - } - }, - function(err, res) { - if(err) { - debug(err); - dispatch('SAVE_OUTBOUND_ERROR'); - } else { - Emails.getEmailSubscriptions(JWT, username, function(error, response){ - if (error) { - return debug(error); - } - dispatch('RECEIVE_EMAIL_SUBSCRIPTIONS', { - weeklyDigest: response.body.DockerNewsMailingList, - betaGroup: response.body.DockerBetaGroupMailingList - }); - dispatch('SAVE_OUTBOUND_SUCCESS'); - }); - } - }); -}; diff --git a/app/scripts/actions/savePushAutoBuildSettings.js b/app/scripts/actions/savePushAutoBuildSettings.js deleted file mode 100644 index c20dee1a21..0000000000 --- a/app/scripts/actions/savePushAutoBuildSettings.js +++ /dev/null @@ -1,74 +0,0 @@ -'use strict'; -import { - Autobuilds - } from 'hub-js-sdk'; -import has from 'lodash/object/has'; -import merge from 'lodash/object/merge'; -import sortBy from 'lodash/collection/sortBy'; -import async from 'async'; -var debug = require('debug')('hub:actions:savePushAutoBuildSettings'); - -function saveTag({JWT, namespace, name}) { - return (tag, callback) => { - if (tag.isNew && !tag.toDelete) { // toDelete unecessary now as tags with isNew && toDelete SHOULD be removed - var ab = merge({}, tag, {repoName: name, namespace: namespace}); - Autobuilds.createAutomatedBuildTags(JWT, ab, function(err, res) { - if (err) { - debug(err); - tag.error = true; - callback(null, { tag, err }); - } else { - callback(null, res.body); - } - }); - } else if (tag.toDelete && !!tag.id) { - Autobuilds.deleteAutomatedBuildTags(JWT, namespace, name, tag.id, function(err, res){ - if (err) { - debug(err); - tag.error = true; - callback(null, { tag, err }); - } else { - callback(null, null); - } - }); - } else { - Autobuilds.updateAutomatedBuildTags(JWT, namespace, name, tag.id, tag, function(err, res){ - if (err) { - debug(err); - tag.error = true; - callback(null, { tag, err }); - } else { - callback(null, res.body); - } - }); - } - }; -} - -export default function(actionContext, {JWT, namespace, name, tags}, done) { - let encounteredError = false; - async.map(tags, saveTag({ JWT, namespace, name }), function(error, results) { - results.forEach( (resultTag) => { - if (has(resultTag, 'tag')) { - const { tag, err } = resultTag; - //We are keeping track of only `update` docker tag errors and at the moment we get them in `non_field_errors` - const nonFieldErrors = err.response.body.non_field_errors; - if (has(tag, 'error')) { - actionContext.dispatch('SAVE_BUILD_TAGS_ERROR', {name: tag.name, error: nonFieldErrors}); - encounteredError = true; - } - } - }); - if (!encounteredError) { - //Gets here only if there are no errors - actionContext.dispatch('SAVE_BUILD_TAGS_SUCCESS'); - const sorted = sortBy(results, 'id'); - actionContext.dispatch('UPDATE_AUTO_BUILD_SETTINGS', { - field: 'autoBuildStore', - key: 'build_tags', - value: sorted - }); - } - done(); - }); -} diff --git a/app/scripts/actions/saveSettingsData.js b/app/scripts/actions/saveSettingsData.js deleted file mode 100644 index dee5615660..0000000000 --- a/app/scripts/actions/saveSettingsData.js +++ /dev/null @@ -1,22 +0,0 @@ -'use strict'; -import { - Users, - JWT -} from 'hub-js-sdk'; -const debug = require('debug')('hub:actions:saveSettingsData'); - -var saveSettingsData = function(actionContext, payload) { - actionContext.dispatch('ACCOUNT_INFO_ATTEMPT_START'); - Users.updateUser(payload.JWT, payload.username, payload.updateData, function(err, res) { - if (err) { - debug(err); - actionContext.dispatch('ACCOUNT_INFO_BAD_REQUEST', err.response.body); - } else { - actionContext.dispatch('ACCOUNT_INFO_SUCCESS'); - setTimeout(() => {actionContext.dispatch('ACCOUNT_INFO_STATUS_CLEAR');}, 4000); - actionContext.dispatch('RECEIVE_USER', res.body); - } - }); -}; - -module.exports = saveSettingsData; diff --git a/app/scripts/actions/saveTeamProfile.js b/app/scripts/actions/saveTeamProfile.js deleted file mode 100644 index 4630603723..0000000000 --- a/app/scripts/actions/saveTeamProfile.js +++ /dev/null @@ -1,53 +0,0 @@ -'use strict'; - -var debug = require('debug')('hub:actions:saveTeamProfile'); -import async from 'async'; -import { Orgs } from 'hub-js-sdk'; -//Team Object -/* - { - id (string), - teamname (regex), - description (string) - } - */ -export default function(actionContext, {jwt, orgname, teamname, team}) { - - var _updateTeam = function(cb) { - Orgs.updateTeam(jwt, { orgname, teamname, team }, function(err, res) { - if (err) { - debug(err); - actionContext.dispatch('UPDATE_TEAM_ERROR', err); - cb(err, {}); - } else { - if (res.ok) { - actionContext.dispatch('UPDATE_TEAM_SUCCESS'); - cb(null, res.body); - } - } - }); - }; - - //Get Team for org - var _getUpdatedTeam = function(cb) { - Orgs.getTeam(jwt, orgname, team.name, function(err, res) { - if (err) { - debug(err); - cb(err, {}); - } else { - cb(null, res.body); - } - }); - }; - - async.series([ - _updateTeam, - _getUpdatedTeam - ], function (err, results) { - if(err) { - debug(err); - } else { - actionContext.dispatch('RECEIVE_ORG_TEAM', results[1]); - } - }); -} diff --git a/app/scripts/actions/selectOrganization.js b/app/scripts/actions/selectOrganization.js deleted file mode 100644 index ca2f46c77e..0000000000 --- a/app/scripts/actions/selectOrganization.js +++ /dev/null @@ -1,8 +0,0 @@ -/* @flow */ -'use strict'; - -//TODO: organization object needs to be documented in hub-js-sdk when available -module.exports = function(actionContext: {dispatch: Function}, - orgName: {orgName: string}) { - actionContext.dispatch('SELECT_ORGANIZATION', orgName); -}; diff --git a/app/scripts/actions/selectSourceRepoForAutobuild.js b/app/scripts/actions/selectSourceRepoForAutobuild.js deleted file mode 100644 index 46cd52b208..0000000000 --- a/app/scripts/actions/selectSourceRepoForAutobuild.js +++ /dev/null @@ -1,6 +0,0 @@ -'use strict'; - -//The source repository could be github, bitbucket or anything else in the future -export default function selectSourceRepoForAutobuild(actionContext, selectedSourceRepo) { - actionContext.dispatch('SELECT_SOURCE_REPO', selectedSourceRepo); -} diff --git a/app/scripts/actions/setNewPrimaryEmail.js b/app/scripts/actions/setNewPrimaryEmail.js deleted file mode 100644 index 4ba49a370f..0000000000 --- a/app/scripts/actions/setNewPrimaryEmail.js +++ /dev/null @@ -1,47 +0,0 @@ -'use strict'; - -import { sortByOrder } from 'lodash'; -import { series, each } from 'async'; -import { - Emails - } from 'hub-js-sdk'; -var debug = require('debug')('hub:actions:setNewPrimaryEmail'); - -function updateEmailSettings({ dispatch }, - { - JWT, username, emailId - }, - done) { - dispatch('START_SAVE_ACTION'); - series([ - function update(callback) { - debug('emailObject', emailId); - Emails.updateEmailByID(JWT, - emailId, - {primary: true}, - (err, res) => callback(null, res)); - } - ], - function afterUpdatingEmails(err, results) { - if (err) { - return debug(err); - } - Emails.getEmailsForUser(JWT, username, function(emailErr, res){ - if (emailErr) { - debug('emailErr', emailErr); - dispatch('FINISH_SAVE_ACTION'); - return done(); - } - var emails = res.body.results; - var sortedEmails = sortByOrder(emails, - ['primary', 'verified'], - [false, false]); - dispatch('RECEIVE_EMAILS', { - emails: sortedEmails - }); - dispatch('FINISH_SAVE_ACTION'); - }); - }); -} - -module.exports = updateEmailSettings; diff --git a/app/scripts/actions/shortDescriptionUpdateFormField.js b/app/scripts/actions/shortDescriptionUpdateFormField.js deleted file mode 100644 index 3acb1f78c6..0000000000 --- a/app/scripts/actions/shortDescriptionUpdateFormField.js +++ /dev/null @@ -1,9 +0,0 @@ -'use strict'; - -export default function({ dispatch }, - { fieldKey, fieldValue }, - done) { - dispatch('SHORT_DESCRIPTION_UPDATE_FIELD_WITH_VALUE', { - fieldKey, fieldValue - }); -} diff --git a/app/scripts/actions/signupUpdateFormField.js b/app/scripts/actions/signupUpdateFormField.js deleted file mode 100644 index 1b63a9a684..0000000000 --- a/app/scripts/actions/signupUpdateFormField.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -export default function(actionContext, { fieldKey, fieldValue }, done) { - actionContext.dispatch('SIGNUP_UPDATE_FIELD_WITH_VALUE', { - fieldKey, fieldValue - }); -} diff --git a/app/scripts/actions/signupValidations.js b/app/scripts/actions/signupValidations.js deleted file mode 100644 index 95f19464b1..0000000000 --- a/app/scripts/actions/signupValidations.js +++ /dev/null @@ -1,59 +0,0 @@ -'use strict'; - -var usernameValidation = function(actionContext, payload) { - var validationState; - var username = payload.unsafeUsername; - if (username.length > 3 && username.length <= 30 && username.match(/[a-z0-9\.\-_]+$/)) { - validationState = 'SUCCESS'; - } else if (username.length === 0) { - validationState = 'NOTHING'; - } else { - validationState = 'ERROR'; - } - actionContext.dispatch('VALIDATED_SIGNUP_USERNAME', { - username: username, - valState: validationState - }); -}; - -var passValidation = function(actionContext, payload) { - var validationState; - var password = payload.unsafePass; - if (password.length >= 5 && password.match(/[a-zA-Z]/) && password.match(/[0-9]/) && - password.match(/[\.-_!@#$%^&\*\(\)\[\]\{\}~:]/)) { - validationState = 'SUPERSUCCESS'; - } else if (password.length >= 5 && password.match(/[a-zA-Z]/) && password.match(/[0-9]/)) { - validationState = 'SUCCESS'; - } else if (password.length >= 5) { - validationState = 'WEAK'; - } else if (password.length === 0) { - validationState = 'NOTHING'; - } else if (password.length < 5) { - validationState = 'ERROR'; - } - actionContext.dispatch('VALIDATED_SIGNUP_PASSWORD', { - password: password, - valState: validationState - }); -}; -var emailValidation = function(actionContext, payload) { - var validationState; - var email = payload.unsafeEmail; - if (email.length > 3 && email.match(/.@./) && !email.match(/.\ ./)) { - validationState = 'SUCCESS'; - } else if (email.length === 0) { - validationState = 'NOTHING'; - } else { - validationState = 'ERROR'; - } - actionContext.dispatch('VALIDATED_SIGNUP_EMAIL', { - email: email, - valState: validationState - }); -}; - -module.exports = { - usernameValidation: usernameValidation, - passValidation: passValidation, - emailValidation: emailValidation -}; diff --git a/app/scripts/actions/toggleDeleteRepoNameConfirmBox.js b/app/scripts/actions/toggleDeleteRepoNameConfirmBox.js deleted file mode 100644 index d54621917b..0000000000 --- a/app/scripts/actions/toggleDeleteRepoNameConfirmBox.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -export default function(actionContext) { - actionContext.dispatch('TOGGLE_DELETE_REPO_NAME_CONFIRM_BOX'); -} diff --git a/app/scripts/actions/toggleLongDescriptionEdit.js b/app/scripts/actions/toggleLongDescriptionEdit.js deleted file mode 100644 index 0ebd88cdf3..0000000000 --- a/app/scripts/actions/toggleLongDescriptionEdit.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -export default function (actionContext, { isEditing }) { - actionContext.dispatch('TOGGLE_LONG_DESCRIPTION_EDIT', { isEditing }); -} diff --git a/app/scripts/actions/toggleShortDescriptionEdit.js b/app/scripts/actions/toggleShortDescriptionEdit.js deleted file mode 100644 index 438bcb1792..0000000000 --- a/app/scripts/actions/toggleShortDescriptionEdit.js +++ /dev/null @@ -1,6 +0,0 @@ -'use strict'; - -export default function (actionContext, { isEditing }) { - actionContext.dispatch('TOGGLE_SHORT_DESCRIPTION_EDIT', { isEditing }); -} - diff --git a/app/scripts/actions/toggleStarred.js b/app/scripts/actions/toggleStarred.js deleted file mode 100644 index 11a3c342f6..0000000000 --- a/app/scripts/actions/toggleStarred.js +++ /dev/null @@ -1,30 +0,0 @@ -'use strict'; - -import { - Repositories as Repos -} from 'hub-js-sdk'; -var debug = require('debug')('hub:actions:toggleStarred'); - -export default function(actionContext, {jwt, repoShortName, status}) { - if(status) { - Repos.starRepo(jwt, repoShortName, - function(err, res) { - if (err) { - debug(err); - } else if (res.ok) { - actionContext.dispatch('TOGGLE_STARRED_STATE', status); - } - } - ); - } else { - Repos.unstarRepo(jwt, repoShortName, - function(err, res) { - if (err) { - debug(err); - } else if (res.ok) { - actionContext.dispatch('TOGGLE_STARRED_STATE', status); - } - } - ); - } -} diff --git a/app/scripts/actions/toggleTriggerStatus.js b/app/scripts/actions/toggleTriggerStatus.js deleted file mode 100644 index b23abf2a91..0000000000 --- a/app/scripts/actions/toggleTriggerStatus.js +++ /dev/null @@ -1,27 +0,0 @@ -'use strict'; -const debug = require('debug')('hub:actions:toggleTriggerStatus'); -import { - Autobuilds as AutoBuild - } from 'hub-js-sdk'; - -function getTriggerStatus(JWT, actionContext, namespace, name) { - AutoBuild.getTriggerStatus(JWT, namespace, name, function(err, res) { - if (err) { - debug(err); - } - if (res.ok) { - actionContext.dispatch('RECEIVE_TRIGGER_STATUS', res.body); - } - }); -} - -export default function toggleTriggerStatus(actionContext, {JWT, namespace, name, active}) { - AutoBuild.toggleTriggerStatus(JWT, namespace, name, active, function(err, res) { - if (err) { - debug(err); - } - if (res.ok) { - getTriggerStatus(JWT, actionContext, namespace, name); - } - }); -} diff --git a/app/scripts/actions/toggleVisibility.js b/app/scripts/actions/toggleVisibility.js deleted file mode 100644 index 4b296d9d03..0000000000 --- a/app/scripts/actions/toggleVisibility.js +++ /dev/null @@ -1,23 +0,0 @@ -'use strict'; - -import { Users } from 'hub-js-sdk'; -var debug = require('debug')('hub:actions:toggleVisibility'); - -module.exports = function(actionContext, {JWT, username, visibility}) { - actionContext.dispatch('START TOGGLE REPO VISIBILITY'); - Users.updateDefaultVisibility(JWT, { username, visibility }, function(err, res){ - if (err) { - actionContext.dispatch('UPDATE_ORG_ERROR', err); - } else if (res.ok) { - Users.getUserSettings(JWT, username, function(getErr, getRes) { - if (getErr) { - debug(getErr); - } else if (getRes.ok) { - actionContext.dispatch('RECEIVE_PRIVATE_REPOSTATS', getRes.body); - let is_private = (getRes.body.default_repo_visibility === 'private'); - actionContext.dispatch('CREATE_REPO_UPDATE_FIELD_WITH_VALUE', {fieldKey: 'is_private', fieldValue: is_private}); - } - }); - } - }); -}; diff --git a/app/scripts/actions/toggleVisibilityRepoNameConfirmBox.js b/app/scripts/actions/toggleVisibilityRepoNameConfirmBox.js deleted file mode 100644 index 196a28bac2..0000000000 --- a/app/scripts/actions/toggleVisibilityRepoNameConfirmBox.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -export default function(actionContext) { - actionContext.dispatch('TOGGLE_VISIBILITY_REPO_NAME_CONFIRM_BOX'); -} diff --git a/app/scripts/actions/triggerBuild.js b/app/scripts/actions/triggerBuild.js deleted file mode 100644 index 06bd11ee9d..0000000000 --- a/app/scripts/actions/triggerBuild.js +++ /dev/null @@ -1,15 +0,0 @@ -'use strict'; - -import { Autobuilds } from 'hub-js-sdk'; -var debug = require('debug')('hub:actions:triggerBuild'); - -module.exports = function(actionContext, {JWT, name, namespace}) { - Autobuilds.triggerBuild(JWT, namespace, name, (err, res) => { - if (err) { - debug(err); - actionContext.dispatch('AB_TRIGGER_ERROR'); - } else { - actionContext.dispatch('AB_TRIGGER_SUCCESS'); - } - }); -}; diff --git a/app/scripts/actions/triggerBuildByTag.js b/app/scripts/actions/triggerBuildByTag.js deleted file mode 100644 index ba29f7bc59..0000000000 --- a/app/scripts/actions/triggerBuildByTag.js +++ /dev/null @@ -1,34 +0,0 @@ -'use strict'; - -import { Autobuilds } from 'hub-js-sdk'; -var debug = require('debug')('hub:actions:triggerBuildByTag'); - -module.exports = function(actionContext, {JWT, tag, triggerId}) { - let successStatus, errorStatus; - actionContext.dispatch('ATTEMPT_TRIGGER_BY_TAG', triggerId); - Autobuilds.triggerBuildByTag(JWT, tag, (err, res) => { - if (err) { - debug(err); - actionContext.dispatch('AB_TRIGGER_BY_TAG_ERROR', - { - error: 'Error triggering the build. Please check your source name.', - id: triggerId - }); - } else { - if (res.ok) { - switch(res.status) { - case 202: - successStatus = 'Successfully triggered a build.'; - break; - case 200: - successStatus = 'Attempted to trigger a build. Please check the build details page for more information.'; - //TODO: report this as error or success once it is clear what exactly this means - break; - default: - break; - } - actionContext.dispatch('AB_TRIGGER_BY_TAG_SUCCESS', {success: successStatus, id: triggerId}); - } - } - }); -}; diff --git a/app/scripts/actions/unlinkBitbucket.js b/app/scripts/actions/unlinkBitbucket.js deleted file mode 100644 index 55a3a9e911..0000000000 --- a/app/scripts/actions/unlinkBitbucket.js +++ /dev/null @@ -1,26 +0,0 @@ -'use strict'; - -import { Builds } from 'hub-js-sdk'; -const debug = require('debug')('hub:actions:unlinkBitbucket'); -import linkedAccountSettingsAction from './navigate/linkedAccountsSettings'; - -module.exports = function(actionContext, jwt) { - Builds.unlinkBitbucket(jwt, function(err, res) { - if (err) { - debug(err); - const { detail } = err.response.body; - if(detail) { - actionContext.dispatch('BITBUCKET_UNLINK_ERROR', detail); - } - } else if (res.ok) { - linkedAccountSettingsAction( - { - actionContext: actionContext, - payload: {}, - done: function() { debug('done unlinking bitbucket.'); }, - maybeData: {token: jwt} - } - ); - } - }); -}; diff --git a/app/scripts/actions/unlinkGithub.js b/app/scripts/actions/unlinkGithub.js deleted file mode 100644 index e5e7dbc021..0000000000 --- a/app/scripts/actions/unlinkGithub.js +++ /dev/null @@ -1,27 +0,0 @@ -'use strict'; - -import { Builds } from 'hub-js-sdk'; -const debug = require('debug')('hub:actions:unlinkGithub'); -import has from 'lodash/object/has'; -import linkedAccountSettingsAction from './navigate/linkedAccountsSettings'; - -module.exports = function(actionContext, jwt) { - Builds.unlinkGithub(jwt, function(err, res) { - if (err) { - debug(err); - const { detail } = err.response.body; - if(detail) { - actionContext.dispatch('GITHUB_UNLINK_ERROR', detail); - } - } else if (res.ok) { - linkedAccountSettingsAction( - { - actionContext: actionContext, - payload: {}, - done: function() { debug('done unlinking github account.'); }, - maybeData: {token: jwt} - } - ); - } - }); -}; diff --git a/app/scripts/actions/updateAccountInfoFormField.js b/app/scripts/actions/updateAccountInfoFormField.js deleted file mode 100644 index a70ccb1a5d..0000000000 --- a/app/scripts/actions/updateAccountInfoFormField.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -export default function(actionContext, { fieldKey, fieldValue}) { - actionContext.dispatch('ACCOUNT_INFO_UPDATE_FIELD_WITH_VALUE', { fieldKey, fieldValue }); -} diff --git a/app/scripts/actions/updateAddOrganizationFormField.js b/app/scripts/actions/updateAddOrganizationFormField.js deleted file mode 100644 index b11166861c..0000000000 --- a/app/scripts/actions/updateAddOrganizationFormField.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -export default function(actionContext, { fieldKey, fieldValue}) { - actionContext.dispatch('ADD_ORG_UPDATE_FIELD_WITH_VALUE', { fieldKey, fieldValue }); -} diff --git a/app/scripts/actions/updateAddRepositoryFormField.js b/app/scripts/actions/updateAddRepositoryFormField.js deleted file mode 100644 index 940c91053e..0000000000 --- a/app/scripts/actions/updateAddRepositoryFormField.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -export default function(actionContext, { fieldKey, fieldValue}) { - actionContext.dispatch('CREATE_REPO_UPDATE_FIELD_WITH_VALUE', { - fieldKey, fieldValue - }); -} diff --git a/app/scripts/actions/updateAutoBuildPushTriggerItem.js b/app/scripts/actions/updateAutoBuildPushTriggerItem.js deleted file mode 100644 index bd36a50333..0000000000 --- a/app/scripts/actions/updateAutoBuildPushTriggerItem.js +++ /dev/null @@ -1,12 +0,0 @@ -/* @flow */ -/*global VisibilityFormFieldPayload */ -'use strict'; - -var debug = require('debug')('hub:actions:updateAutoBuildPushTriggerItem'); -export default function(actionContext, { isNew, index, fieldkey, value}) { - if (isNew) { - actionContext.dispatch('UPDATE_AUTOBUILD_NEW_TAG_ITEM', {index, fieldkey, value}); - } else { - actionContext.dispatch('UPDATE_AUTOBUILD_PUSH_TRIGGER_ITEM', {index, fieldkey, value}); - } -} diff --git a/app/scripts/actions/updateAutoBuildSettings.js b/app/scripts/actions/updateAutoBuildSettings.js deleted file mode 100644 index 08fc59e2e9..0000000000 --- a/app/scripts/actions/updateAutoBuildSettings.js +++ /dev/null @@ -1,20 +0,0 @@ -'use strict'; - -import { Autobuilds } from 'hub-js-sdk'; -var debug = require('debug')('hub:actions:updateAutoBuildSettings'); - -module.exports = function(actionContext, {JWT, namespace, name, data}) { - Autobuilds.updateAutomatedBuildSettings(JWT, namespace, name, data, function(err, res){ - if (err) { - debug(res.body); - } else if (res.ok) { - Autobuilds.getAutomatedBuildSettings(JWT, namespace, name, function(getErr, getRes) { - if (getErr) { - debug(getErr); - } else if (getRes.ok) { - actionContext.dispatch('RECEIVE_AUTOBUILD_SETTINGS', getRes.body); - } - }); - } - }); -}; diff --git a/app/scripts/actions/updateAutoBuildSettingsStore.js b/app/scripts/actions/updateAutoBuildSettingsStore.js deleted file mode 100644 index 82fc8de4c3..0000000000 --- a/app/scripts/actions/updateAutoBuildSettingsStore.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -export default function(actionContext, { field, key, value}) { - actionContext.dispatch('UPDATE_AUTO_BUILD_SETTINGS', {field, key, value}); -} diff --git a/app/scripts/actions/updateAutobuildFormField.js b/app/scripts/actions/updateAutobuildFormField.js deleted file mode 100644 index 6e06bc9486..0000000000 --- a/app/scripts/actions/updateAutobuildFormField.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -export default function(actionContext, { fieldKey, fieldValue}) { - actionContext.dispatch('AUTOBUILD_FORM_UPDATE_FIELD_WITH_VALUE', { - fieldKey, fieldValue - }); -} diff --git a/app/scripts/actions/updateBillingInfoFormField.js b/app/scripts/actions/updateBillingInfoFormField.js deleted file mode 100644 index b386a3de83..0000000000 --- a/app/scripts/actions/updateBillingInfoFormField.js +++ /dev/null @@ -1,15 +0,0 @@ -'use strict'; - -export default function(actionContext, { field, fieldKey, fieldValue}) { - if (field === 'card' && fieldKey === 'number') { - var type = window.recurly.validate.cardType(fieldValue.toString()); - actionContext.dispatch('BILLING_INFO_UPDATE_FIELD_WITH_VALUE', { - field: 'card', - fieldKey: 'type', - fieldValue: type - }); - } - actionContext.dispatch('BILLING_INFO_UPDATE_FIELD_WITH_VALUE', { - field, fieldKey, fieldValue - }); -} diff --git a/app/scripts/actions/updateBillingInformation.js b/app/scripts/actions/updateBillingInformation.js deleted file mode 100644 index 669ae950bb..0000000000 --- a/app/scripts/actions/updateBillingInformation.js +++ /dev/null @@ -1,87 +0,0 @@ -'use strict'; -/*global UpdateBillingInfoPayload */ -import { Billing } from 'hub-js-sdk'; -import _ from 'lodash'; -import async from 'async'; -var debug = require('debug')('hub:actions:updateBillingInformation'); - -function updateBillingInformation(actionContext, {JWT, user, billingInfo, accountInfo, card}, done) { - actionContext.dispatch('BILLING_SUBMIT_START'); - var recurlyData = _.merge({}, billingInfo, card); - let isOrg = false; - let username = ''; - if (_.has(user, 'username')) { - username = user.username; - } else if (_.has(user, 'orgname')) { - username = user.orgname; - isOrg = true; - } - const account = _.merge({}, accountInfo, {user: username}); - - try { - /** - * This will only run where window is defined. ie: the browser - * It throws an exception in node - */ - window.recurly.configure(process.env.RECURLY_PUBLIC_KEY); - } catch(e) { - debug('error', e); - } - window.recurly.token(recurlyData, function(recurlyErr, token) { - if (recurlyErr) { - // SHOULD ONLY GET HERE IF RECURLY DECLINES THEIR INFO - debug('recurly error', recurlyErr); - actionContext.dispatch('GET_RECURLY_ERROR', recurlyErr); - done(); - } else { - async.series([ - function(callback){ - Billing.updateBillingAccount(JWT, username, account, function(accountErr, accountRes){ - if (accountErr) { - let message = 'There was an error updating your contact information. Please check your information and try again.'; - if (_.has(accountRes.body, 'detail') && _.isString(accountRes.body.detail)) { - message = accountRes.body.detail; - } - actionContext.dispatch('BILLING_SUBMIT_ERROR', message); - callback(accountErr, accountRes); - } else if (accountRes.ok) { - callback(null, accountRes.body); - } - }); - }, - function(callback) { - let updatedInfo = {username: username, payment_token: token.id}; - Billing.updateBillingInfo(JWT, username, updatedInfo, function(billErr, billRes) { - if (billErr) { - debug('updateBillingInfo error', billErr); - let message = 'There was an error submitting your billing information. Please check your information and try again.'; - if (_.has(billRes.body, 'detail') && _.isString(billRes.body.detail)) { - message = billRes.body.detail; - } - actionContext.dispatch('BILLING_SUBMIT_ERROR', message); - callback(billErr, billRes); - } else if (billRes.ok) { - callback(null, billRes.body); - } - }); - } - ], - function(err, res) { - if (err) { - done(); - } else { - if (isOrg) { - actionContext.history.push(`/u/${username}/dashboard/billing/`); - } else { - actionContext.history.push('/account/billing-plans/'); - } - actionContext.dispatch('RECEIVE_BILLING_INFO', {billingInfo: res[1], accountInfo: res[0]}); - actionContext.dispatch('BILLING_SUBMIT_SUCCESS'); - done(); - } - }); - } - }); -} - -module.exports = updateBillingInformation; diff --git a/app/scripts/actions/updateChangePassStore.js b/app/scripts/actions/updateChangePassStore.js deleted file mode 100644 index cdea3e35a4..0000000000 --- a/app/scripts/actions/updateChangePassStore.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -var updateStore = function(actionContext, payload) { - actionContext.dispatch('CHANGE_PASS_UPDATE', payload); -}; - -module.exports = updateStore; diff --git a/app/scripts/actions/updateCloudBillingSubscription.js b/app/scripts/actions/updateCloudBillingSubscription.js deleted file mode 100644 index 3341a87f51..0000000000 --- a/app/scripts/actions/updateCloudBillingSubscription.js +++ /dev/null @@ -1,35 +0,0 @@ -'use strict'; -/** - * CLONE OF updateSubscriptionPlanOrPackage.js - * with Different dispatches - */ -import { Billing } from 'hub-js-sdk'; -import has from 'lodash/object/has'; -var debug = require('debug')('hub:actions:updateCloudBillingSubscription'); - -function updateBillingSubscriptions(actionContext, {JWT, username, subscription_uuid, package_code, coupon_code, isOrg}, done) { - actionContext.dispatch('ENTERPRISE_PAID_ATTEMPT_START'); - var data = { - package: package_code, - username, - coupon_code - }; - Billing.updateBillingSubscriptions(JWT, subscription_uuid, username, data, function(err, res) { - if (err) { - debug(err); - // If fails - There's nothing else we can do. Facepalm - actionContext.dispatch('ENTERPRISE_PAID_BAD_REQUEST', res.body.detail); - done(); - } else if (res.ok) { - actionContext.dispatch('ENTERPRISE_PAID_SUCCESS'); - if (isOrg) { - actionContext.history.push(`/u/${username}/dashboard/billing/`); - } else { - actionContext.history.push('/account/billing-plans/'); - } - done(); - } - }); -} - -module.exports = updateBillingSubscriptions; diff --git a/app/scripts/actions/updateEnterpriseTrialFormField.js b/app/scripts/actions/updateEnterpriseTrialFormField.js deleted file mode 100644 index 481545ac79..0000000000 --- a/app/scripts/actions/updateEnterpriseTrialFormField.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -export default function(actionContext, {fieldKey, fieldValue}) { - actionContext.dispatch('ENTERPRISE_TRIAL_UPDATE_FIELD_WITH_VALUE', { fieldKey, fieldValue }); -} diff --git a/app/scripts/actions/updateNotifCheckbox.js b/app/scripts/actions/updateNotifCheckbox.js deleted file mode 100644 index 26697d0aa2..0000000000 --- a/app/scripts/actions/updateNotifCheckbox.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -export default function(actionContext, cboxType) { - actionContext.dispatch('NOTIF_CHECKBOX_CLICK', cboxType); -} diff --git a/app/scripts/actions/updateOutbound.js b/app/scripts/actions/updateOutbound.js deleted file mode 100644 index cba8bae610..0000000000 --- a/app/scripts/actions/updateOutbound.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -export default function(actionContext, newList) { - actionContext.dispatch('UPDATE_OUTBOUND', newList); -} diff --git a/app/scripts/actions/updateRepoSettingsVisibilityField.js b/app/scripts/actions/updateRepoSettingsVisibilityField.js deleted file mode 100644 index 38259ca559..0000000000 --- a/app/scripts/actions/updateRepoSettingsVisibilityField.js +++ /dev/null @@ -1,56 +0,0 @@ -'use strict'; - -import async from 'async'; -var debug = require('debug')('hub:actions:updateRepoSettingsVisibilityField'); -import { Repositories as Repos, Users } from 'hub-js-sdk'; - -function updateRepoVisibility(actionContext, { jwt, isPrivate, repoShortName }) { - return (cb) => { - Repos.updateRepoVisibility(jwt, { isPrivate, repoShortName }, (err, res) => { - if (err) { - const { badRequest, body } = err.response; - if(badRequest) { - debug(err); - actionContext.dispatch('VISIBILITY_BAD_REQUEST', body); - cb(err); - } else if (res && res.body.error) { - actionContext.dispatch('VISIBILITY_ERROR', res.body); - cb(err); - } else { - actionContext.dispatch('VISIBILITY_ERROR'); - cb(err); - } - } else { - actionContext.dispatch('TOGGLE_VISIBILITY_SUCCESS', isPrivate); - cb(null, res.body); - } - }); - }; -} - -function getPrivateRepoStats(actionContext, { jwt, repoShortName }) { - return (cb) => { - const namespace = repoShortName.split('/')[0]; - Users.getUserSettings(jwt, namespace, function (err, res) { - if (err) { - cb(); - } else { - actionContext.dispatch('RECEIVE_PRIVATE_REPOSTATS', res.body); - cb(); - } - }); - }; -} - - -export default function(actionContext, { jwt, isPrivate, repoShortName }, done) { - actionContext.dispatch('TOGGLE_VISIBILITY_ATTEMPT_START'); - async.series([ - updateRepoVisibility(actionContext, { jwt, isPrivate, repoShortName }), - getPrivateRepoStats(actionContext, {jwt, repoShortName }) - ], function(err, results) { - if (err) { - debug(err); - } - }); -} diff --git a/app/scripts/actions/updateStripeBilling.js b/app/scripts/actions/updateStripeBilling.js deleted file mode 100644 index 826f4eb6e5..0000000000 --- a/app/scripts/actions/updateStripeBilling.js +++ /dev/null @@ -1,292 +0,0 @@ -'use strict'; -/*global UpdateBillingInfoPayload */ -const request = require('superagent'); -import { Billing } from 'hub-js-sdk'; -import has from 'lodash/object/has'; -import merge from 'lodash/object/merge'; -import map from 'lodash/collection/map'; -import find from 'lodash/collection/find'; -import isString from 'lodash/lang/isString'; -import async from 'async'; -var debug = require('debug')('hub:actions:updateBillingInformation'); - -import _encodeForm from '../components/utils/encodeForm.js'; -import { - ACCOUNT, - BILLING, - BILLFORWARD_ACCOUNT_ID, - STRIPE_URL, - STRIPE_STAGE_TOKEN, - STRIPE_PROD_TOKEN, - BF_STAGE_URL, - BF_PROD_URL, - BF_STAGE_TOKEN, - BF_PROD_TOKEN, - v4BillingProfile -} from 'stores/common/Constants.js'; - -const handleResponse = ({ callback, dispatch, type }) => (err, res) => { - if (err) { - let message; - if (type === ACCOUNT) { - message = 'There was an error updating your account profile information. Please check your information and try again.'; - } else if (type === BILLING) { - message = 'There was an error updating your billing information. Please check your information and try again.'; - } - if (res && res.body) { - message = isString(res.body.detail) ? res.body.detail : res.body.message; - } - dispatch('BILLING_SUBMIT_ERROR', message); - callback(err, res); - } else if (res.ok) { - if (type === ACCOUNT) { - dispatch('BILLING_ACCOUNT_EXISTS'); - } else if (type === BILLING) { - dispatch('BILLING_INFO_EXISTS'); - } - const billforward_id = res.header[BILLFORWARD_ACCOUNT_ID]; - callback(null, { ...res.body, billforward_id }); - } -}; - -/* - NOTE: Stripe's api only accepts x-www-form-urlencoded data - NOTE: 'billforwardCreatePayment' is chained to this function and requires - `billforward-id`. The `billforward-id` is being passed through to the - create payment function via the META here. -*/ -function _createCardToken({ - cvc, - exp_month, - exp_year, - name_first, - name_last, - number -}, cb) { - const stripeToken = process.env.ENV === 'production' ? - STRIPE_PROD_TOKEN : STRIPE_STAGE_TOKEN; - const card = { - name: `${name_first} ${name_last}`, - cvc, - number, - exp_month, - exp_year - }; - const encoded = _encodeForm({ card }); - request.post(STRIPE_URL) - .accept('application/json') - .type('application/x-www-form-urlencoded') - .set('Authorization', 'Bearer ' + stripeToken) - .send(encoded) - .end(cb); -} - -/* - NOTE: This is the call to billforward that actually adds a payment method - to a user's billing profile. - This call requires a billforward-id (accountID) which is DIFFERENT than the - docker_id - Hence why 'billingCreatePaymentMethod' is NOT being wrapped by - the getAccountFromNamespace decorator. -*/ -function _billforwardAddPaymentMethod({ - '@type': type, - accountID, - cardID, - defaultPaymentMethod, - gateway, - stripeToken -}, cb) { - const billforwardUrl = process.env.ENV === 'production' ? - BF_PROD_URL : BF_STAGE_URL; - const billforwardToken = process.env.ENV === 'production' ? - BF_PROD_TOKEN : BF_STAGE_TOKEN; - - request.post(billforwardUrl) - .accept('application/json') - .type('application/json') - .set('Authorization', 'Bearer ' + billforwardToken) - .send({ - '@type': type, - accountID, - cardID, - defaultPaymentMethod, - gateway, - stripeToken - }) - .end(cb); -} - -//-------------------------------------------------------------------------- -// CREATE A BILLING PAYMENT METHOD ON BILLFORWAD WITH STRIPE -// DUPLICATED FROM ./createStripeSubscription.js -//-------------------------------------------------------------------------- -function billingCreatePaymentMethod(dispatch, { - billforwardId, - cvc, - exp_month, - exp_year, - name_first, - name_last, - number -}, cb) { - const cardData = { - cvc, - exp_month, - exp_year, - name_first, - name_last, - number - }; - /* - NOTE: - Creating a payment method requires 2 parts - 1 - Generating a token from Stripe's api - 2 - Sending generated token to Billforward's api to attach payment method to - a relevant billing profile. - */ - _createCardToken(cardData, (stripeErr, stripeRes) => { - if (!stripeRes.ok) { - let message = 'There was an error submitting your card information. Please check your information and try again.'; - if (stripeRes.error && stripeRes.error.message) { - message = stripeRes.error.message; - } - dispatch('BILLING_SUBMIT_ERROR', message); - cb(message); - } else { - const tokenObject = stripeRes && stripeRes.body; - const stripeToken = tokenObject.id; - const cardID = tokenObject.card.id; - const accountID = billforwardId; - const bfData = { - '@type': 'StripeAuthCaptureRequest', - accountID, - cardID, - defaultPaymentMethod: true, - gateway: 'Stripe', - stripeToken - }; - _billforwardAddPaymentMethod(bfData, handleResponse({callback: cb, dispatch, type: BILLING})); - } - }); -} -//-------------------------------------------------------------------------- -// SAVE ADDRESS INFORMATION IN BILLFORWARD -//-------------------------------------------------------------------------- -const updateV4BillingProfile = ({ JWT, profileData, docker_id }, cb) => { - const v4BillingAPI = v4BillingProfile(docker_id); - request - .patch(v4BillingAPI) - .accept('application/json') - .type('application/json') - .set('Authorization', 'Bearer ' + JWT) - .send(profileData) - .end(cb); -}; - -//-------------------------------------------------------------------------- -// UPDATE STRIPE BILLING INFORMATION -// NOTE: This will just add a payment method - creating multiple cards -//-------------------------------------------------------------------------- -function updateBillingInformation(actionContext, { - JWT, - user, - billingInfo, - accountInfo, - card, - billforwardId -}, done) { - actionContext.dispatch('BILLING_SUBMIT_START'); - let isOrg = false; - let username = ''; - if (has(user, 'username')) { - username = user.username; - } else if (has(user, 'orgname')) { - username = user.orgname; - isOrg = true; - } - const { - email, - first_name, - last_name, - company_name - } = accountInfo; - const { - address1, - address2, - country, - state, - zip, - city, - first_name: billing_first, - last_name: billing_last - } = billingInfo; - const { - number, - cvv, - month, - year - } = card; - - async.series([ - function(callback){ - const account = merge({}, accountInfo, {user: username}); - Billing.updateBillingAccount(JWT, username, account, handleResponse({callback, dispatch: actionContext.dispatch, type: ACCOUNT})); - }, - function(callback) { - /* - NOTE: - THIS WILL CREATE A NEW PAYMENT METHOD ON EVERY CALL - - In billforward this could potentially save multiple versions of the same card - - Solution would be to check whether the card is the same and decide to create or not - */ - billingCreatePaymentMethod(actionContext.dispatch, { - billforwardId, - cvc: cvv, - exp_month: month, - exp_year: year, - name_first: billing_first, - name_last: billing_last, - number - }, callback); - }, - function(callback) { - const profileData = { - first_name, - last_name, - addresses: [ - { - address_line_1: address1, - address_line_2: address2, - city, - province: state, - country, - post_code: zip, - primary_address: true - } - ] - }; - updateV4BillingProfile({ - JWT, - profileData, - docker_id: user.id - }, handleResponse({callback, dispatch: actionContext.dispatch, type: ACCOUNT})); - } - ], - function(err, res) { - if (err) { - done(); - } else { - if (isOrg) { - actionContext.history.push(`/u/${username}/dashboard/billing/`); - } else { - actionContext.history.push('/account/billing-plans/'); - } - actionContext.dispatch('BILLING_SUBMIT_SUCCESS'); - done(); - } - }); - - -} - -module.exports = updateBillingInformation; diff --git a/app/scripts/actions/updateSubscriptionPlanOrPackage.js b/app/scripts/actions/updateSubscriptionPlanOrPackage.js deleted file mode 100644 index b4ea288715..0000000000 --- a/app/scripts/actions/updateSubscriptionPlanOrPackage.js +++ /dev/null @@ -1,66 +0,0 @@ -'use strict'; -/*global UpdateBillingInfoPayload */ -import { Billing } from 'hub-js-sdk'; -import _ from 'lodash'; -const CLOUD_METERED = 'cloud_metered'; -var debug = require('debug')('hub:actions:updateSubscriptionPlanOrPackage'); - -function updateBillingSubscriptions(actionContext, { - coupon_code, - JWT, - package_code, - plan_code, - username, - subscription_uuid, - add_ons - }, done) { - actionContext.dispatch('UPDATE_PLAN_START', plan_code); - var data = { - username, - coupon_code, - add_ons - }; - - // we are either updating a plan or a package - if (plan_code) { - data.plan = plan_code; - } - if (package_code) { - data.package = package_code; - } - - // Explicitly remove all add ons (such as nautilus) when downgrading to - // a free account - if (plan_code === CLOUD_METERED) { - data.add_ons = []; - } - - if (!plan_code || plan_code === CLOUD_METERED) { - actionContext.dispatch('UNSUBSCRIBE_PLAN'); - } else if (!package_code) { - actionContext.dispatch('UNSUBSCRIBE_PACKAGE'); - } - Billing.updateBillingSubscriptions(JWT, subscription_uuid, username, data, function(err, res) { - if (err) { - debug(err); - const detail = err.response && err.response.body && err.response.body.detail; - const error = detail || 'Could not reach server.'; - actionContext.dispatch('UPDATE_PLAN_ERROR', error); - done(); - } else if (res.ok) { - Billing.getBillingSubscriptions(JWT, username, function(getErr, getRes) { - if (getErr) { - debug(getErr); - } else if (getRes.ok) { - let subscriptions = getRes.body; - let subscription = _.head(subscriptions); - // This will update your subscription in the store - while leaving the billing information the same - actionContext.dispatch('RECEIVE_BILLING_SUBSCRIPTION', {currentPlan: subscription}); - } - done(); - }); - } - }); -} - -module.exports = updateBillingSubscriptions; diff --git a/app/scripts/actions/updateToOrgOwner.js b/app/scripts/actions/updateToOrgOwner.js deleted file mode 100644 index 9ea02666c0..0000000000 --- a/app/scripts/actions/updateToOrgOwner.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -export default function(actionContext, payload) { - actionContext.dispatch('UPDATE_TO_ORG_OWNER', payload); -} diff --git a/app/scripts/actions/validateCouponCode.js b/app/scripts/actions/validateCouponCode.js deleted file mode 100644 index 0c3a8e57bc..0000000000 --- a/app/scripts/actions/validateCouponCode.js +++ /dev/null @@ -1,45 +0,0 @@ -'use strict'; -var debug = require('debug')('hub:actions:validateCouponCode'); - -module.exports = (actionContext, {coupon_code, plan}) => { - if (coupon_code) { - try { - /** - * This will only run where window is defined. ie: the browser - * It throws an exception in node - */ - window.recurly.configure(process.env.RECURLY_PUBLIC_KEY); - /* eslint-disable new-cap */ - var pricing = window.recurly.Pricing(); - /* eslint-enable new-cap*/ - pricing - .plan(plan, {quantity: 1}) - .coupon(coupon_code) - .catch(function(err) { - debug('ERROR', err); - actionContext.dispatch('BILLING_ERRORS', {fieldErrors: {coupon_code: true}}); - }) - .done(function(price) { - var discount = price.now.discount; - if (discount % 1 === 0) { - // remove the trailing decimals if its a whole number - discount = Math.round(discount); - } - actionContext.dispatch('UPDATE_COUPON_VALUE', discount); - if (discount <= 0) { - actionContext.dispatch('BILLING_ERRORS', {fieldErrors: {coupon_code: true}}); - } else { - actionContext.dispatch('BILLING_ERRORS', {fieldErrors: {coupon_code: false}}); - } - }); - } catch(e) { - debug('error', e); - actionContext.dispatch('BILLING_ERRORS', {fieldErrors: {coupon_code: true}}); - } - actionContext.dispatch('BILLING_INFO_UPDATE_FIELD_WITH_VALUE', {field: 'card', fieldKey: 'coupon_code', fieldValue: coupon_code}); - } else { - actionContext.dispatch('BILLING_ERRORS', {fieldErrors: {coupon_code: false}}); - actionContext.dispatch('BILLING_INFO_UPDATE_FIELD_WITH_VALUE', {field: 'card', fieldKey: 'coupon_code', fieldValue: ''}); - actionContext.dispatch('UPDATE_COUPON_VALUE', 0); - } -}; diff --git a/app/scripts/app.js b/app/scripts/app.js deleted file mode 100644 index 5aaec97293..0000000000 --- a/app/scripts/app.js +++ /dev/null @@ -1,103 +0,0 @@ -'use strict'; -const debug = require('debug')('hub:app'); -const Fluxible = require('fluxible'); - -let app = new Fluxible({ - component: require('./components/Routes.jsx'), - stores: [ - require('./stores/AccountInfoFormStore'), - require('./stores/AccountSettingsLicensesStore'), - require('./stores/AddOrganizationStore'), - require('./stores/AddTrialLicenseStore'), - require('./stores/AddWebhookFormStore'), - require('./stores/ApplicationStore'), - require('./stores/AutobuildConfigStore'), - require('./stores/AutoBuildSettingsStore'), - require('./stores/AutobuildSourceRepositoriesStore'), - require('./stores/AutobuildStore'), - require('./stores/AutobuildTagsStore'), - require('./stores/AutobuildTriggerByTagStore'), - require('./stores/BillingInfoFormStore'), - require('./stores/BillingPlansStore'), - require('./stores/BitbucketLinkStore'), - require('./stores/ChangePasswordStore'), - require('./stores/CloudCouponStore'), - require('./stores/CloudBillingStore'), - require('./stores/ConvertToOrgStore'), - require('./stores/CreateRepositoryFormStore'), - require('./stores/DashboardContribsStore'), - require('./stores/DashboardMembersStore'), - require('./stores/DashboardNamespacesStore'), - require('./stores/DashboardReposStore'), - require('./stores/DashboardStarsStore'), - require('./stores/DashboardStore'), - require('./stores/DashboardTeamsStore'), - require('./stores/DeletePipelineStore'), - require('./stores/DeleteRepoFormStore'), - require('./stores/EmailNotifStore'), - require('./stores/EmailsStore'), - require('./stores/EnterprisePaidFormStore'), - require('./stores/EnterprisePartnerTrackingStore'), - require('./stores/EnterpriseTrialFormStore'), - require('./stores/EnterpriseTrialSuccessStore'), - require('./stores/GithubLinkStore'), - require('./stores/JWTStore'), - require('./stores/LoginStore'), - require('./stores/NotifyStore'), - require('./stores/OrgTeamStore'), - require('./stores/OrganizationStore'), - require('./stores/OutboundCommunicationStore'), - require('./stores/PipelineHistoryStore'), - require('./stores/PlansStore'), - require('./stores/PrivateRepoUsageStore'), - require('./stores/RepoDetailsBuildLogs'), - require('./stores/RepoDetailsBuildsStore'), - require('./stores/RepoDetailsDockerfileStore'), - require('./stores/RepoDetailsLongDescriptionFormStore'), - require('./stores/RepoDetailsShortDescriptionFormStore'), - require('./stores/RepoDetailsVisibilityFormStore'), - require('./stores/RepoSettingsCollaborators'), - require('./stores/RepositoryCommentsStore'), - require('./stores/RepositoryPageStore'), - require('./stores/SearchStore'), - require('./stores/SignupStore'), - require('./stores/TriggerBuildStore'), - require('./stores/UserProfileReposStore'), - require('./stores/UserProfileStore'), - require('./stores/UserProfileStarsStore'), - require('./stores/UserStore'), - require('./stores/WebhooksSettingsStore') - ] -}); - -/** - * Add a plugin which adds the global redux store as .reduxStore to all flux - * actions. - * - * This allows us to call actionContext.reduxStore.dispatch() to dispatch - * actions from fluxible actions - */ -app.plug({ - name: 'ReduxActionIntegration', - plugContext(options, context) { - // Options should be passed reduxStore from the options passed into - // createContext - - return { - // Each action's context should also have the redux store that's defined - // within the app context. - plugActionContext(actionContext) { - // NOTE: Server-side rendering passes this in as options. - // Client-side rendering passes this in as context. - // Fluxible has no way to specify options within rehydration. - // We can only affect context. - - // This is defined in server.js within `server.use` for server-side - // rendering and within `app.rehydrate` in client.js - actionContext.reduxStore = options.reduxStore || context.reduxStore; - } - }; - } -}); - -export default app; diff --git a/app/scripts/bootstrapCreateElement.js b/app/scripts/bootstrapCreateElement.js deleted file mode 100644 index 1f9ccce538..0000000000 --- a/app/scripts/bootstrapCreateElement.js +++ /dev/null @@ -1,21 +0,0 @@ -'use strict'; - -import React from 'react'; -import provideContext from 'fluxible-addons-react/provideContext'; -const debug = require('debug')('hub:bootstrapCreateElement'); -/** - * We create a react element for the Router using this function, passing it to - * the `createElement` (func) property in . This will enable us to - * provide context for the Fluxible app and adds some context functions like - * `executeAction` and `getStore` to all components in our Routes. - * - * context is a Fluxible Context. - */ -export default (context) => { - return (component, props) => { - debug('setting context'); - props.context = context.getComponentContext(); - props.JWT = props.JWT || (props.cookies && props.cookies.JWT) || false; - return React.createElement(provideContext(component), props); - }; -}; diff --git a/app/scripts/client.js b/app/scripts/client.js deleted file mode 100644 index 54cdf61f0a..0000000000 --- a/app/scripts/client.js +++ /dev/null @@ -1,102 +0,0 @@ -/*global window, process, require */ -'use strict'; - -// Needed to shim Object.assign (used by 3rd party libs) -import 'babel-core/polyfill'; - -import React from 'react'; -import { render } from 'react-dom'; -import { Router } from 'react-router'; -import FluxRouter from './fluxibleRouter'; -import createHistory from 'history/lib/createBrowserHistory'; -import app from './app'; -import navigateAction from './actions/navigate'; -import JWTStore from './stores/JWTStore'; -import bootstrapCreateElement from './bootstrapCreateElement'; - -// This renders a Provider for basic flux integration -import { Provider } from 'react-redux'; -import reducers from './reducers'; -import enhancedCreateStore from './reduxStore'; - -require('velocity-animate'); -require('velocity-animate/velocity.ui'); - -let oDebug = require('debug'); -if (process.env.ENV !== 'production') { - oDebug.enable('hub:*'); -} -const debug = oDebug('hub:client'); -const dehydratedState = window.App; // Sent from the server - -if (process.env.ENV !== 'production') { - window.React = React; // For chrome dev tool support -} - -let history = createHistory(); -let unlisten = history.listen(function (location) { - debug('unlisten', location.pathname); -}); - -// Plug a History into the actionContext -let pluginRouter = Router; -app.plug({ - name: 'HistoryPlugin', - plugContext() { - return { - plugActionContext(actionContext) { - actionContext.history = history; - } - }; - } -}); - -function onUpdate(context) { - return (state, callback) => { - debug('at least the second render'); - if (state) { - if (!state.jwt) { - let jwtStore = context.getComponentContext().getStore(JWTStore); - state.jwt = jwtStore.getJWT(); - } - context.executeAction(navigateAction, state, callback); - } - }; -} - -function renderApp(context) { - const mountNode = document.getElementById('app'); - const Routes = app.getComponent(); - - // context.reduxStore works client-side as we're setting this directly - // below in rehydrate. - const jsx = ( - - - - ); - - return render(jsx, mountNode, () => { debug('React Rendered'); }); -} - -// The callback is called after the app has rehydrated any plugins; -// our redux plugin neets to create the store itself. -app.rehydrate(dehydratedState, function(err, context) { - debug('rehydrating app'); - if (err) { - throw err; - } - - // Create a new store and save it to Fluxible's app context. - context.reduxStore = enhancedCreateStore(reducers); - - window.context = context; - debug('supposedly the first render'); - // Don't call the action on the first render on top of the server rehydration - // Otherwise there is a race condition where the action gets executed before - // render has been called, which can cause the checksum to fail. - renderApp(context); -}); diff --git a/app/scripts/components/AddRepo.css b/app/scripts/components/AddRepo.css deleted file mode 100644 index f70fa38675..0000000000 --- a/app/scripts/components/AddRepo.css +++ /dev/null @@ -1,5 +0,0 @@ -@import 'dux/css/box.css'; - -.contentWrapper { - margin-top: var(--default-margin); -} diff --git a/app/scripts/components/AddRepo.jsx b/app/scripts/components/AddRepo.jsx deleted file mode 100644 index 21a6ef975d..0000000000 --- a/app/scripts/components/AddRepo.jsx +++ /dev/null @@ -1,259 +0,0 @@ -'use strict'; - -import React, { createClass, PropTypes } from 'react'; -import _ from 'lodash'; -import connectToStores from 'fluxible-addons-react/connectToStores'; - -import CreateRepositoryFormStore from 'stores/CreateRepositoryFormStore'; -import DUXInput from './common/DUXInput.jsx'; -import SimpleTextArea from './common/SimpleTextArea.jsx'; -import Route404 from './common/RouteNotFound404Page.jsx'; -import PrivateRepoUsageStore from 'stores/PrivateRepoUsageStore.js'; -import RepositoryNameInput from 'common/RepositoryNameInput.jsx'; -import createRepository from 'actions/createRepository'; -import updateAddRepositoryFormField from 'actions/updateAddRepositoryFormField'; -import getSettingsData from 'actions/getSettingsData'; -import { STATUS } from 'stores/common/Constants'; -import { SplitSection } from 'common/Sections'; - -import Markdown from '@dux/element-markdown'; -import Card, { Block } from '@dux/element-card'; -import { PageHeader, Button } from 'dux'; -import styles from './AddRepo.css'; -import DocumentTitle from 'react-document-title'; - -var debug = require('debug')('AddRepositoryForm'); - -var AddRepositoryForm = createClass({ - displayName: 'AddRepositoryForm', - contextTypes: { - executeAction: PropTypes.func.isRequired - }, - propTypes: { - JWT: PropTypes.string.isRequired, - createRepoFormStore: PropTypes.shape({ - fields: PropTypes.object.isRequired, - values: PropTypes.object.isRequired, - namespaces: PropTypes.arrayOf(PropTypes.string.isRequired).isRequired, - globalFormError: PropTypes.string - }), - privateRepoUsage: PropTypes.shape({ - privateRepoAvailable: PropTypes.number.isRequired - }) - }, - getInitialState: function() { - return { - currentNamespace: this.props.createRepoFormStore.values.namespace - }; - }, - _handleCreate: function(e) { - e.preventDefault(); - - var newRepo = { - namespace: this.state.currentNamespace, - name: this.props.createRepoFormStore.values.name.toLowerCase(), - description: this.props.createRepoFormStore.values.description, - full_description: this.props.createRepoFormStore.values.full_description, - is_private: this.props.createRepoFormStore.values.is_private === 'private' - }; - - this.context.executeAction(createRepository, - { - jwt: this.props.JWT, - repository: newRepo - }); - }, - _onChange(fieldKey) { - let _this = this; - return (e) => { - if (fieldKey === 'namespace') { - this.setState({ - currentNamespace: e.target.value - }); - this.context.executeAction(getSettingsData, { - JWT: _this.props.JWT, - username: e.target.value, - repoType: 'regular' - }); - } - this.context.executeAction(updateAddRepositoryFormField, { - fieldKey, - fieldValue: e.target.value - }); - }; - }, - _getCurrentQueryNamespace() { - //Check if user has passed in namespace as query | verify if they have access to it - var currentNamespace = this.props.location.query.namespace; - if (!_.includes(this.props.createRepoFormStore.namespaces, currentNamespace)) { - currentNamespace = this.props.createRepoFormStore.values.namespace; - } - return currentNamespace; - }, - componentDidMount() { - this.setState({ - currentNamespace: this._getCurrentQueryNamespace() - }); - }, - _renderCreateForm() { - const { createRepoFormStore } = this.props; - - var globalFormError = (
); - if(createRepoFormStore.globalFormError) { - globalFormError = ( -
{createRepoFormStore.globalFormError}
- ); - } - - var nameError = (

); - var nameClass = ''; - if(createRepoFormStore.fields.name.hasError) { - nameError = ( -

- {createRepoFormStore.fields.name.error + - ' No spaces and special characters other than - and . are allowed. Repo names should not begin/end with a . or - .'} -

- ); - nameClass = 'text-error'; - } - - var fullDescriptionError = (

); - var fullDescriptionClass = 'large-12 columns'; - if(createRepoFormStore.fields.full_description.hasError) { - fullDescriptionError = ( -

{createRepoFormStore.fields.full_description.error}

- ); - fullDescriptionClass = 'large-12 columns form-error'; - } - - var descriptionError = (

); - var descriptionClass = 'large-12 columns'; - if(createRepoFormStore.fields.description.hasError) { - descriptionError = ( -

{createRepoFormStore.fields.description.error}

- ); - descriptionClass = 'large-12 columns form-error'; - } - var defaultValue = createRepoFormStore.values.is_private ? 'private' : 'public'; - var errText = ''; - if (createRepoFormStore.fields.is_private.hasError) { - errText = - - {createRepoFormStore.fields.is_private.error} - ; - } - const subtitleContent = `1. Choose a namespace *(Required)* -2. Add a repository name *(Required)* -3. Add a short description -4. Add markdown to the full description field -5. Set it to be a private or public repository`; - - return ( - {subtitleContent}}> -
- {globalFormError} -
-
- - {nameError} -
- -
-
- - {descriptionError} -
-
- -
-
- - {fullDescriptionError} -
-
- -
-
- Visibility - - {errText} -
-
- - - -
-
-
- ); - }, - render() { - if (!this.props.JWT) { - return (); - } else { - let content = ( -
-
- - -

Something went wrong!

-

- We were unable to populate your user namespaces. - If this issue persists, please contact support@docker.com -  or file an issue at hub-feedback on github -

-
-
-
-
- ); - if ( this.props.createRepoFormStore.namespaces && this.props.createRepoFormStore.namespaces.length > 0 ) { - content = ( -
- {this._renderCreateForm()} -
- ); - } - - return ( - -
- - { content } -
-
- ); - } - } -}); - -export default connectToStores(AddRepositoryForm, - [ - CreateRepositoryFormStore - ], - function({ getStore }, props) { - return { - createRepoFormStore: getStore(CreateRepositoryFormStore).getState() - }; - }); diff --git a/app/scripts/components/Application.css b/app/scripts/components/Application.css deleted file mode 100644 index b8cb605434..0000000000 --- a/app/scripts/components/Application.css +++ /dev/null @@ -1,31 +0,0 @@ -.main{ - display:flex; - flex-direction: column; - justify-content: flex-start; - min-height: 100vh; -} - -.storePromo { - text-align: center; - padding-left: 2rem; - padding-top: 0.3rem; - padding-bottom: 0.3rem; - color: white; - - /* set fallback in case multiple background images are not supported */ - background-color: #008BBF; - background-image: - linear-gradient(-74deg, transparent 90%, rgba(255, 255, 255, 0.23) 20%), - linear-gradient(-74deg, transparent 83%, rgba(255, 255, 255, 0.18) 15%), - linear-gradient(-74deg, transparent 76%, rgba(255, 255, 255, 0.1) 15%); - - a { - padding-bottom: 0.3rem; - color: inherit; - text-decoration: none; - } - - .storePromoUnderline { - text-decoration: underline; - } -} diff --git a/app/scripts/components/Application.jsx b/app/scripts/components/Application.jsx deleted file mode 100644 index f7655f9352..0000000000 --- a/app/scripts/components/Application.jsx +++ /dev/null @@ -1,135 +0,0 @@ -'use strict'; - -const debug = require('debug')('Application'); -import ApplicationStore from '../stores/ApplicationStore'; -import JWTStore from '../stores/JWTStore'; -import UserStore from '../stores/UserStore.js'; -import React, { PropTypes, Component, cloneElement } from 'react'; -import Welcome from './Welcome.jsx'; -import connectToStores from 'fluxible-addons-react/connectToStores'; -import Spinner from './Spinner.jsx'; -import MainNav from './Nav.jsx'; -import styles from './Application.css'; -import DocumentTitle from 'react-document-title'; -import merge from 'lodash/object/merge'; -import { STORE_OFFICIAL_REPONAME_ID_MAP } from './store-promotion'; - -class Application extends Component { - - renderGenericStorePromo() { - return ( - - ); - } - - renderRepoStorePromo(name, id) { - return ( - - ); - } - - - render() { - //Destructure router and props - const { JWT, user, location, history, params } = this.props; - //We use !JWT to check if a user is in logged out state - - if (!JWT && location.pathname === '/') { - debug('Out Home'); - return ( - -
- - -
-
- ); - } else if (history.isActive('/login/') || history.isActive('/reset-password/')) { - debug('Application'); - return ( - -
- {this.props.children} -
-
- ); - } else { - debug('Root'); - - // Render store promotion based on the current location and only if the - // store-promo flag is set. - let promo = null; - const storePromoFlag = this.props.location.query['store-promo'] === '1'; - if (storePromoFlag) { - if (history.isActive('/_/') || - location.pathname.indexOf('/r/library/') === 0) { - const name = params.splat; - const id = STORE_OFFICIAL_REPONAME_ID_MAP[name]; - if (name && id) { - promo = this.renderRepoStorePromo(name, id); - } - } else if (history.isActive('/search/')) { - promo = this.renderGenericStorePromo(); - } else if (history.isActive('/explore/')) { - promo = this.renderGenericStorePromo(); - } - } - - const ifJWT = JWT ? JWT : ''; - return ( - -
- {promo} - - {this.props.children && cloneElement(this.props.children, { - JWT: ifJWT, - user, - location - })} -
-
- ); - } - } -} - -export default connectToStores(Application, - [ - ApplicationStore, - JWTStore, - UserStore - ], - ({ getStore }, props) => { - return merge({}, - getStore(ApplicationStore).getState(), - { - JWT: getStore(JWTStore).getJWT(), - user: getStore(UserStore).getState() - }); - }); diff --git a/app/scripts/components/Badge.jsx b/app/scripts/components/Badge.jsx deleted file mode 100644 index 254a2cf6eb..0000000000 --- a/app/scripts/components/Badge.jsx +++ /dev/null @@ -1,17 +0,0 @@ -'use strict'; - -import React from 'react'; - -var Badge = React.createClass({ - render: function() { - var name = this.props.name; - var category = this.props.category; - return ( -
-
{name}
-
- ); - } -}); - -module.exports = Badge; diff --git a/app/scripts/components/CSEngineDownloadPage.css b/app/scripts/components/CSEngineDownloadPage.css deleted file mode 100644 index ef0891456a..0000000000 --- a/app/scripts/components/CSEngineDownloadPage.css +++ /dev/null @@ -1,3 +0,0 @@ -.pageWrapper { - padding-top: 1.25rem; -} \ No newline at end of file diff --git a/app/scripts/components/CSEngineDownloadPage.jsx b/app/scripts/components/CSEngineDownloadPage.jsx deleted file mode 100644 index a9741e14b3..0000000000 --- a/app/scripts/components/CSEngineDownloadPage.jsx +++ /dev/null @@ -1,20 +0,0 @@ -'use strict'; - -import React, { PropTypes, Component } from 'react'; -import CSEngineBox from 'common/CSEngineBox'; -import styles from './CSEngineDownloadPage.css'; - -//publicly accessible page for only CS engine download -export default class CSEngineDownloadPage extends Component { - render() { - return ( -
-
-
- -
-
-
- ); - } -} diff --git a/app/scripts/components/CreateButton.jsx b/app/scripts/components/CreateButton.jsx deleted file mode 100644 index 458fe26762..0000000000 --- a/app/scripts/components/CreateButton.jsx +++ /dev/null @@ -1,24 +0,0 @@ -'use strict'; -import React from 'react'; -import _ from 'lodash'; -import { FluxibleMixin } from 'fluxible'; - -var CreateButton = React.createClass({ - propTypes: { - what: React.PropTypes.string.isRequired - }, - getDefaultProps: function() { - return { - what: '' - }; - }, - render: function() { - return ( - - ); - } -}); - -module.exports = CreateButton; diff --git a/app/scripts/components/DashboardWrapper.css b/app/scripts/components/DashboardWrapper.css deleted file mode 100644 index d22ed0dc67..0000000000 --- a/app/scripts/components/DashboardWrapper.css +++ /dev/null @@ -1,4 +0,0 @@ -.select { - margin-top: 6px; - min-width: 200px; -} diff --git a/app/scripts/components/DashboardWrapper.jsx b/app/scripts/components/DashboardWrapper.jsx deleted file mode 100644 index 31627c12b6..0000000000 --- a/app/scripts/components/DashboardWrapper.jsx +++ /dev/null @@ -1,98 +0,0 @@ -'use strict'; - -import React, { Component, PropTypes, cloneElement } from 'react'; -import { Link } from 'react-router'; -import connectToStores from 'fluxible-addons-react/connectToStores'; -import trunc from 'lodash/string/trunc'; -import PrivateReposBlock from './dashboards/PrivateRepoStatusBlock.jsx'; -import DashboardNamespacesStore from '../stores/DashboardNamespacesStore'; -import { SecondaryNav } from 'dux'; -import GravatarOption from './gravatar/GravatarOption'; -import GravatarValue from './gravatar/GravatarValue'; -import FA from './common/FontAwesome'; -import LiLink from './common/LiLink'; -import Select from 'react-select'; -import styles from './DashboardWrapper.css'; - -const { array, func, shape, string } = PropTypes; -const debug = require('debug')('DashboardWrapper'); - -class DashboardWrapper extends Component { - - static propTypes = { - //currentUserContext (dashboard user context, could be logged in user or one of the user's orgs) - //namespaces (all the namespaces that the user can look at) - dashboardNamespaces: shape({ - currentUserContext: string.isRequired, - namespaces: array.isRequired - }), - JWT: string, - user: shape({ - username: string - }) - } - - mkOptions = (arr) => { - return arr.map((namespace) => { - return {value: namespace, label: trunc(namespace, 16)}; - }); - }; - - changeContext = ({value: namespace, label}) => { - if (namespace) { - const { dashboardNamespaces, user, history, location } = this.props; - let currentPage = parseInt(location.query.page, 10); - if (dashboardNamespaces.currentUserContext === namespace) { - //do nothing - debug('doing nothing. Namespace is the same'); - } else if (user.username === namespace) { - //navigate to home - debug('navigate to home; its a user namespace'); - history.pushState(null, '/', {page: currentPage || 1}); - } else { - //navigate to org dashboard - debug('navigate to org dashboard'); - history.pushState(null, `/u/${namespace}/dashboard/`); - } - } - }; - - render() { - const { children, dashboardNamespaces, JWT, user } = this.props; - return ( -
- -
    -
  • - -
  • - - Repositories - - - Teams - - { Billing } - { Settings } -
- -
- {cloneElement(children, { - JWT, - user: org, - isOwner, - currentUserContext - })} -
- ); - } else { - return ( - - ); - } - } -} - -export default connectToStores(OrgDashboardWrapper, - [ - DashboardNamespacesStore, - OrganizationStore - ], - function({ getStore }, props) { - return merge( - {}, - getStore(DashboardNamespacesStore).getState(), - {org: getStore(OrganizationStore).getCurrentOrg()} - ); - }); diff --git a/app/scripts/components/Register.css b/app/scripts/components/Register.css deleted file mode 100644 index 9a60f5fef6..0000000000 --- a/app/scripts/components/Register.css +++ /dev/null @@ -1,11 +0,0 @@ -@import "dux/css/colors.css"; -@import "dux/css/box.css"; - -/* Upper Section */ -.header { - background: var(--docker-dark); - color: var(--smoke); - min-height: 560px; - height: 100%; - padding-top: 75px; -} diff --git a/app/scripts/components/Register.jsx b/app/scripts/components/Register.jsx deleted file mode 100644 index 13b71b6b9f..0000000000 --- a/app/scripts/components/Register.jsx +++ /dev/null @@ -1,23 +0,0 @@ -'use strict'; - -import styles from './Register.css'; - -import React, { Component, PropTypes } from 'react'; -import SignupForm from './welcome/SignupForm.jsx'; -var debug = require('debug')('Register'); - -export default class Register extends Component { - render() { - return ( -
-
- -
- -
- -
-
- ); - } -} diff --git a/app/scripts/components/RepositoryPageWrapper.css b/app/scripts/components/RepositoryPageWrapper.css deleted file mode 100644 index 87f9cfb4d5..0000000000 --- a/app/scripts/components/RepositoryPageWrapper.css +++ /dev/null @@ -1,31 +0,0 @@ -@import "dux/css/colors.css"; - -.repoLabel { - text-transform: uppercase; - font-weight: 500; -} - -.repoHeader { - border-bottom: 1px solid #c1c9d1; - background-color: white; - padding-top: 1.6rem; - padding-bottom: 1.2rem; -} -.repoTitle { - color: #555; - margin-bottom: 0; - font-weight: 300; -} -.repoSubtitle { - color: var(--secondary-5); - display: block; -} - -.repoStar { - cursor: pointer; - color: var(--secondary-3); - margin-left: 1rem; - font-size: xx-large; -} - -.private {} \ No newline at end of file diff --git a/app/scripts/components/RepositoryPageWrapper.jsx b/app/scripts/components/RepositoryPageWrapper.jsx deleted file mode 100644 index ef3ceb7888..0000000000 --- a/app/scripts/components/RepositoryPageWrapper.jsx +++ /dev/null @@ -1,187 +0,0 @@ -'use strict'; - -import styles from './RepositoryPageWrapper.css'; -import React, { PropTypes, Component, cloneElement } from 'react'; -const { string, number, bool, shape, array, object, func } = PropTypes; -import { Link } from 'react-router'; -import _ from 'lodash'; -import includes from 'lodash/collection/includes'; -import merge from 'lodash/object/merge'; -import omit from 'lodash/object/omit'; -import words from 'lodash/string/words'; -import moment from 'moment'; -import FA from 'common/FontAwesome'; -const REPOSTATUS = require('../stores/repostore/Constants').STATUS; - -import RouteNotFound404Page from 'common/RouteNotFound404Page'; -import toggleStarred from '../actions/toggleStarred'; -import RepositoryPageStore from '../stores/RepositoryPageStore'; -import DashboardNamespacesStore from '../stores/DashboardNamespacesStore'; -import connectToStores from 'fluxible-addons-react/connectToStores'; -import DocumentTitle from 'react-document-title'; - -var debug = require('debug')('RepositoryPageWrapper'); - -class Privacy extends Component { - static propTypes = { - isOfficial: bool.isRequired, - isPrivate: bool.isRequired, - isAutomated: bool.isRequired - } - render() { - const publicOrPrivate = this.props.isPrivate ? 'Private' : 'Public'; - if (this.props.isOfficial) { - return ( -
-
Official Repository
-
- ); - } else if (this.props.isAutomated) { - return ( -
-
{publicOrPrivate} | Automated Build
-
- ); - } else { - return ( -
-
{publicOrPrivate} Repository
-
- ); - } - } -} - -class StarRepo extends Component { - static propTypes = { - hasStarred: bool.isRequired, - toggleStar: func.isRequired - } - render() { - const { toggleStar, hasStarred } = this.props; - - let toggle = toggleStar(true); - let icon = 'fa-star-o'; - - if (hasStarred) { - toggle = toggleStar(false); - icon = 'fa-star'; - } - - return ( - - - - ); - } -} - -class RepositoryPageWrapper extends Component { - static propTypes = { - description: string.isRequired, - fullDescription: string.isRequired, - hasStarred: bool.isRequired, - isPrivate: bool.isRequired, - isAutomated: bool.isRequired, - lastUpdated: string, - name: string.isRequired, - namespace: string.isRequired, - status: number.isRequired, - canEdit: bool.isRequired, - comments: shape({ - count: number.isRequired, - results: array.isRequired - }), - user: object, - JWT: string, - history: object.isRequired, - ownedNamespaces: array.isRequired, - namespaces: array, - currentUserContext: string - } - - static contextTypes = { - executeAction: func.isRequired - } - - _toggleStar = status => e => { - e.preventDefault(); - var repoShortName = this.props.namespace + '/' + this.props.name; - this.context.executeAction(toggleStarred, { - jwt: this.props.JWT, - repoShortName: repoShortName, - status: status - }); - }; - - render() { - if (this.props.STATUS === REPOSTATUS.REPO_NOT_FOUND) { - return ; - } - - let privacy; - - //Redirect to user profile page if public user, if org (and owner) redirect to dashboard, if public org, org profile page - let namespaceLink; - var {namespace, ownedNamespaces, user} = this.props; - if (includes(ownedNamespaces, this.props.namespace) && namespace !== user.username) { - namespaceLink = {this.props.namespace}; - } else { - namespaceLink = {this.props.namespace}; - } - const starRepo = ; - let repoShortName = ( -
- {namespaceLink} - / - {this.props.name} - {starRepo} -
- ); - if (this.props.isOfficial || this.props.namespace === 'library') { - repoShortName = ( -
- {this.props.name} - {starRepo} -
- ); - } - - let computedLastUpdated = 'never'; - if (this.props.lastUpdated) { - computedLastUpdated = moment(this.props.lastUpdated).fromNow(); - } - - return ( - -
-
-
-
- -

{repoShortName}

- Last pushed: {computedLastUpdated} -
-
-
- {this.props.children && cloneElement(this.props.children, omit(this.props, 'children'))} -
-
- ); - } -} - -export default connectToStores(RepositoryPageWrapper, - [ - RepositoryPageStore, - DashboardNamespacesStore - ], - ({ getStore }, props) => { - return merge({}, - getStore(DashboardNamespacesStore).getState(), - getStore(RepositoryPageStore).getState()); - }); diff --git a/app/scripts/components/Routes.css b/app/scripts/components/Routes.css deleted file mode 100644 index 2f483ab999..0000000000 --- a/app/scripts/components/Routes.css +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Adding global css in Routes.css to load class names as-is so we don't have local processed classes - * - * vendor overrides - * ---------------- - * 1. react-select [styles/vendor-overrides/react-select.css] - * 2. rc-tooltip [styles/vendor-overrides/rc-tooltip.css] - * - */ -:global { - @import '../../styles/vendor-overrides/react-select.css'; - /** Default styles from rc-tooltip which will be overwritten **/ - @import "rc-tooltip/assets/bootstrap_white.css"; - @import '../../styles/vendor-overrides/rc-tooltip.css'; -} diff --git a/app/scripts/components/Routes.jsx b/app/scripts/components/Routes.jsx deleted file mode 100644 index 713b0d8100..0000000000 --- a/app/scripts/components/Routes.jsx +++ /dev/null @@ -1,212 +0,0 @@ -'use strict'; - -import { - Route, Redirect, IndexRoute -} from 'react-router'; -import React from 'react'; -import styles from './Routes.css'; - -const Account = require('./account/Account'); -const AccountSettings = require('./account/AccountSettings'); -const AddOrganizationForm = require('./account/AddOrganizationForm'); -import AddRepo from './AddRepo'; -const Application = require('./Application'); -const Autobuild = require('./repositories/Autobuild'); -const AutobuildIndex = require('./repositories/AutobuildIndex.jsx'); -const AutoBuildSetupForm = require('./repositories/AutoBuildSetupForm'); -const BillingPlans = require('./account/BillingPlans'); -import UpdateBillingInfo from './account/UpdateBillingInfo'; -import ChangePassSuccess from './welcome/ChangePassSuccess'; -import CreateBillingSubscription from './account/CreateBillingSubscription'; -import ConvertToOrg from './account/ConvertToOrg'; -import CSEngineDownloadPage from './CSEngineDownloadPage'; -import DashboardContribs from './dashboards/Contribs'; -import DashboardWrapper from './DashboardWrapper'; -import DashboardRepos from './dashboards/Repos'; -import DashboardStars from './dashboards/Stars'; -import orgDashTeams from './orgdashboards/Teams'; -import Dockerfile from './repo/repo_details/Dockerfile'; -import Explore from './Explore'; -import EnterpriseSubscriptions from './enterprise/Enterprise'; -import ServerTrial from './enterprise/EnterpriseTrial'; -import EnterpriseTrialSuccess from './enterprise/EnterpriseTrialSuccess'; -import EULA from './EULA'; -import EnterpriseTrialTerms from './enterprise/EnterpriseTrialTerms.jsx'; -import ForgotPassword from './welcome/ForgotPass'; -import GithubLinkScopes from './account/services/GithubLinkScopes'; -import Help from './help/Help'; -import Licenses from './account/Licenses'; -const LinkedAccountSourcesForm = require('./repositories/LinkedAccountSourcesForm'); -const LinkedServices = require('./account/LinkedServices'); -import Login from './Login'; -import Members from './orgdashboards/Members'; -const NotificationsSettings = require('./account/NotificationsSettings'); -const OrganizationProfile = require('./account/orgs/OrganizationProfile'); -const OrganizationSettings = require('./account/OrganizationSettings'); -const OrganizationSummary = require('./account/OrganizationSummary'); -import OrgDashboardWrapper from './OrgDashboardWrapper'; -import Register from './Register'; -import RepositorySettingsBuilds from './repo/repoSettings/Builds'; -import RepositorySettingsCollaborators from './repo/repoSettings/CollaboratorsWrapper.jsx'; -import RepositorySettingsMain from './repo/repoSettings/SettingsMain'; -import RepositorySettingsWebhooks from './repo/repoSettings/webhooks'; -import RepositorySettingsWrapper from './repo/RepositorySettingsWrapper'; -import RepositoryDetailsBuildDetails from './repo/repo_details/BuildDetails'; -import RepositoryDetailsBuildLogs from './repo/repo_details/BuildLogs'; -import RepositoryDetailsInfo from './repo/repo_details/Info'; -import RepositoryDetailsTags from './repo/repo_details/Tags'; -import RepositoryDetailsScannedTag from './repo/repo_details/ScannedTag'; -import RepositoryDetailsWrapper from './repo/RepositoryDetailsWrapper'; -import RepositoryPageWrapper from './RepositoryPageWrapper'; -import ResetPassword from './welcome/ResetPass'; -import RouteNotFound404Page from './common/RouteNotFound404Page'; -const Search = require('./search/Search'); -const UserStars = require('./userWrapper/UserStars'); -const User = require('./Users'); //Unused -import UserProfileWrapper from './UserProfileWrapper'; -import UserProfileRepos from './userprofile/Repos'; - -// NOTE: Provider right now doesn't work easily with fluxible's render pipeline. -// Even though we add the as a root element to Routes.jsx: -// -// module.exports = ( -// -// { routes } -// -// ); -// -// Fluxible doesn't render the root Provider component; it renders the first -// component which connects to fluxibles stores. -// -// FIX: We've instead added as the base class that fluxibleRouter -// renders -// -// TODO: When we rip out Fluxible add as a top level component here. - -var routes = ( - - {/* Login and Password */} - - - - - - {/* Currently logged in user Dashboard */} - - - - - - - {/* Public user profile */} - - - - - - {/* Organization Dashboard */} - - - - - - - - - - {/* Organizations Summary and Add Route */} - - - - - - {/* Add a repository route */} - - - {/* Autobuild creation related routes */} - - - - - - - - - {/* Github linking related route | the scope selection screen */} - - - {/* Official repositories route | TODO: add library/:name */} - - - - - - - {/* THIS ROUTE IS A DUPLICATE OF /u/:user/. WHY IS THIS HERE??? */} - - - - - - - - - - - - - - - - - - - - - - {/* User Account Settings */} - - - - - - - - - - - - - - - - - {/* Billing/Enterprise/Subscription related routes */} - - - {/* TODO: @camacho 2/9/16 - remove routes after 1 week to give time for loaded clients to be updated*/} - - - - - - - - - - {/* Some publicly available routes to explore, search and ask for help */} - - - - - - {/* Handle 404 for bad routes | If no route matches, render a 404 page */} - - -); - -module.exports = routes; diff --git a/app/scripts/components/Spinner.jsx b/app/scripts/components/Spinner.jsx deleted file mode 100644 index 9a90885587..0000000000 --- a/app/scripts/components/Spinner.jsx +++ /dev/null @@ -1,20 +0,0 @@ -'use strict'; -const React = require('react'); - -var Spinner = React.createClass({ - render: function() { - return (
-
-
-
-
-
-
-
-
-
-
); - } -}); - -module.exports = Spinner; diff --git a/app/scripts/components/StatsComponent.jsx b/app/scripts/components/StatsComponent.jsx deleted file mode 100644 index f285424eba..0000000000 --- a/app/scripts/components/StatsComponent.jsx +++ /dev/null @@ -1,26 +0,0 @@ -'use strict'; -import React from'react'; - -//TODO: add to component, currently just use a placeholder docker icon -//
    -//
  • {this.props.value}
  • -//
  • {this.props.statsItemName}
  • -//
- -var StatsComponent = React.createClass({ - displayName: 'StatsComponent', - propTypes: { - value: React.PropTypes.string.isRequired, - statsItemName: React.PropTypes.string.isRequired - }, - render: function() { - return ( -
-

{this.props.value}

-

{this.props.statsItemName}

-
- ); - } -}); - -module.exports = StatsComponent; diff --git a/app/scripts/components/UserProfileWrapper.css b/app/scripts/components/UserProfileWrapper.css deleted file mode 100644 index 4059138564..0000000000 --- a/app/scripts/components/UserProfileWrapper.css +++ /dev/null @@ -1,27 +0,0 @@ -@import "dux/css/colors.css"; -@import "dux/css/box.css"; - -.heading { - padding-left: 1rem; -} - -.userinfo { - border-top: 1px solid var(--secondary-5); - border-bottom: 1px solid var(--secondary-5); - padding: 1rem; - margin-right: 1rem; - list-style-type: none; -} - - .item { - width: 260px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.gravatar { - border: 1px solid var(--secondary-5); - margin: 1rem 0; - border-radius: 3px; -} diff --git a/app/scripts/components/UserProfileWrapper.jsx b/app/scripts/components/UserProfileWrapper.jsx deleted file mode 100644 index d859f0de65..0000000000 --- a/app/scripts/components/UserProfileWrapper.jsx +++ /dev/null @@ -1,127 +0,0 @@ -'use strict'; - -import React, { PropTypes, createClass, cloneElement } from 'react'; -import connectToStores from 'fluxible-addons-react/connectToStores'; -import UserProfileStore from '../stores/UserProfileStore'; -import RepositoriesList from './common/RepositoriesList'; -import RouteNotFound404Page from './common/RouteNotFound404Page'; -import moment from 'moment'; -import { SecondaryNav } from 'dux'; -import FA from 'common/FontAwesome'; -import { Link } from 'react-router'; -import _ from 'lodash'; -import styles from './UserProfileWrapper.css'; -import DocumentTitle from 'react-document-title'; - -var debug = require('debug')('UserProfileWrapper'); - -var UserShape = { - id: PropTypes.string.isRequired, - username: PropTypes.string, - orgname: PropTypes.string, - full_name: PropTypes.string.isRequired, - location: PropTypes.string.isRequired, - company: PropTypes.string.isRequired, - profile_url: PropTypes.string.isRequired, - date_joined: PropTypes.string.isRequired, - gravatar_url: PropTypes.string.isRequired -}; - -var ProfileCard = createClass({ - displayName: 'ProfileCard', - propTypes: UserShape, - render() { - var gravatar = this.props.gravatar_url; - /** - * If the gravatar has a size equal to 80 in the url, - * change it to 512. This is a HACK. - */ - if(this.props.gravatar_url && this.props.gravatar_url.match(/s=80/)) { - gravatar = gravatar.replace('s=80', 's=512'); - } - - var maybeLocation = null; - var maybeCompany = null; - var maybeProfileUrl = null; - - if (this.props.location) { - maybeLocation =
  • {this.props.location}
  • ; - } - if (this.props.maybeCompany) { - maybeCompany =
  • {this.props.company}
  • ; - } - if (this.props.profile_url) { - maybeProfileUrl =
  • {this.props.profile_url}
  • ; - } - - return ( -
    -
    -
    - -
    -
    -
    -

    {this.props.username || this.props.orgname}

    -

    {this.props.full_name}

    -
      - {maybeLocation} - {maybeCompany} - {maybeProfileUrl} -
    • Joined {moment(this.props.date_joined).format('MMMM YYYY')}
    • -
    -
    -
    - ); - } -}); - -var UserProfile = createClass({ - displayName: 'UserProfile', - propTypes: { - user: PropTypes.shape(UserShape) - }, - render() { - if(this.props.STATUS === '404' || _.isEmpty(this.props.user)) { - return (); - } else { - let namespace; - var maybeStars = null; - if(this.props.user.orgname) { - namespace = this.props.user.orgname; - } else { - namespace = this.props.user.username; - maybeStars = (
  • Stars
  • ); - } - return ( - -
    - -
      -
    • Repos
    • - {maybeStars} -
    -
    -
    -
    - -
    -
    - {this.props.children && cloneElement(this.props.children, {user: this.props.user})} -
    -
    -
    -
    - ); - } - } -}); - -export default connectToStores(UserProfile, - [ - UserProfileStore - ], - function({ getStore }, props) { - return getStore(UserProfileStore) - .getState(); - }); diff --git a/app/scripts/components/Users.jsx b/app/scripts/components/Users.jsx deleted file mode 100644 index 1e173210da..0000000000 --- a/app/scripts/components/Users.jsx +++ /dev/null @@ -1,60 +0,0 @@ -'use strict'; -/** -TODO: UNUSED COMPONENTS. SHOULD REMOVE -*/ -import React from 'react'; -import { Link } from 'react-router'; - -var UserPage = React.createClass({ - getDefaultProps: function() { - return { - user: {}, - JWT: '' - }; - }, - render: function() { - return ( -
    - This will be the base wrapper of the 'Users' page where either your or another users profile will appear
    - This will let you see your public facing page at /u/username/ too
    - 'Your' homepage/dashboard will live at /home/
    - -
    - ); - } -}); - -var RootUser = React.createClass({ - render: function() { - return ( -
    -

    - This is root user page.
    - When not looking at a specific user or an owned image
    - This will show a list of repos/images owned by the root user
    - This could be a image box of some sort -

    - ); - } -}); - -var User = React.createClass({ - // This page should either be the users home page or the view page for other users - render: function() { - return ( -
    -

    - This is the UID: {this.props.params.uid}
    - This is main user page.
    - This will show a list of repos/images owned by the user
    - -

    - ); - } -}); - -module.exports = { - userpage: UserPage, - rootuser: RootUser, - user: User -}; diff --git a/app/scripts/components/Welcome.css b/app/scripts/components/Welcome.css deleted file mode 100644 index 7c4be7573f..0000000000 --- a/app/scripts/components/Welcome.css +++ /dev/null @@ -1,86 +0,0 @@ -@import "dux/css/colors.css"; -@import "dux/css/box.css"; - -.flex{ - display:flex; - flex-direction: column; - justify-content: flex-start; - flex-grow: 1; -} - -.white { - background-color: var(--white); - flex-grow: 1; - padding-top: calc(var(--default-margin) * 1.5); -} - -.browse { - padding: .5rem 0; - text-align: center; -} - -/* Upper Section */ -.header { - background: var(--docker-dark); - color: var(--smoke); - min-height: 560px; - padding-top: 75px; -} - -.top { - padding: 0 var(--default-margin); -} - -.buildShipRun { - margin-top: 5rem; -} - -.subtext { - color: var(--white); -} - -.heading { - font-weight: 300; - color: var(--smoke); -} - -.headingHero { - composes: heading; - font-size: 3rem; - line-height: 0.8; -} - -.headingHeroAlt { - composes: headingHero; - color: var(--primary-color); -} - -/* Lower Section */ -.lowerHeading { - text-align: center; - margin-bottom: var(--default-margin); -} - -/* Company List */ -.companyRow { - padding: 1.5rem 0 .5rem 0; - margin-left: 0; - margin-right: 0; - margin-bottom: var(--default-margin); -} - -.companyLinkLi { - text-align: center; -} - -/* Footer */ -.footer { - text-align: center; - margin-top: var(--default-margin); -} - -.footerCopy { - color: var(--gray-3); - font-weight: 100; - font-size: .8rem; -} diff --git a/app/scripts/components/Welcome.jsx b/app/scripts/components/Welcome.jsx deleted file mode 100644 index 5a9a95bb0e..0000000000 --- a/app/scripts/components/Welcome.jsx +++ /dev/null @@ -1,113 +0,0 @@ -'use strict'; - -import styles from './Welcome.css'; - -import React, { createClass, PropTypes } from 'react'; -import LoginForm from './welcome/LoginForm.jsx'; -import SignupForm from './welcome/SignupForm.jsx'; -import { Link } from 'react-router'; -import classnames from 'classnames'; -import Button from '@dux/element-button'; -var debug = require('debug')('Welcome'); - -let LowerSection = createClass({ - displayName: 'LowerSection', - propTypes: { - companyList: PropTypes.arrayOf(PropTypes.object) - }, - getDefaultProps() { - return { - companyList: [ - {logo: 'harvard'}, - {logo: 'sony'}, - {logo: 'nordstrom'}, - {logo: 'oracle'}, - {logo: 'zendesk'}, - {logo: 'gopro'}, - {logo: 'autodesk'}, - {logo: 'cisco'}, - {logo: 'zenefits'}, - {logo: 'dollar-shave-club'}, - {logo: 'zipcar'}, - {logo: 'gilt'}, - {logo: 'adp'}, - {logo: 'makerbot'}, - {logo: 'oculus'}, - {logo: 'adobe'} - ] - }; - }, - mkCompanyLi({name, url, logo}) { - let img = `/public/images/customers/${logo}.png`; - return ( -
  • - -
  • - ); - }, - render() { - - let companyClasses = classnames({ - 'small-block-grid-4': true, - [styles.companyRow]: true - }); - - return ( -
    -

    The most innovative companies use Docker

    -
    -
    -
      - {this.props.companyList.map(str => { return this.mkCompanyLi(str); })} -
    -
    -
    -
    - ); - } -}); - -var Welcome = React.createClass({ - displayName: 'WelcomePage', - transitionExplore: function(e){ - e.preventDefault(); - this.props.history.pushState(null, '/explore/'); - }, - render() { - - let buildShipRun = classnames({ - 'large-8 columns': true, - [styles.buildShipRun]: true - }); - - return ( -
    -
    -
    - -
    -

    Build, Ship, & Run

    -

    Any App, Anywhere

    -

    Dev-test pipeline automation, 100,000+ free apps, public and private registries

    -
    - -
    - -
    - -
    -
    -
    - Browse Thousands of the most popular software tools in the Docker Image Library -
    -
    -
    -

    © 2016 Docker Inc.

    -
    -
    -
    - ); - } -}); - -module.exports = Welcome; diff --git a/app/scripts/components/account/Account.jsx b/app/scripts/components/account/Account.jsx deleted file mode 100644 index 0f30fa138b..0000000000 --- a/app/scripts/components/account/Account.jsx +++ /dev/null @@ -1,127 +0,0 @@ -'use strict'; - -import React, { PropTypes, cloneElement } from 'react'; -import { Link } from 'react-router'; -import FluxibleMixin from 'fluxible-addons-react/FluxibleMixin'; -import { SecondaryNav } from 'dux'; -import FA from 'common/FontAwesome'; -import LiLink from '../common/LiLink'; -import AccountSettingsLicensesStore from '../../stores/AccountSettingsLicensesStore'; -import EmailNotifStore from '../../stores/EmailNotifStore'; -import Route404 from '../common/RouteNotFound404Page.jsx'; - -let SettingNav = React.createClass({ - displayName: 'SettingsSecondaryNav', - mixins: [FluxibleMixin], - contextTypes: { - getStore: PropTypes.func.isRequired - }, - statics: { - storeListeners: { - onLicensesStoreChange: [AccountSettingsLicensesStore], - onNotifStoreChange: [EmailNotifStore] - } - }, - onLicensesStoreChange: function() { - let store = this.context.getStore(AccountSettingsLicensesStore); - this.setState({ - licenseAttempt: store.getAttempt() - }); - }, - onNotifStoreChange: function() { - let store = this.context.getStore(EmailNotifStore); - this.setState({ - notificationAttempt: store.getAttempt() - }); - }, - getInitialState() { - return { - licenseAttempt: false, - notificationAttempt: false - }; - }, - _showLicensesLoader() { - this.context.getStore(AccountSettingsLicensesStore).setAttempt(true); - this.setState({ - licenseAttempt: true - }); - }, - _showNotificationsLoader() { - this.context.getStore(EmailNotifStore).setAttempt(true); - this.setState({ - notificationAttempt: true - }); - }, - renderLicenses() { - var licensesElement; - if (!this.state.licenseAttempt) { - licensesElement = 'Licenses'; - } else { - licensesElement = (Licenses ); - } - return {licensesElement}; - }, - renderNotifications() { - var notificationsElement; - if (!this.state.notificationAttempt) { - notificationsElement = 'Notifications'; - } else { - notificationsElement = (Notifications ); - } - return {notificationsElement}; - }, - render() { - return ( - -
      - Account Settings - Billing & Plans - Linked Accounts & Services - {this.renderNotifications()} - {this.renderLicenses()} -
    -
    - ); - } -}); - -var Account = React.createClass({ - mixins: [FluxibleMixin], - propTypes: { - loggedOutElement: PropTypes.element - }, - contextTypes: { - getStore: PropTypes.func.isRequired - }, - render: function() { - - const { JWT, user, location } = this.props; - const path = location.pathname; - if (!JWT && path === '/account/billing-plans/create-subscription/') { - /* Handles the www.docker.com/pricing links to buy hub plans at URLs - * /account/billing-plans/create-subscription/?plan=index_personal_PLANSIZE - * when the user is logged out (has special redirects) - */ - return cloneElement(this.props.children, { - user: this.props.user, - JWT: this.props.JWT - }); - } else if (!JWT) { - return ( - - ); - } else { - return ( -
    - - {this.props.children && cloneElement(this.props.children, { - user: this.props.user, - JWT: this.props.JWT - })} -
    - ); - } - } -}); - -module.exports = Account; diff --git a/app/scripts/components/account/AccountSettings.css b/app/scripts/components/account/AccountSettings.css deleted file mode 100644 index f0a93fca61..0000000000 --- a/app/scripts/components/account/AccountSettings.css +++ /dev/null @@ -1,14 +0,0 @@ -@import "dux/css/box"; -@import "dux/css/colors"; - -.body { - margin-top: var(--default-margin); -} - -.margin { - margin: var(--default-margin); -} - -.visibility { - color: var(--black); -} \ No newline at end of file diff --git a/app/scripts/components/account/AccountSettings.jsx b/app/scripts/components/account/AccountSettings.jsx deleted file mode 100644 index 9a102998b5..0000000000 --- a/app/scripts/components/account/AccountSettings.jsx +++ /dev/null @@ -1,141 +0,0 @@ -'use strict'; - -import React, { PropTypes } from 'react'; -import { Link } from 'react-router'; -import connectToStores from 'fluxible-addons-react/connectToStores'; -import _ from 'lodash'; - -import styles from './AccountSettings.css'; -import EmailForm from './forms/EmailForm'; -import AccountInfoForm from './forms/AccountInfoForm'; -import ChangePassForm from './forms/ChangePassForm'; -import convertToOrgAction from '../../actions/convertToOrganization'; -import toggleVisibility from '../../actions/toggleVisibility.js'; -import PrivateRepoUsageStore from '../../stores/PrivateRepoUsageStore.js'; -import { PageHeader, Button } from 'dux'; -import classnames from 'classnames'; -import { SplitSection } from '../common/Sections.jsx'; -import DocumentTitle from 'react-document-title'; - -var debug = require('debug')('AccountSettings'); - -var Settings = React.createClass({ - contextTypes: { - executeAction: React.PropTypes.func.isRequired - }, - getDefaultProps: function() { - return { - user: {}, - JWT: '' - }; - }, - render: function() { - - return ( - -
    - -
    -
    - - - - - -
    -
    -
    -
    - ); - } -}); - -var DefaultVisibility = React.createClass({ - displayName: 'DefaultVisibility', - PropTypes: { - defaultRepoVisibility: PropTypes.string.isRequired - }, - contextTypes: { - executeAction: React.PropTypes.func.isRequired - }, - toggleClick(visibility) { - const _this = this; - return (e) => { - e.preventDefault(); - this.context.executeAction(toggleVisibility, _.merge(visibility, {JWT: _this.props.JWT, username: _this.props.username})); - }; - }, - render: function() { - - return ( -
    - Update the default visibility for your repositories.

    }> -
    -
    -
      -
    • - -
    • -
    • - -
    • -
    -
    -
    -
    -
    - ); - } -}); - -var ToOrgForm = React.createClass({ - _toOrgClick: function(e) { - e.preventDefault(); - this.props.history.pushState(null, '/account/convert-to-org/'); - }, - render: function() { - - if (this.props.userType === 'Organization') { - return ( -
    -
    -
    This is an Organization account for:
    -
    {this.props.username}
    -
    -
    -
    - ); - } else { - return ( - To use organization features you must convert your account from a "User" to an "Organization"

    }> -
    - -
    -
    - ); - } - } -}); - -export default connectToStores(Settings, - [ - PrivateRepoUsageStore - ], - function({ getStore }, props) { - return getStore(PrivateRepoUsageStore).getState(); - }); diff --git a/app/scripts/components/account/AddOrganizationForm.css b/app/scripts/components/account/AddOrganizationForm.css deleted file mode 100644 index f70fa38675..0000000000 --- a/app/scripts/components/account/AddOrganizationForm.css +++ /dev/null @@ -1,5 +0,0 @@ -@import 'dux/css/box.css'; - -.contentWrapper { - margin-top: var(--default-margin); -} diff --git a/app/scripts/components/account/AddOrganizationForm.jsx b/app/scripts/components/account/AddOrganizationForm.jsx deleted file mode 100644 index 63e658d507..0000000000 --- a/app/scripts/components/account/AddOrganizationForm.jsx +++ /dev/null @@ -1,96 +0,0 @@ -'use strict'; - -import React from 'react'; -import OrganizationStore from '../../stores/OrganizationStore'; -import AddOrganizationStore from '../../stores/AddOrganizationStore'; -import createOrganizationAction from '../../actions/createOrganization'; -import updateAddOrganizationFormField from '../../actions/updateAddOrganizationFormField'; -import connectToStores from 'fluxible-addons-react/connectToStores'; -const debug = require('debug')('AddOrganizationForm'); -import SimpleInput from 'common/SimpleInput.jsx'; -import Button from '@dux/element-button'; -import styles from './AddOrganizationForm.css'; -import { SplitSection } from '../common/Sections.jsx'; - -var AddOrganizationForm = React.createClass({ - contextTypes: { - executeAction: React.PropTypes.func.isRequired - }, - propTypes: { - JWT: React.PropTypes.string.isRequired - }, - _onChange(fieldKey) { - return (e) => { - this.context.executeAction(updateAddOrganizationFormField, { - fieldKey, - fieldValue: e.target.value - }); - }; - }, - _handleCreate: function(e) { - e.preventDefault(); - /*eslint-disable camelcase */ - var newOrg = { - orgname: this.props.values.orgname.toLowerCase(), - full_name: this.props.values.full_name, - gravatar_email: this.props.values.gravatar_email, - company: this.props.values.company, - location: this.props.values.location, - profile_url: this.props.values.profile_url - /*eslint-enable camelcase */ - }; - this.context.executeAction(createOrganizationAction, { - jwt: this.props.JWT, - organization: newOrg - }); - }, - render: function() { - return ( -
    - - Organizations can have multiple Teams. Teams can have differing permissions. Namespace is - unique and this is where repositories for this organization will be created. -

    }> -
    -
    - - - - - - - - - -
    -
    - ); - } -}); - -export default connectToStores(AddOrganizationForm, - [ - AddOrganizationStore - ], - function({ getStore }, props) { - return getStore(AddOrganizationStore).getState(); - }); diff --git a/app/scripts/components/account/BillingPlans.css b/app/scripts/components/account/BillingPlans.css deleted file mode 100644 index d0d01aa909..0000000000 --- a/app/scripts/components/account/BillingPlans.css +++ /dev/null @@ -1,21 +0,0 @@ -@import 'dux/css/colors.css'; - -.body { - margin-top: 2rem; -} - -.error { - background: var(--primary-5); - color:white; -} - -.plansQuestion { - margin-bottom: 2rem; -} - -.questionTitle { - font-weight: 500; - color: var(--secondary-1); -} - -/*.questionAnswer {}*/ diff --git a/app/scripts/components/account/BillingPlans.jsx b/app/scripts/components/account/BillingPlans.jsx deleted file mode 100644 index dc241415cc..0000000000 --- a/app/scripts/components/account/BillingPlans.jsx +++ /dev/null @@ -1,249 +0,0 @@ -/*global MktoForms2*/ - -'use strict'; - -import React, { PropTypes } from 'react'; -const { string, array, object, func, shape } = PropTypes; -import { Link } from 'react-router'; -import connectToStores from 'fluxible-addons-react/connectToStores'; -import isEmpty from 'lodash/lang/isEmpty'; - -import BillingPlansStore from '../../stores/BillingPlansStore'; -import updateSubscriptionPlanOrPackage from '../../actions/updateSubscriptionPlanOrPackage.js'; - -import PlansTable from './billingplans/Plans'; -import EnterpriseSubscriptions from './billingplans/EnterpriseSubscriptions.jsx'; -import BillingInfo from './billingplans/BillingInfo.jsx'; -import InvoiceTables from './billingplans/InvoiceTables.jsx'; -import styles from './BillingPlans.css'; -import { FullSection } from '../common/Sections.jsx'; -import Route404 from '../common/RouteNotFound404Page.jsx'; -import { PageHeader } from 'dux'; -import DocumentTitle from 'react-document-title'; - -/* Marketo constants for the marketing survey form */ -const mktoFormId = 1317; -const mktoFormElemId = 'mktoForm_' + mktoFormId; -const mktoFormBaseUrl = 'https://app-sj05.marketo.com'; -const mktoFormMunchkinId = '929-FJL-178'; - -var BillingInfoPage = React.createClass({ - - contextTypes: { - executeAction: func.isRequired - }, - - PropTypes: { - JWT: string, - user: object, - currentPlan: shape({ - id: string, - plan: string, - package: string - }), - accountInfo: shape({ - account_code: string, - username: string, - email: string, - first_name: string, - last_name: string, - company_name: string - }), - billingInfo: shape({ - city: string, - state: string, - zip: string, - first_name: string, - last_name: string, - address1: string, - address2: string, - country: string - }), - plansError: string, - invoices: array, - unsubscribing: string, - updatePlan: string - }, - - stopSubscription(subscriptionType) { - /** - * UPDATE 4/6/16 "cloud_metered" is the new "free" plan instead of deleting - * per ticket HUB-2219 - */ - return () => { - const { JWT, user, currentPlan } = this.props; - const namespace = user.username || user.orgname; - let subscriptionData = { - JWT, - username: namespace, - subscription_uuid: currentPlan.subscription_uuid - }; - if (subscriptionType === 'plan') { - subscriptionData.plan_code = 'cloud_metered'; - if (currentPlan.package) { - // preserve package (like cloud_starter) if it exists - subscriptionData.package_code = currentPlan.package; - } - } else if (subscriptionType === 'package') { - // If you are removing a package, leave the plan alone - subscriptionData.plan_code = currentPlan.plan; - // Explicitly set null to remove - subscriptionData.package_code = null; - } - this.context.executeAction(updateSubscriptionPlanOrPackage, subscriptionData); - }; - }, - - showSurveyModal(subscriptionType) { - return () => { - if (typeof MktoForms2 === 'object' && - typeof MktoForms2.loadForm === 'function') { - MktoForms2.loadForm( - mktoFormBaseUrl, - mktoFormMunchkinId, - mktoFormId, - (form) => { - form.onSubmit(this.stopSubscription(subscriptionType)); - // Don't refresh the page after a successful submission. - // React component will re-render itself. - form.onSuccess(() => false); - form.vals({'Email': this.props.accountInfo.email}); - MktoForms2.lightbox(form).show(); - }); - } else { - // If for any reason there is a problem with the Marketo script, - // we shouldn't block the user from stopping his/her subscription. - this.stopSubscription(subscriptionType); - } - }; - }, - - getSurveyModalHtml() { - return ( -
    -
    -
    - ); - }, - - render: function() { - let plansIntro; - let plansFooter; - let errorSection; - const { - accountInfo, - billingInfo, - currentPlan, - invoices, - isOwner, - JWT, - plansError, - unsubscribing, - updatePlan, - user, - history - } = this.props; - if (accountInfo.newBilling) { - plansIntro = ( - -
    - The Docker Hub Registry is free to use for public repositories. Plans with private repositories are - available in different sizes. All plans allow collaboration with unlimited people. -
    -
    - ); - plansFooter = ( - -
    -
    What types of payment do you accept?
    -
    Credit card (Visa, MasterCard, Discover, or American Express).
    -
    -
    -
    Do I have to pay to use your service?
    -
    No, you only have to pay if you require one or more private repository.
    -
    -
    -
    Can I change my plan at a later time?
    -
    Yes, you can upgrade or downgrade at any time.
    -
    -
    -
    What if I need a larger plan?
    -
    Please contact our Sales team at sales@docker.com or call us toll free at 888-214-4258.
    -
    -
    - ); - } else { - plansIntro = (
    ); - plansFooter = (
    ); - } - if (plansError) { - errorSection = ( - -
    - There was an error trying to update your subscription. Please contact the Docker support team.
    - {plansError} -
    -
    - ); - } - const username = user.username || user.orgname || ''; - const isOrg = !!user.orgname; - - if (isOrg && !isOwner) { - return ( - - ); - } else { - /* - accountInfo.newBilling / billingInfo.newBilling - Means this is a brand new account without any information saved to the backend - */ - return ( - -
    - -
    - {plansIntro} - {errorSection} - - {plansFooter}
    -
    - - - -
    - {this.getSurveyModalHtml()} -
    -
    - ); - } - } -}); - -export default connectToStores(BillingInfoPage, - [BillingPlansStore], - function({ getStore }, props) { - return getStore(BillingPlansStore).getState(); - }); diff --git a/app/scripts/components/account/ConvertToOrg.css b/app/scripts/components/account/ConvertToOrg.css deleted file mode 100644 index ace3d024ff..0000000000 --- a/app/scripts/components/account/ConvertToOrg.css +++ /dev/null @@ -1,25 +0,0 @@ -@import 'dux/css/colors.css'; - -.body { - margin-top: 1rem; -} - -.toOrgContent { - margin-bottom: 1rem; -} - -.warning { - color: var(--primary-5); -} - -.center { - text-align: center; - margin-bottom: 1rem; -} - -.form { - padding-top: 1rem; - div { - margin-bottom: 0; - } -} \ No newline at end of file diff --git a/app/scripts/components/account/ConvertToOrg.jsx b/app/scripts/components/account/ConvertToOrg.jsx deleted file mode 100644 index 22545837e9..0000000000 --- a/app/scripts/components/account/ConvertToOrg.jsx +++ /dev/null @@ -1,145 +0,0 @@ -'use strict'; - -import React, { PropTypes } from 'react'; -import { Link } from 'react-router'; -import _ from 'lodash'; -import connectToStores from 'fluxible-addons-react/connectToStores'; -import classnames from 'classnames'; - -import DUXInput from '../common/DUXInput.jsx'; -import convertToOrgAction from '../../actions/convertToOrganization'; -import updateToOrgOwner from '../../actions/updateToOrgOwner.js'; -import ConvertToOrgStore from '../../stores/ConvertToOrgStore.js'; -import { PageHeader, Module } from 'dux'; -import Button from '@dux/element-button'; - -import { FullSection } from '../common/Sections.jsx'; - -import styles from './ConvertToOrg.css'; - -var debug = require('debug')('ConvertToOrg'); - -var _mkErrors = function(err, key) { - const errorClass = classnames({ - [ styles.center ]: true, - [ styles.warning ]: true - }); - return ( -
    - { err } -
    - ); -}; - -var ConvertToOrg = React.createClass({ - contextTypes: { - executeAction: PropTypes.func.isRequired - }, - propTypes: { - user: PropTypes.shape({ - username: PropTypes.string - }), - JWT: PropTypes.string, - convertError: PropTypes.bool.isRequired, - error: PropTypes.object - }, - getInitialState: function() { - return { - newOwner: '' - }; - }, - onChangeOwner: function(e) { - e.preventDefault(); - var newOwner = e.target.value; - this.context.executeAction(updateToOrgOwner, { newOwner: newOwner }); - }, - onCancelClick: function(e) { - e.preventDefault(); - this.props.history.pushState(null, '/account/settings/'); - }, - submitChangeOrg: function(e) { - e.preventDefault(); - debug('Change user to org'); - this.context.executeAction(convertToOrgAction, - {jwt: this.props.JWT, username: this.props.user.username, newOwner: this.props.newOwner}); - }, - render: function() { - var disabled = !this.props.newOwner; - var intent = this.props.convertError ? 'alert' : null; - let error = null; - if (this.props.convertError) { - error = ( -
    - { _.map(this.props.error, _mkErrors) } -
    - ); - } - return ( -
    - -
    -
    - -
    Your user account will be transformed into an organization account where all administrative duties are left to another user or group of users. You will no longer be able to login to this account.
    -
    - -
    Email addresses for this account will be removed, freeing them up to be used for any other accounts.
    -
    - -
    Converting your account removes any associations to other services like GitHub or Atlassian Bitbucket. You will be able to link your external accounts to another Docker Hub user.
    -
    - -
    Billing details and Private Repository plans will remain attached to this account after it is converted to an organization.
    -
    - -
    Repository namespaces and names remain unchanged. Any user collaborators that you have configured for these repositories will be removed and must be reconfigured using group collaborators.
    -
    - -
    Automated Builds for this account will be updated to appear as if they were originallly configured by the initial organization owner. Any user in a group with 'admin' level access to a repository will be able to edit Automated Build Configurations.
    -
    -
    -
    -
    WARNING
    -
    This account conversion operation can not be undone.
    -
    -
    -
    -
    -

    In order to complete the conversion of your account to an organization you will need to enter the Docker ID of an **existing** Docker Hub user account. - The user account you specify will become a member of the Owners group and will have full administrative privileges to manage the organization.

    - - { error } -
    -
    -
    - -
    -
    -
    -
    - -
    -
    - -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - ); - } -}); - -export default connectToStores(ConvertToOrg, - [ConvertToOrgStore], - function({ getStore }, props) { - return getStore(ConvertToOrgStore).getState(); - }); diff --git a/app/scripts/components/account/CreateBillingSubscription.css b/app/scripts/components/account/CreateBillingSubscription.css deleted file mode 100644 index d7d63cbe3e..0000000000 --- a/app/scripts/components/account/CreateBillingSubscription.css +++ /dev/null @@ -1,36 +0,0 @@ -@import "dux/css/box"; -@import 'dux/css/colors.css'; - -.select { - width: 5rem; -} -.error { - color: var(--primary-5); -} - -.title { - font-weight: 700; - margin-top: 1.5rem; -} - -.subtitle { - color: var(--primary-2); - margin-bottom: .5rem; -} - -.preview { - composes: module from 'dux/dux/Module/Module.css'; - padding: 2rem 2rem 0; - margin-left: 1rem; -} - -.total { - margin-bottom: 35px; -} - -.couponCode { - margin-top: 2rem; -} -.price { - text-align: right; -} diff --git a/app/scripts/components/account/CreateBillingSubscription.jsx b/app/scripts/components/account/CreateBillingSubscription.jsx deleted file mode 100644 index 972231444b..0000000000 --- a/app/scripts/components/account/CreateBillingSubscription.jsx +++ /dev/null @@ -1,319 +0,0 @@ -'use strict'; - -import React, { PropTypes } from 'react'; -const { string, number, func, shape, object, array, oneOfType } = PropTypes; -import map from 'lodash/collection/map'; -import find from 'lodash/collection/find'; -import includes from 'lodash/collection/includes'; -import has from 'lodash/object/has'; -import merge from 'lodash/object/merge'; -import classnames from 'classnames'; -import { Link } from 'react-router'; -import connectToStores from 'fluxible-addons-react/connectToStores'; - -import BillingInfoForm from './billingplans/BillingInfoForm.jsx'; -import BillingInfoFormStore from '../../stores/BillingInfoFormStore.js'; -import PlansStore from '../../stores/PlansStore.js'; -import BillingPlansStore from '../../stores/BillingPlansStore.js'; -import DUXInput from '../common/DUXInput.jsx'; -import createBillingSubscription from '../../actions/createSubscription.js'; -import updateSubscriptionPlanOrPackage from '../../actions/updateSubscriptionPlanOrPackage.js'; -import updateBillingInfoFormField from '../../actions/updateBillingInfoFormField.js'; -import validateBillingInfo from '../../actions/common/validateBillingInfo.js'; -import validateCouponCode from '../../actions/validateCouponCode.js'; -import EnterpriseLoggedOutPage from '../enterprise/EnterpriseLoggedOutPage.jsx'; -import { Button, PageHeader } from 'dux'; -import styles from './CreateBillingSubscription.css'; - -var debug = require('debug')('createBillingSubscription'); - -function mkShortPlanIntervalUnit(unit) { - if (unit === 'months'){ - return 'mo'; - } else if (unit === 'years') { - return 'yr'; - } else { - return 'mo'; - } -} - -function _mkOptions(list_item) { - return ( - - ); -} - -var CreateBillingSubscription = React.createClass({ - displayName: 'CreateBillingSubscription', - contextTypes: { - getStore: func.isRequired, - executeAction: func.isRequired - }, - getInitialState: function() { - return { - couponCode: '', - selectedPlan: this.props.location.query.plan - }; - }, - propTypes: { - JWT: string.isRequired, - user: object.isRequired, - billingInfoForm: shape({ - billforwardId: string, - accountInfo: shape({ - account_code: string, - username: string, - email: string, - first_name: string, - last_name: string, - company_name: string - }), - billingInfo: shape({ - city: string, - state: string, - zip: string, - first_name: string, - last_name: string, - address1: string, - address2: string, - country: string - }), - card: shape({ - number: string, - cvv: string, - month: oneOfType([number, string]), - year: oneOfType([number, string]), - type: string, - coupon_code: string, - coupon: number - }), - errorMessage: string, - fieldErrors: object, - STATUS: string - }), - plans: shape({ - currentPlan: shape({ - subscription_uuid: string, - package: string - }), - plansList: array - }) - }, - createBillingSubscription(){ - const { JWT, user } = this.props; - const { billforwardId, accountInfo, billingInfo, card } = this.props.billingInfoForm; - const { currentPlan } = this.props.plans; - const { package: currentPackage, subscription_uuid } = currentPlan; - const { selectedPlan } = this.state; - const { executeAction } = this.context; - if (selectedPlan) { - // User has no billing profile account OR no billing payment information - var subscriptionData = { - JWT, - user, - accountInfo, - billingInfo, - card, - billforwardId, - isNewBillingAccount: accountInfo.newBilling, - plan_code: selectedPlan - }; - - return executeAction(createBillingSubscription, subscriptionData); - } else if (currentPackage) { - // User HAS a CLOUD plan - upgrade to hub plan WITH cloud subscription - // SHOULD NEVER REACH HERE ANYMORE - PACKAGES HAVE BEEN REMOVED!! - const namespace = user.username || user.orgname; - let updatePlanInfo = { - JWT, - username: namespace, - subscription_uuid: subscription_uuid, - plan_code: selectedPlan, - package_code: currentPackage, - coupon_code: card.coupon_code - }; - return executeAction(updateSubscriptionPlanOrPackage, updatePlanInfo); - } - return executeAction(validateBillingInfo({storePrefix: 'BILLING'})); - }, - getPlan(selectedPlan) { - const plans = [ - 'index_personal_micro', - 'index_personal_small', - 'index_personal_medium', - 'index_personal_large', - 'index_personal_xlarge', - 'index_personal_xxlarge' - ]; - if (selectedPlan && includes(plans, selectedPlan)) { - const { plansList } = this.props.plans; - const planObject = find(plansList, {plan_code: selectedPlan}); - const interval = has(planObject, 'plan_interval_unit') ? mkShortPlanIntervalUnit(planObject.plan_interval_unit) : 'mo'; - const price = parseInt(planObject.price_in_cents, 10) / 100; - return {planCode: planObject.plan_code, price: price, interval}; - } else { - return {price: 0, interval: 'mo', planCode: null}; - } - }, - _onChange(field, fieldKey) { - return (e) => { - this.context.executeAction(updateBillingInfoFormField, { - field, - fieldKey, - fieldValue: e.target.value - }); - }; - }, - _updateSelectPlan(e) { - e.preventDefault(); - let planCode = e.target.value; - const { card } = this.props.billingInfoForm; - this.setState({selectedPlan: planCode}); - this.props.history.pushState(null, this.props.location.pathname, {plan: planCode}); - if (card.coupon > 0 || this.state.couponCode) { - this.context.executeAction(validateCouponCode, {coupon_code: this.state.couponCode, plan: planCode}); - } - }, - _updateCoupon(e) { - e.preventDefault(); - this.setState({couponCode: e.target.value}); - }, - validateCoupon(plan) { - return (e) => { - e.preventDefault(); - this.context.executeAction(validateCouponCode, {coupon_code: this.state.couponCode, plan: plan}); - this.setState({couponCode: ''}); - }; - }, - render: function() { - const { plansList } = this.props.plans; - const { selectedPlan } = this.state; - const { JWT, user, history } = this.props; - - if(!JWT) { - //get plan type from end of '?plan=index_personal_PLANTYPE' - //default to micro plan if no query selected - const planType = selectedPlan ? selectedPlan.substring(15) : 'micro'; - return ; - } else { - const { accountInfo, billingInfo, card, fieldErrors, STATUS, errorMessage } = this.props.billingInfoForm; - const { price, interval, planCode } = this.getPlan(selectedPlan); - - var discount; - if (card.coupon > 0) { - discount = '- $' + card.coupon; - } else { - discount = '-----'; - } - let titleClass = classnames({ - [styles.title]: true, - [styles.error]: true - }); - let title = ( -
    - * Please select a plan:  - -
    - ); - - if (selectedPlan) { - title = ( -
    - You are subscribing to the   - -   plan at ${price}/{interval} -
    - ); - } - const namespace = user.username || user.orgname; - const isOrg = !!user.orgname; - - return ( -
    - - -
    -
    - { title } -
    Once your billing information has been processed, your account will be immediately upgraded.
    -
    Thank you for subscribing!
    -
    Your billing information can be updated at any time
    -
    -
    -
    -
    - -
    -
    -
    -
    - Plan Cost: -
    -
    - ${price} -
    -
    -
    -
    - Coupon: -
    -
    - {discount} -
    -
    -
    -
    -
    - Total Charge: -
    -
    - ${price - card.coupon} -
    -
    -
    -
    -
    - -
    -
    - -
    -
    -
    -
    -
    -
    - ); - } - } -}); - -export default connectToStores(CreateBillingSubscription, - [BillingInfoFormStore, PlansStore], - function({ getStore }, props) { - return merge({}, - {plans: getStore(PlansStore).getState(), billingInfoForm: getStore(BillingInfoFormStore).getState()}); - }); diff --git a/app/scripts/components/account/Licenses.css b/app/scripts/components/account/Licenses.css deleted file mode 100644 index dda5c374ae..0000000000 --- a/app/scripts/components/account/Licenses.css +++ /dev/null @@ -1,51 +0,0 @@ -@import "dux/css/box"; -@import "dux/css/colors"; - -.license { - background: var(--white); - border: 1px solid var(--iron); - border-top-right-radius: var(--global-radius) 0; - border-top-left-radius: var(--global-radius) 0; - padding: 1rem 2rem; - margin: 1rem 0 0 0; -} - -.download { - background: var(--secondary-5); - color: var(--secondary-2); - border-bottom-right-radius: var(--global-radius) 0; - border-bottom-left-radius: var(--global-radius) 0; - text-align: center; - padding: .5rem; - line-height: 16px; - font-size: 14px; -} - -.downloadAlert { - background: var(--alert-color); - color: var(--secondary-5); - border-bottom-right-radius: var(--global-radius) 0; - border-bottom-left-radius: var(--global-radius) 0; - text-align: center; - padding: .5rem; -} - -.pageWrapper { - padding-top: 1.25rem; -} - -.legal { - font-size: 12px; - font-style: italic; - min-height: 48px; -} - -input.checkbox { - margin-bottom: 0; - margin-right: 4px; -} - -.finePrint { - font-size: 10px; - font-style: italic; -} diff --git a/app/scripts/components/account/Licenses.jsx b/app/scripts/components/account/Licenses.jsx deleted file mode 100644 index 2b074cc196..0000000000 --- a/app/scripts/components/account/Licenses.jsx +++ /dev/null @@ -1,221 +0,0 @@ -'use strict'; - -import React, { PropTypes, createClass, Component } from 'react'; -import _ from 'lodash'; -import moment from 'moment'; -import classnames from 'classnames'; -import { Link } from 'react-router'; -import connectToStores from 'fluxible-addons-react/connectToStores'; -import request from 'superagent'; - -// Blob is a polyfill -require('vendor/Blob'); -import { saveAs } from 'vendor/FileSaver'; -import FA from 'common/FontAwesome'; - -import { PageHeader } from 'dux'; -import AccountSettingsLicensesStore from '../../stores/AccountSettingsLicensesStore'; -import Row from '../common/Row'; -import CSEngineBox from 'common/CSEngineBox'; - -import styles from './Licenses.css'; -import DocumentTitle from 'react-document-title'; - -var debug = require('debug')('AccountSettingsLicenses'); - -class LicenseBox extends Component { - - state = { - hasAcceptedTerms: false, - hasError: false, - isDownloading: false, - // Paid licenses require terms - // https://github.com/docker/dhe-license-server/blob/master/tiers/tiers.go - requiresAcceptedTerms: this.props.tier !== 'Trial' && this.props.tier !== 'Evaluation' - } - - onCheckboxChange = () => { - this.setState({ - hasAcceptedTerms: !this.state.hasAcceptedTerms - }); - } - - onClick = (e) => { - this.setState({ - isDownloading: true, - hasError: false - }); - request.get(process.env.REGISTRY_API_BASE_URL - + '/api/licensing/v3/license/' - + this.props.orgname - + '/' - + this.props.keyId - + '/') - .set('Authorization', 'JWT ' + this.props.JWT) - .end((err, res) => { - if(err) { - this.setState({ - isDownloading: false, - hasError: true - }); - } else { - - this.setState({ - isDownloading: false, - hasError: false - }); - - const blob = new Blob([res.text], { - type: 'text/plain;charset=utf-8' - }); - saveAs(blob, `docker_subscription.lic`); - } - - }); - } - - render() { - const { expiration, alias, orgname, end, tier, maxEngines } = this.props; - const { requiresAcceptedTerms, hasAcceptedTerms } = this.state; - const exp = moment(expiration).fromNow(); - // This is a temporary work around until we can enable click to accept - // in Store - let maybeTermsAndConditions =
    ; - if (requiresAcceptedTerms) { - const EUSALink = 'https://www.docker.com/docker-software-end-user-subscription-agreement'; - const checkbox = ( - - ); - maybeTermsAndConditions = ( -
    - { checkbox } - I agree to Docker's subscription terms -
    This will not override any pre-negotiated terms.
    -
    - ); - } - - const preventDownload = requiresAcceptedTerms && !hasAcceptedTerms; - let icon; - let onClick; - if (preventDownload) { - icon = 'Please accept terms to download'; - onClick = () => {}; - } else { - icon = ; - onClick = this.onClick; - if(this.state.isDownloading) { - icon = ; - } - } - - const classes = classnames({ - 'large-3 columns': true, - 'end': end - }); - - const downloadClasses = classnames({ - [styles.download]: !this.state.hasError, - [styles.downloadAlert]: this.state.hasError - }); - return ( -
    -
    -

    {alias}

    -

    Organization: {orgname}

    -

    Engines: {maxEngines}

    -

    Expires: {exp}

    - { maybeTermsAndConditions } -
    - -
    {icon}
    -
    - ); - } -} - -class Licenses extends Component { - contextTypes: { - executeAction: React.PropTypes.func.isRequired - } - - propTypes: { - JWT: PropTypes.string.isRequired, - licenses: PropTypes.array.isRequired - } - - state = { - rpm: { - isDownloading: false, - hasError: false - }, - deb: { - isDownloading: false, - hasError: false - } - } - - - render() { - if(this.props.licenses.length <= 0) { - return ( - -
    - -
    - -
    You don't seem to have any - licenses; Get a - Trial. -
    -
    -
    -
    -
    - ); - } else { - const { rpm, deb } = this.state; - - const icon = ; - const iconDownloading = ; - - const rpmIcon = rpm.isDownloading ? iconDownloading : icon; - const debIcon = deb.isDownloading ? iconDownloading : icon; - - const rpmIntent = rpm.hasAlert ? 'alert' : null; - const debIntent = deb.hasAlert ? 'alert' : null; - - return ( - -
    - -
    -
    -
    - -
    -
    -
    - {this.props.licenses.map((license, i, arr) => { return ; } )} -
    -
    -
    -
    - ); - } - } -} - -export default connectToStores(Licenses, - [ - AccountSettingsLicensesStore - ], - function({ getStore }, props) { - return getStore(AccountSettingsLicensesStore).getState(); - }); diff --git a/app/scripts/components/account/LinkedServices.css b/app/scripts/components/account/LinkedServices.css deleted file mode 100644 index e8b35530b3..0000000000 --- a/app/scripts/components/account/LinkedServices.css +++ /dev/null @@ -1,44 +0,0 @@ -@import 'dux/css/colors.css'; -@import 'dux/css/box.css'; - -.body { - margin-top: 2rem; -} - -.icon { - width: 100px; - height: 100px; -} - -.name { - font-weight: 700; - margin: 0 var(--default-margin); -} - -.access { - margin: .5rem 0; - text-align: left; -} - -.service { - composes: base from 'dux/dux/Module/Module.css'; - color: var(--secondary-4); - padding: 1.8rem; - text-align: center; - transition: border .2s; - i { - font-size: 5rem; - margin-bottom: 1rem; - } - &:hover { - background: #f4f9fc; - color: var(--secondary-4); - cursor: pointer; - } - &.link:hover { - border: 1px solid var(--primary-2); - } - &.unlink:hover { - border: 1px solid var(--primary-5); - } -} \ No newline at end of file diff --git a/app/scripts/components/account/LinkedServices.jsx b/app/scripts/components/account/LinkedServices.jsx deleted file mode 100644 index 497139ed3c..0000000000 --- a/app/scripts/components/account/LinkedServices.jsx +++ /dev/null @@ -1,177 +0,0 @@ -'use strict'; - -import React, { PropTypes, Component } from 'react'; -import connectToStores from 'fluxible-addons-react/connectToStores'; -import { PageHeader } from 'dux'; - -import AutobuildStore from '../../stores/AutobuildStore'; -import BitbucketLinkStore from '../../stores/BitbucketLinkStore'; -import GithubLinkStore from '../../stores/GithubLinkStore'; -import GithubLinkAction from '../../actions/linkGithub'; -import BitbucketLinkAction from '../../actions/linkBitbucket'; -import GithubUnlinkAction from '../../actions/unlinkGithub'; -import BitbucketUnlinkAction from '../../actions/unlinkBitbucket'; -import { Button, Module } from 'dux'; -import { SplitSection } from '../common/Sections.jsx'; -import FA from '../common/FontAwesome'; -import classnames from 'classnames'; -import styles from './LinkedServices.css'; -import merge from 'lodash/object/merge'; -import DocumentTitle from 'react-document-title'; - -const { string, array, object, func } = PropTypes; - -class LinkedServices extends Component { - - static contextTypes = { - executeAction: func.isRequired - } - - static propTypes = { - JWT: string.isRequired, - githubAccount: object, - githubRepos: array, - bitbucketAccount: object, - bitbucketRepos: array, - gitlabAccount: object, - gitlabRepos: array, - bitbucketError: string, - bbAuthUrl: string, - githubError: string - } - - authServiceClick = (e) => { - e.preventDefault(); - } - - render() { - var github = {service: 'Github', account: this.props.githubAccount}; - var bitbucket = {service: 'Bitbucket', account: this.props.bitbucketAccount}; - var gitlab = {service: 'Gitlab', account: this.props.gitlabAccount}; - let maybeError; - const errorMsg = this.props.githubError || this.props.bitbucketError; - if (errorMsg) { - maybeError = {errorMsg}; - } - return ( - -
    - -
    -
    - - These account links are currently used for Automated Builds, - so that we can access your project lists and help you configure your Automated Builds. -   Please note: A github/bitbucket account can be connected to only one docker hub account at a time.

    }> -
    - - -
    -
    - {maybeError} -
    -
    -
    -
    -
    - ); - } -} - -class LinkedAccount extends Component { - static propTypes = { - data: object, - bbAuthUrl: string, - JWT: string, - history: object.isRequired - } - - static contextTypes = { - executeAction: PropTypes.func.isRequired - } - - linkAction = (provider, e) => { - e.preventDefault(); - if (provider.service.toLowerCase() === 'github') { - this.context.executeAction(GithubLinkAction, this.props.JWT); - this.props.history.pushState(null, '/account/authorized-services/github-permissions/'); - } else if (provider.service.toLowerCase() === 'bitbucket') { - const bbWin = window.open(); - bbWin.location = this.props.bbAuthUrl; - } - } - - unlinkAction = (provider, e) => { - e.preventDefault(); - if (provider.service.toLowerCase() === 'github') { - this.context.executeAction(GithubUnlinkAction, this.props.JWT); - } else if (provider.service.toLowerCase() === 'bitbucket') { - this.context.executeAction(BitbucketUnlinkAction, this.props.JWT); - } - } - - render() { - var service = this.props.data.service; - var icon; - if (service.toLowerCase() === 'github') { - icon = 'fa-github'; - } else if (service.toLowerCase() === 'bitbucket') { - icon = 'fa-bitbucket'; - } - var account = this.props.data.account; - let linkClass = classnames({ - [styles.service]: true, - [styles.unlink]: account, - [styles.link]: !account - }); - if (account) { - return ( -
    -
    -
    -
    - -
    -
    - {account.login}:
    - read/write access -
    -

    - Unlink {service} -
    -
    - ); - } else { - return ( -
    -
    -
    - Link {service} -
    -
    - ); - } - } -} - -export default connectToStores(LinkedServices, - [ - AutobuildStore, - BitbucketLinkStore, - GithubLinkStore - ], - function({ getStore }, props) { - return merge( - {}, - getStore(AutobuildStore).getState(), - { bitbucketError: getStore(BitbucketLinkStore).getState().error, - bbAuthUrl: getStore(BitbucketLinkStore).getState().authURL, - githubError: getStore(GithubLinkStore).getState().error } - ); - }); diff --git a/app/scripts/components/account/NotificationsSettings.css b/app/scripts/components/account/NotificationsSettings.css deleted file mode 100644 index 1a3cebfd7a..0000000000 --- a/app/scripts/components/account/NotificationsSettings.css +++ /dev/null @@ -1,36 +0,0 @@ -@import 'dux/css/colors.css'; - -.body { - margin-top: 2rem; -} - -.button { - margin-bottom: -1rem; -} - -.success { - border: 1px solid var(--primary-2); -} - -.formError { - border: 1px solid var(--primary-5); -} - -.notification { - margin-bottom: 1rem; - word-wrap: break-word; -} -.notification:hover { - cursor: pointer; - cursor: hand; -} -.unverifiedNotif { - margin-bottom: 1rem; - word-wrap: break-word; - color: var(--secondary-4); - cursor: default; -} - -.checkbox { - padding-top: .5rem; -} diff --git a/app/scripts/components/account/NotificationsSettings.jsx b/app/scripts/components/account/NotificationsSettings.jsx deleted file mode 100644 index 63364634c7..0000000000 --- a/app/scripts/components/account/NotificationsSettings.jsx +++ /dev/null @@ -1,240 +0,0 @@ -'use strict'; - -import React, { PropTypes } from 'react'; -import _ from 'lodash'; -import connectToStores from 'fluxible-addons-react/connectToStores'; -import classnames from 'classnames'; - -import { Button, PageHeader } from 'dux'; -import OutboundCommunicationStore from '../../stores/OutboundCommunicationStore'; -import EmailsStore from '../../stores/EmailsStore'; -import resetNotifications from '../../actions/resetNotifications.js'; -import saveOutbound from '../../actions/saveOutbound'; -import UpdateOutbound from '../../actions/updateOutbound.js'; -import EmailNotifForm from './notificationSettings/EmailNotifForm.jsx'; - -import { SplitSection } from './../common/Sections.jsx'; -import styles from './NotificationsSettings.css'; -import DocumentTitle from 'react-document-title'; - -var debug = require('debug')('NotificationSettings'); - -var Notifications = React.createClass({ - displayName: 'Notifications', - contextTypes: { - executeAction: PropTypes.func.isRequired - }, - propTypes: { - user: PropTypes.shape({ - username: PropTypes.string - }), - JWT: PropTypes.string - }, - getDefaultProps: function() { - return { - user: {}, - JWT: '' - }; - }, - onOutboundClick: function(e) { - debug('onOutboundClick'); - var email = e.currentTarget.getAttribute('data-email'); - var list = e.currentTarget.getAttribute('data-list'); - var unsubscribedIndex; - var subscribedIndex; - var newSubscribed; - var newUnsubscribed; - var newList; - if (list === 'weekly') { - /*eslint-disable camelcase */ - unsubscribedIndex = this.props.weeklyDigest.unsubscribed_emails.indexOf(email); - subscribedIndex = this.props.weeklyDigest.subscribed_emails.indexOf(email); - newUnsubscribed = _.clone(this.props.weeklyDigest.unsubscribed_emails); - newSubscribed = _.clone(this.props.weeklyDigest.subscribed_emails); - if (unsubscribedIndex > -1 && subscribedIndex === -1) { - newUnsubscribed.splice(unsubscribedIndex, 1); - newSubscribed.push(email); - } else { - newSubscribed.splice(subscribedIndex, 1); - newUnsubscribed.push(email); - } - newList = { - subscribed_emails: newSubscribed, - unsubscribed_emails: newUnsubscribed - }; - this.context.executeAction(UpdateOutbound, {list: 'weekly', data: newList}); - /*eslint-enable camelcase */ - } else if (list === 'beta') { - unsubscribedIndex = this.props.betaGroup.unsubscribed_emails.indexOf(email); - subscribedIndex = this.props.betaGroup.subscribed_emails.indexOf(email); - newUnsubscribed = _.clone(this.props.betaGroup.unsubscribed_emails); - newSubscribed = _.clone(this.props.betaGroup.subscribed_emails); - if (unsubscribedIndex > -1 && subscribedIndex === -1) { - newUnsubscribed.splice(unsubscribedIndex, 1); - newSubscribed.push(email); - } else { - newSubscribed.splice(subscribedIndex, 1); - newUnsubscribed.push(email); - } - newList = { - unsubscribed_emails: newUnsubscribed, - subscribed_emails: newSubscribed - }; - this.context.executeAction(UpdateOutbound, {list: 'beta', data: newList}); - } - }, - onOutboundSubmit: function(e) { - e.preventDefault(); - let _this = this; - let weeklyUns = []; - let betaUns = []; - let weekly = _.clone(this.props.weeklyDigest); - let beta = _.clone(this.props.betaGroup); - /* eslint-disable camelcase */ - weekly.unsubscribed_emails.forEach(function(email) { - if (_this.isVerified(email)) { - weeklyUns.push(email); - } - }); - weekly.unsubscribed_emails = weeklyUns; - beta.unsubscribed_emails.forEach(function(email) { - if (_this.isVerified(email)) { - betaUns.push(email); - } - }); - beta.unsubscribed_emails = betaUns; - /* eslint-enable camelcase */ - var outboundData = { - JWT: this.props.JWT, - username: this.props.user.username, - weeklyDigest: weekly, - betaGroup: beta - }; - this.context.executeAction(saveOutbound, outboundData); - }, - onOutboundCancel: function(e) { - debug('resetting outbound communication'); - this.context.executeAction(resetNotifications, ['outbound']); - }, - sortEmails: function(emailArray) { - var _this = this; - return (_.sortBy(emailArray, - function(email) { - return !(_this.isVerified(email)); - }) - ); - }, - isVerified: function(email) { - return _.pluck(_.filter(this.props.emails, {email: email}), 'verified')[0]; - }, - render: function() { - var digestEmails = this.sortEmails(this.props.digestEmails); - var betaEmails = this.sortEmails(this.props.betaEmails); - return ( - -
    - -
    -
    - - - The following settings will control how Docker communicates news, new products, new features, and more.

    }> -
    - -
    Docker Weekly
    -

    Docker weekly is a newsletter which contains the latest news, updates, and information on releases and other exciting stuff. Sign up!

    -
    - -
    Docker Beta Group
    -

    Become part of our Docker Beta Group and get early access to some Docker products and/or features.

    -

    Please select which email address (or addresses) you'd like to subscribe:

    -
    - -
    -
    - -
    -
    - -
    -
    -
    -
    - -
    -
    -
    -
    - ); - } -}); - -var OutboundList = React.createClass({ - contextTypes: { - executeAction: PropTypes.func.isRequired - }, - propTypes: { - emailGroups: PropTypes.shape({ - subscribed_emails: PropTypes.array, - unsubscribed_emails: PropTypes.array - }), - emailList: PropTypes.array, - emails: PropTypes.array, - onOutboundClick: PropTypes.func.isRequired, - type: PropTypes.string.isRequired - }, - render: function() { - let _this = this; - return ( -
    -
    -
    - {this.props.children} -
    -
    - {this.props.emailList.map(function(email) { - if (_this.props.isVerified(email)) { - return ( -
    -
    - -
    -
    - {email} -
    -
    - ); - } else { - return ( -
    -
    - -
    -
    - {email} - unverified -
    -
    - ); - } - })} -
    - ); - } -}); - -export default connectToStores(Notifications, - [OutboundCommunicationStore, EmailsStore], function({ getStore }, props) { - return _.merge({}, getStore(OutboundCommunicationStore).getState(), getStore(EmailsStore).getEmails()); - }); diff --git a/app/scripts/components/account/OrganizationSettings.jsx b/app/scripts/components/account/OrganizationSettings.jsx deleted file mode 100644 index 48c000f7b6..0000000000 --- a/app/scripts/components/account/OrganizationSettings.jsx +++ /dev/null @@ -1,62 +0,0 @@ -'use strict'; - -import React, { cloneElement } from 'react'; -import { Link } from 'react-router'; -import FluxibleMixin from 'fluxible-addons-react/FluxibleMixin'; -import OrganizationStore from '../../stores/OrganizationStore'; -import { PageHeader } from 'dux'; -import FA from '../common/FontAwesome'; -import DocumentTitle from 'react-document-title'; -const debug = require('debug')('OrganizationSettings'); - -var OrganizationSettings = React.createClass({ - displayName: 'OrganizationSettings', - mixins: [FluxibleMixin], - getInitialState: function() { - return { - orgs: this.context.getStore(OrganizationStore).getOrgs() - }; - }, - statics: { - storeListeners: { - onOrgStoreChange: [OrganizationStore] - } - }, - onOrgStoreChange: function() { - this.setState({ - orgs: this.context.getStore(OrganizationStore).getOrgs() - }); - }, - componentDidMount: function() { - this.setState({ - orgs: this.context.getStore(OrganizationStore).getOrgs() - }); - }, - render: function() { - - var maybeCreateOrgBtn; - var pathname = this.props.location.pathname; - if (pathname.indexOf('/add/') === -1) { - maybeCreateOrgBtn = Create Organization ; - } - - return ( - -
    - - {maybeCreateOrgBtn} - -
    - {cloneElement(this.props.children, { - user: this.props.user, - JWT: this.props.JWT, - orgs: this.state.orgs - })} -
    -
    -
    - ); - } -}); - -module.exports = OrganizationSettings; diff --git a/app/scripts/components/account/OrganizationSummary.css b/app/scripts/components/account/OrganizationSummary.css deleted file mode 100644 index 65001dbfb0..0000000000 --- a/app/scripts/components/account/OrganizationSummary.css +++ /dev/null @@ -1,23 +0,0 @@ -@import "dux/css/box.css"; - -.orgGridItem { - composes: module from "dux/dux/Module/Module.css"; - text-align: center; - &:hover { - cursor: pointer; - } -} -.orgSummary { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} -.orgAvatar { - width: 3rem; - height: 3rem; - border-radius: 100%; - padding: 5px; -} -.orgListItem { - list-style: none; -} diff --git a/app/scripts/components/account/OrganizationSummary.jsx b/app/scripts/components/account/OrganizationSummary.jsx deleted file mode 100644 index 554dbbca17..0000000000 --- a/app/scripts/components/account/OrganizationSummary.jsx +++ /dev/null @@ -1,62 +0,0 @@ -'use strict'; - -import styles from './OrganizationSummary.css'; -import classnames from 'classnames'; -import React, { Component, PropTypes } from 'react'; -const { bool, string } = PropTypes; -import { Link } from 'react-router'; -import selectOrganizationAction from '../../actions/selectOrganization'; -import { mkAvatarForNamespace } from 'utils/avatar'; - -const debug = require('debug')('OrganizationSummary'); - - -class OrgItem extends Component { - - static propTypes = { - orgname: string.isRequired, - end: bool - } - - render() { - const { orgname, end } = this.props; - const classes = classnames( - styles.orgListItem, - 'medium-3', - 'columns', - { - 'end': end - } - ); - return ( -
  • - -
    - -
    {orgname}
    -
    - -
  • - ); - } -} - -export default class OrganizationSummary extends Component { - static contextTypes = { - executeAction: React.PropTypes.func.isRequired - } - static propTypes = { - user: React.PropTypes.object.isRequired, - JWT: React.PropTypes.string.isRequired, - orgs: React.PropTypes.array.isRequired - } - render() { - const orgItems = this.props.orgs.map((org, i, array) => { return ; }); - - return ( -
      - {orgItems} -
    - ); - } -} diff --git a/app/scripts/components/account/UpdateBillingInfo.css b/app/scripts/components/account/UpdateBillingInfo.css deleted file mode 100644 index b2ee158666..0000000000 --- a/app/scripts/components/account/UpdateBillingInfo.css +++ /dev/null @@ -1,11 +0,0 @@ -@import "dux/css/box"; -@import "dux/css/colors"; - -.body { - margin-top: var(--default-margin); -} - -.subtitle { - color: var(--primary-2); - margin-bottom: .5rem; -} diff --git a/app/scripts/components/account/UpdateBillingInfo.jsx b/app/scripts/components/account/UpdateBillingInfo.jsx deleted file mode 100644 index 1b7baf22e2..0000000000 --- a/app/scripts/components/account/UpdateBillingInfo.jsx +++ /dev/null @@ -1,131 +0,0 @@ -'use strict'; -import React, { PropTypes } from 'react'; -const { string, number, func, shape, object, array, oneOfType } = PropTypes; -import connectToStores from 'fluxible-addons-react/connectToStores'; -import updateBillingInformation from '../../actions/updateBillingInformation.js'; -import updateStripeBilling from '../../actions/updateStripeBilling.js'; -import BillingInfoFormStore from '../../stores/BillingInfoFormStore.js'; -import BillingInfoForm from './billingplans/BillingInfoForm.jsx'; -import { Link } from 'react-router'; -import classnames from 'classnames'; -import styles from './UpdateBillingInfo.css'; -import { PageHeader, Module } from 'dux'; -var debug = require('debug')('UpdateBillingInfo:'); - -var updateBillingInfoPage = React.createClass({ - displayName: 'UpdateBillingInfo', - contextTypes: { - getStore: func.isRequired, - executeAction: func.isRequired - }, - propTypes: { - JWT: string.isRequired, - user: object.isRequired, - billforwardId: string, - accountInfo: shape({ - account_code: string, - username: string, - email: string, - first_name: string, - last_name: string, - company_name: string - }), - billingInfo: shape({ - city: string, - state: string, - zip: string, - first_name: string, - last_name: string, - address1: string, - address2: string, - country: string - }), - card: shape({ - number: string, - cvv: string, - month: oneOfType([number, string]), - year: oneOfType([number, string]), - type: string - }), - errorMessage: string, - fieldErrors: object, - STATUS: string - }, - updateBillingInfoSubmit(){ - const { - JWT, - user, - accountInfo, - billingInfo, - card, - billforwardId, - location - } = this.props; - if (billforwardId) { - // If we have a billforwardID then we will update via stripe - this.context.executeAction(updateStripeBilling, { - JWT, - user, - accountInfo, - billingInfo, - billforwardId, - card - }); - } else { - // If we do not have a billforward ID then we go through the original recurly update flow - this.context.executeAction(updateBillingInformation, { - JWT, - user, - accountInfo, - billingInfo, - card - }); - } - }, - render: function() { - const { - user, - history, - accountInfo, - billingInfo, - card, - fieldErrors, - STATUS, - errorMessage - } = this.props; - const namespace = user.username || user.orgname; - let isOrg = !!user.orgname; - return ( -
    - -
    -
    -
    Billing information is required for changing or upgrading subscriptions
    -
    You may update your billing information at any time
    -
    -
    -
    -
    - -
    -
    -
    - ); - } -}); - -export default connectToStores(updateBillingInfoPage, - [BillingInfoFormStore], - function({ getStore }, props) { - return getStore(BillingInfoFormStore).getState(); - }); diff --git a/app/scripts/components/account/billingplans/BillingInfo.css b/app/scripts/components/account/billingplans/BillingInfo.css deleted file mode 100644 index 246b626169..0000000000 --- a/app/scripts/components/account/billingplans/BillingInfo.css +++ /dev/null @@ -1,7 +0,0 @@ -@import 'dux/css/colors.css'; - -.infoContent { - border-left: 1px solid var(--iron); - padding: 0 3rem; - margin: .5rem 0; -} diff --git a/app/scripts/components/account/billingplans/BillingInfo.jsx b/app/scripts/components/account/billingplans/BillingInfo.jsx deleted file mode 100644 index 5b5f210f25..0000000000 --- a/app/scripts/components/account/billingplans/BillingInfo.jsx +++ /dev/null @@ -1,132 +0,0 @@ -'use strict'; - -import React, { PropTypes } from 'react'; -import { Link } from 'react-router'; - -import Button from '@dux/element-button'; -import { SplitSection } from '../../common/Sections.jsx'; -import FA from '../../common/FontAwesome.jsx'; -import styles from './BillingInfo.css'; - -var BillingInfo = React.createClass({ - propTypes: { - currentPlan: PropTypes.shape({ - id: PropTypes.string, - plan: PropTypes.string - }), - accountInfo: PropTypes.shape({ - account_code: PropTypes.string, - username: PropTypes.string, - email: PropTypes.string, - first_name: PropTypes.string, - last_name: PropTypes.string, - company_name: PropTypes.string - }), - billingInfo: PropTypes.shape({ - city: PropTypes.string, - state: PropTypes.string, - zip: PropTypes.string, - first_name: PropTypes.string, - last_name: PropTypes.string, - address1: PropTypes.string, - address2: PropTypes.string, - country: PropTypes.string - }), - invoices: PropTypes.array, - isOrg: PropTypes.bool.isRequired, - username: PropTypes.string.isRequired - }, - _updateClick: function(e) { - e.preventDefault(); - if (this.props.isOrg) { - this.props.history.pushState(null, `/u/${this.props.username}/dashboard/billing/update-info/`); - } else { - this.props.history.pushState(null, '/account/billing-plans/update/'); - } - }, - render: function() { - const { - accountInfo, - billingInfo, - currentPlan - } = this.props; - if (accountInfo.newBilling) { - return ( -
    - ); - } - let subtitle = ( -
    -
    -

    * fields required to complete a billing transaction

    -
    -
    -
    - -
    -
    -
    - ); - let cardInfo; - if (billingInfo.card_type && billingInfo.last_four) { - cardInfo = ( -
    -
    Card Info:
    -
    - {billingInfo.first_name} {billingInfo.last_name}
    - {billingInfo.card_type} card ending with x{billingInfo.last_four}
    - Expiration: {billingInfo.month}/{billingInfo.year} -
    -
    - ); - } - let addressInfo; - if (billingInfo.address1 && billingInfo.country) { - addressInfo = ( -
    -
    Billing Address:
    -
    - {billingInfo.address1}
    - {billingInfo.address2}
    - {billingInfo.city} {billingInfo.state} {billingInfo.zip}
    - {billingInfo.country} -
    -
    - ); - } - return ( - -
    -
    -
    Name:
    -
    -
    -
    {accountInfo.first_name} {accountInfo.last_name}
    -
    -
    -
    -
    -
    Email:
    -
    -
    -
    {accountInfo.email}
    -
    -
    -
    -
    -
    Company:
    -
    -
    -
    {accountInfo.company_name}
    -
    -
    - { cardInfo } - { addressInfo } -
    - ); - } -}); - -module.exports = BillingInfo; diff --git a/app/scripts/components/account/billingplans/BillingInfoForm.css b/app/scripts/components/account/billingplans/BillingInfoForm.css deleted file mode 100644 index 07b96a3836..0000000000 --- a/app/scripts/components/account/billingplans/BillingInfoForm.css +++ /dev/null @@ -1,36 +0,0 @@ -@import 'dux/css/colors.css'; -@import 'dux/css/box.css'; - -.marginBottom { - margin-bottom: var(--default-margin); -} - -.form { - padding: 0 var(--default-margin); -} - -.billingDropdown { - width: 100%; - margin-bottom: 1.5rem; -} - -.error { - border: 1px solid var(--primary-5); -} - -.billingFormSection { - margin-bottom: 1.5rem; -} - -.dateText { - text-align: center; - height: 2rem; - display: flex; - align-items: center; - margin-bottom: 2rem; -} - -.globalError { - color: var(--primary-5); - padding-bottom: 1rem; -} \ No newline at end of file diff --git a/app/scripts/components/account/billingplans/BillingInfoForm.jsx b/app/scripts/components/account/billingplans/BillingInfoForm.jsx deleted file mode 100644 index 80fb22eb19..0000000000 --- a/app/scripts/components/account/billingplans/BillingInfoForm.jsx +++ /dev/null @@ -1,380 +0,0 @@ -'use strict'; - -import React, { PropTypes } from 'react'; -const { string, number, object, bool, func, shape, oneOfType } = PropTypes; -import { Link } from 'react-router'; -import includes from 'lodash/collection/includes'; -import map from 'lodash/collection/map'; -import classnames from 'classnames'; - -import DUXInput from '../../common/DUXInput.jsx'; -import FA from '../../common/FontAwesome.jsx'; -import acceptedCards from '../../common/data/acceptedCards.js'; -import updateBillingInfoFormField from '../../../actions/updateBillingInfoFormField.js'; -import validateBillingInfo from '../../../actions/common/validateBillingInfo.js'; -import { STATUS } from 'stores/billingformstore/Constants.js'; -import { Button } from 'dux'; -import Card, { Block } from '@dux/element-card'; - -var countries = require('common/data/countries.js'); -var states = require('common/data/states.js'); -var months = require('common/data/months.js'); -var years = require('common/data/years.js'); - -import styles from './BillingInfoForm.css'; -var debug = require('debug')('BillingInfoForm:'); - -var _mkOptions = function(list_item){ - return ( - - ); -}; - -var _mkCountryOptions = function(country) { - return ( - - ); -}; - -var BillingInfoForm = React.createClass({ - contextTypes: { - getStore: func.isRequired, - executeAction: func.isRequired - }, - propTypes: { - isOrg: bool.isRequired, - username: string.isRequired, - accountInfo: shape({ - account_code: string, - username: string, - email: string, - first_name: string, - last_name: string, - company_name: string - }), - billingInfo: shape({ - city: string, - state: string, - zip: string, - first_name: string, - last_name: string, - address1: string, - address2: string, - country: string - }), - card: shape({ - number: string, - cvv: string, - month: oneOfType([number, string]), - year: oneOfType([number, string]), - type: string - }), - fieldErrors: object.isRequired, - errorMessage: string, - STATUS: string.isRequired, - history: object.isRequired - }, - _onChange(field, fieldKey) { - return (e) => { - this.context.executeAction(updateBillingInfoFormField, { - field, - fieldKey, - fieldValue: e.target.value - }); - }; - }, - _onSelectChange(field, fieldKey) { - return (e) => { - var fieldValue = e.target.options[e.target.selectedIndex].value; - if (fieldKey === 'month' || fieldKey === 'year') { - fieldValue = parseInt(fieldValue, 10); - } - this.context.executeAction(updateBillingInfoFormField, { - field, - fieldKey, - fieldValue: fieldValue - }); - }; - }, - _onBackClick(e) { - e.preventDefault(); - if (this.props.isOrg) { - this.props.history.pushState(null, `/u/${this.props.username}/dashboard/billing/`); - } else { - this.props.history.pushState(null, '/account/billing-plans/'); - } - }, - _mkIconFromCardType(cardType) { - const icon = acceptedCards[cardType]; - if (icon) { - return (); - } - }, - formSubmit(e){ - e.preventDefault(); - const billing = this.props.billingInfo; - let validate = window.recurly.validate; - const fieldErrors = { - number: !validate.cardNumber(this.props.card.number), - expiry: !validate.expiry(this.props.card.month, this.props.card.year), - cvv: !validate.cvv(this.props.card.cvv), - first_name: !billing.first_name, - last_name: !billing.last_name, - city: !billing.city, - address1: !billing.address1, - country: !billing.country - }; - const accountErr = { hasError: !this.props.accountInfo.email }; - if (includes(fieldErrors, true) || accountErr.hasError ) { - const hasError = { fieldErrors, accountErr }; - this.context.executeAction(validateBillingInfo({storePrefix: 'BILLING'}), hasError); - } else { - this.props.submitAction(); - } - }, - render: function() { - const { card } = this.props; - const cardIcon = card.number ? this._mkIconFromCardType(card.type) : null; - var expiryClass = classnames({ - [styles.error]: this.props.fieldErrors.expiry, - [styles.billingDropdown]: true - }); - var countryClass = classnames({ - [styles.billingDropdown]: true, - [styles.error]: this.props.fieldErrors.country - }); - let submit = 'Submit'; - if (this.props.STATUS === STATUS.ATTEMPTING) { - submit = ( -
    - Submitting -
    - ); - } - var intent; - if (this.props.STATUS === STATUS.SUCCESS) { - intent = 'success'; - submit = ( -
    - Redirecting -
    - ); - } else if (this.props.STATUS === STATUS.FORM_ERROR) { - intent = 'alert'; - } - const submitButton = ( - - ); - return ( - - -
    -
    -
    Contact Info:
    -
    -
    -
    - -
    -
    - -
    -
    - -
    -
    - -
    -
    - -
    -
    - -
    -
    - -
    -
    -
    -
    Billing Info:
    -
    -
    -
    - -
    -
    - -
    -
    -
    -
    - -
    -
    - -
    -
    - {cardIcon} -
    -
    -
    -
    - Expires -
    -
    - -
    -
    - / -
    -
    - -
    -
    -
    -
    - -
    -
    - -
    -
    - -
    -
    -
    -
    - -
    -
    - -
    -
    -
    - { this.props.errorMessage } -
    -
    -
    - { submitButton } -
    -
    - -
    -
    -
    -
    -
    - ); - } -}); - -var PostalComponent = React.createClass({ - propTypes: { - billingInfo: shape({ - city: string, - state: string, - zip: string, - first_name: string, - last_name: string, - address1: string, - address2: string, - country: string - }), - onChange: func.isRequired, - onSelectChange: func.isRequired - }, - render: function() { - var countryState; - var country = this.props.billingInfo.country; - var stateClass = this.props.fieldErrors.state ? 'billing-dropdown error' : 'billing-dropdown'; - //IF US TERRITORY - ADD STATES SELECT - if (includes(['US', 'UM'], country)) { - countryState = ( -
    - -
    - ); - } else { - countryState = ( -
    - -
    - ); - } - return ( -
    - {countryState} -
    - -
    -
    - ); - } -}); - -export default BillingInfoForm; diff --git a/app/scripts/components/account/billingplans/EnterpriseSubscriptions.css b/app/scripts/components/account/billingplans/EnterpriseSubscriptions.css deleted file mode 100644 index 0dffb51685..0000000000 --- a/app/scripts/components/account/billingplans/EnterpriseSubscriptions.css +++ /dev/null @@ -1,98 +0,0 @@ -@import 'dux/css/colors.css'; -@import 'dux/css/box.css'; - -.cancel { - float: right; - color: var(--primary-5); -} -.cancel:hover { - color: color(var(--primary-5) blackness(15%)); -} - -.title { - color: var(--primary-1); - i { - color: var(--secondary-5); - } -} -.title:hover { - cursor: pointer; - color: color(var(--primary-1) blackness(55%)); - i { - color: color(var(--secondary-5) blackness(55%)); - } -} - -.cloudStarter { - margin-left: var(--default-margin); -} - -.centerText { - text-align: center; -} - -.check { - color: var(--primary-2); -} - -.download { - margin-right: var(--default-margin);; -} - -.curlHelp { - font-size: .875rem; - font-weight: 500; - margin-bottom: 1rem; -} - -.curlWrap { - width: 100%; -} - -.curlCommand { - resize: none; - overflow: hidden; - height: inherit; -} - -.clipboard { - height: 3rem; - display:flex; - flex-direction: row; - align-items: center; -} - -.downloadFlexItem { - display: flex; - flex-flow: row nowrap; - flex-grow: 4; - flex-basis: 0; - padding: 0 1rem; - word-break: break-word; - max-width: 100%; -} - -.flexbox { - display: flex; - flex-flow: column; -} - -.flexRow { - min-height: 9rem; - padding: 1rem; - display: flex; - align-items: center; - background-color: var(--white); - border: 1px solid var(--secondary-5); - border-radius: 3px; - margin-bottom: .5rem; -} - -.flexItem { - display: flex; - flex-flow: row nowrap; - flex-grow: 1; - flex-basis: 0; - padding: 0.7em 1rem 0.7em 1rem; - word-break: break-word; -} diff --git a/app/scripts/components/account/billingplans/EnterpriseSubscriptions.jsx b/app/scripts/components/account/billingplans/EnterpriseSubscriptions.jsx deleted file mode 100644 index 8e9710c501..0000000000 --- a/app/scripts/components/account/billingplans/EnterpriseSubscriptions.jsx +++ /dev/null @@ -1,160 +0,0 @@ -'use strict'; - -import React, { PropTypes } from 'react'; -const { string, shape, object, func } = PropTypes; -import { Link } from 'react-router'; -import { FullSection } from '../../common/Sections.jsx'; -import FA from '../../common/FontAwesome'; -import styles from './EnterpriseSubscriptions.css'; -import CopyCodeBox from 'common/CopyCodeBox'; -import classnames from 'classnames'; -import {DEB, RPM} from 'common/data/csEngineInstructions'; -const debug = require('debug')('EnterpriseSubscriptions'); - -var EnterpriseSubscriptions = React.createClass({ - propTypes: { - currentPlan: shape({ - id: string, - plan: string - }), - stopSubscription: func.isRequired, - unsubscribing: string, - user: object, - history: object.isRequired - }, - getInitialState() { - return { - confirmAction: '' - }; - }, - selectAction(plan) { - return (e) => { - e.preventDefault(); - this.setState({confirmAction: plan}); - }; - }, - cancelSelectPlan: function(e) { - e.preventDefault(); - this.setState({confirmAction: ''}); - }, - moreInfo: function(e) { - e.preventDefault(); - this.props.history.pushState(null, '/enterprise/'); - }, - purchaseCloud: function(e) { - e.preventDefault(); - this.props.history.pushState(null, '/enterprise/cloud-starter/'); - }, - render: function() { - let owned; - let price; - let subInfo; - let cloudActionButton; - let curlBody; - - // Hide Cloud Starter for anyone who has not already purchased it - if (this.props.currentPlan.package !== 'cloud_starter') { - return null; - } - - owned = ( -
    Currently Subscribed 
    - ); - if (this.state.confirmAction === 'cloud') { - cloudActionButton = ( -
    - Confirm or  - Cancel -
    - ); - } else { - cloudActionButton = ( - - ); - } - if (this.props.unsubscribing === 'package' || this.props.unsubscribing === 'subscription') { - cloudActionButton = (
    Removing Subscription
    ); - } - - let cloudStarter = ( -
    -
    -

     Cloud Starter

    - {owned} -
    -
    - ); - - if (this.state.confirmAction === 'download') { - cloudActionButton = null; - cloudStarter = null; - curlBody = ( -
    -
    -
    -
    - * Copy and run either the RPM or the DEB specific instructions in your terminal. - -
    -
    -
    -
    - RPM - -
    -
    -
    -
    - DEB - - - - For more details about this installation,  - - view our documentation - - -
    -
    -
    -
    - ); - } else { - price = ( -
    $150/mo
    - ); - subInfo = ( -
    -
    - 20 Private Repositories
    - 10 Docker Engines
    - Email Support -
    -
    - ); - } - return ( - -
    -
    - {cloudStarter} - {price} - {subInfo} - {cloudActionButton} - {curlBody} -
    -
    -
    - ); - } -}); - -module.exports = EnterpriseSubscriptions; diff --git a/app/scripts/components/account/billingplans/InvoiceTables.jsx b/app/scripts/components/account/billingplans/InvoiceTables.jsx deleted file mode 100644 index fab6841bda..0000000000 --- a/app/scripts/components/account/billingplans/InvoiceTables.jsx +++ /dev/null @@ -1,73 +0,0 @@ -'use strict'; -import React, { PropTypes } from 'react'; -import { Link } from 'react-router'; -import _ from 'lodash'; -import moment from 'moment'; -import { FullSection } from '../../common/Sections.jsx'; -import { FlexTable, FlexRow, FlexHeader, FlexItem } from '../../common/FlexTable.jsx'; -import downloadInvoice from '../../../actions/downloadInvoice.js'; -const debug = require('debug')('COMPONENT:INVOICE_TABLE'); - -let mkInvoiceTable = function(invoice) { - var subtotal = '$' + (parseInt(invoice.subtotal_in_cents, 10) / 100); - var total = '$' + (parseInt(invoice.total_in_cents, 10) / 100); - var date = moment.utc(invoice.created_at).format('MMM Do YYYY'); - debug('CREATED_AT: ', invoice.created_at); - debug('CREATED_AT_MOMENT: ', date); - return ( - - {date} - {invoice.invoice_number} - {invoice.state} - {total} - - Download Invoice - - - ); -}; - -var InvoiceTables = React.createClass({ - contextTypes: { - executeAction: React.PropTypes.func.isRequired - }, - propTypes: { - invoices: PropTypes.array, - username: PropTypes.string, - JWT: PropTypes.string - }, - downloadInvoice(id) { - return (e) => { - e.preventDefault(); - this.context.executeAction(downloadInvoice, {JWT: this.props.JWT, username: this.props.username, invoiceId: id}); - }; - }, - render: function() { - if (!this.props.JWT || _.isEmpty(this.props.invoices)) { - return ( -
    - ); - } else { - return ( - -
    - - - Date - Invoice # - State - Total - Download - - {this.props.invoices.map(mkInvoiceTable, this)} - -
    -
    - ); - } - } -}); - -module.exports = InvoiceTables; diff --git a/app/scripts/components/account/billingplans/Plans.css b/app/scripts/components/account/billingplans/Plans.css deleted file mode 100644 index 700f88f13b..0000000000 --- a/app/scripts/components/account/billingplans/Plans.css +++ /dev/null @@ -1,58 +0,0 @@ -@import 'dux/css/colors.css'; -@import 'dux/css/box.css'; - -.cancel { - color: var(--primary-5); -} -.cancel:hover { - color: color(var(--primary-5) blackness(15%)); -} - -.shield { - margin-right: 0.5rem; -} - -.nautilusUpsellRow { - display: flex; - width: 100%; - padding: 0.3rem; - background: #f1f6fb; -} - -.nautilusUpsell { - width: 100%; - margin: 0.75rem; - background: var(--white); - border: 1px solid var(--secondary-5); - border-radius: var(--global-radius); - - label { - display: flex; - align-items: center; - padding: 0.5rem; - font-size: 1rem; - font-weight: 400; - line-height: 1rem; - color: var(--secondary-2); - } -} - -.nautilusEnabled { - border-color: #22b8eb; -} - -.enableNautilus { - display: flex; - align-items: center; - margin: 0 0.5rem; - - input { - margin: 0; - } -} - -.monitoredWithNautilus { - display: flex; - align-items: center; - margin: 0.5rem; -} diff --git a/app/scripts/components/account/billingplans/Plans.jsx b/app/scripts/components/account/billingplans/Plans.jsx deleted file mode 100644 index 72d6ef7eb4..0000000000 --- a/app/scripts/components/account/billingplans/Plans.jsx +++ /dev/null @@ -1,355 +0,0 @@ -'use strict'; -/*eslint-disable camelcase*/ -import React, { PropTypes } from 'react'; -import { Link } from 'react-router'; -import PlansStore from '../../../stores/PlansStore'; -import updateSubscriptionPlanOrPackage from '../../../actions/updateSubscriptionPlanOrPackage.js'; -import defaultPlans from 'common/data/plans.js'; -/** -* Used for the public pricing page (/billing-plans/) -* We should either find a workaround for defaultPlans or remove this route altogether -*/ -import FA from '../../common/FontAwesome.jsx'; -import _ from 'lodash'; -import connectToStores from 'fluxible-addons-react/connectToStores'; -import { FullSection } from '../../common/Sections.jsx'; -import { FlexTable, FlexRow, FlexHeader, FlexItem } from '../../common/FlexTable.jsx'; -import styles from './Plans.css'; -const CLOUD_METERED = 'cloud_metered'; -const debug = require('debug')('Plans:'); -const NAUTILUS = 'nautilus'; -import Tooltip from 'rc-tooltip'; -import classnames from 'classnames'; - - -function mkShortPlanIntervalUnit(unit) { - if (unit === 'months'){ - return 'mo'; - } else if (unit === 'years') { - return 'yr'; - } else { - return 'mo'; - } -} - -let mkPricingElement = function(plan) { - var action; - var shortInterval = mkShortPlanIntervalUnit(plan.plan_interval_unit); - var price = parseInt(plan.price_in_cents, 10) / 100; - var pricePerInterval = {price: price, interval: shortInterval}; - - var currentPlanName = this.props.currentPlan.plan || 'free'; - var currentSize = this.getPlanSize(currentPlanName); - debug(currentSize); - if (this.props.JWT) { - if (!!this.props.currentPlan && currentPlanName === plan.plan_code) { - action = 'Current Plan'; - } else if (this.state.confirmPlan === plan.plan_code) { - action = ( -
    - Confirm or  - Cancel -
    - ); - } else if (this.props.updatePlan === plan.plan_code) { - action = ( -
    - Processing -
    - ); - } else if (!!this.props.currentPlan && currentSize > plan.num_private_repos) { - action = (Downgrade Plan); - } else { - action = (Upgrade Plan); - } - } else { - action = ( -
    - Sign up or Log in -
    - ); - } - - return ( - - ); -}; - -function isNautilusEnabled(currentPlan) { - const { add_ons } = currentPlan; - if (!add_ons) { - return false; - } - return _.indexOf(add_ons, NAUTILUS) >= 0; -} - - -var PlanRow = React.createClass({ - displayName: 'PlanRow', - propTypes: { - is_active: PropTypes.bool.isRequired, - num_private_repos: PropTypes.number.isRequired, - name: PropTypes.string.isRequired, - - pricePerInterval: PropTypes.shape({ - price: PropTypes.number.isRequired, - interval: PropTypes.string.isRequired - }), - action: PropTypes.oneOfType([ - PropTypes.string.isRequired, - PropTypes.object.isRequired - ]) - }, - render() { - if (!this.props.is_active) { - return null; - } else { - var ppi = this.props.pricePerInterval; - return ( - - {this.props.name} - ${ppi.price}/{ppi.interval} - {this.props.num_private_repos} - {this.props.num_private_repos} - {this.props.action} - - ); - } - } -}); - -var PlansTable = React.createClass({ - displayName: 'PlansTable', - - contextTypes: { - getStore: React.PropTypes.func.isRequired, - executeAction: React.PropTypes.func.isRequired - }, - - propTypes: { - JWT: PropTypes.string, - username: PropTypes.oneOfType([ - PropTypes.string, PropTypes.bool - ]), - history: PropTypes.object.isRequired, - user: PropTypes.object, - plansList: PropTypes.array.isRequired, - currentPlan: PropTypes.shape({ - subscription_uuid: PropTypes.string, - plan: PropTypes.string, - package: PropTypes.string - }), - stopSubscription: PropTypes.func.isRequired, - billingInfo: PropTypes.object.isRequired, - isNewBilling: PropTypes.bool.isRequired, - updatePlan: PropTypes.string - }, - - getInitialState() { - return { - confirmPlan: '', - hasNautilus: isNautilusEnabled(this.props.currentPlan) - }; - }, - - getPlanSize(plan_code) { - return (_.result(_.find(this.props.plansList, {plan_code: plan_code}), 'num_private_repos')); - }, - - selectConfirmPlan(plan) { - return (e) => { - e.preventDefault(); - this.setState({confirmPlan: plan.plan_code}); - }; - }, - - cancelSelectPlan: function(e) { - e.preventDefault(); - this.setState({confirmPlan: ''}); - }, - - _stopSubscription: function(e) { - e.preventDefault(); - this.setState({confirmPlan: ''}); - this.props.stopSubscription(); - }, - - updateSubscriptionsPlan(plan) { - return (e) => { - e.preventDefault(); - this.setState({confirmPlan: ''}); - if (this.props.isNewBilling) { - // IF USER HAS NO BILLING ACCOUNT OR NO BILLING PAYMENT INFORMATION - // GO TO CREATION PAGE - if (_.has(this.props.user, 'username')) { - this.props.history.pushState(null, '/account/billing-plans/create-subscription/', {plan: plan.plan_code}); - } else if (_.has(this.props.user, 'orgname')) { - this.props.history.pushState(null, `/u/${this.props.user.orgname}/dashboard/billing/create-subscription/`, {plan: plan.plan_code}); - } - } else { - // IF USER HAS BILLING INFORMATION - THEN WE CAN JUST UPGRADE - this.context.executeAction(updateSubscriptionPlanOrPackage, - {JWT: this.props.JWT, - username: this.props.username, - subscription_uuid: this.props.currentPlan.subscription_uuid, - plan_code: plan.plan_code, - package_code: this.props.currentPlan.package - }); - } - }; - }, - - toggleNautilus() { - const { currentPlan, username, JWT } = this.props; - const { plan, subscription_uuid } = currentPlan; - const { hasNautilus } = this.state; - const add_ons = hasNautilus ? [] : [NAUTILUS]; - const data = { - plan_code: plan, - username, - add_ons, - subscription_uuid, - JWT - }; - - this.context.executeAction(updateSubscriptionPlanOrPackage, data); - this.setState({ hasNautilus: !hasNautilus }); - }, - - renderNautilusUpsell() { - const { currentPlan } = this.props; - const isFreePlan = !currentPlan || !currentPlan.plan - || currentPlan.plan === CLOUD_METERED; - let text; - const shield = ( - - - - - - - - - ); - if (isFreePlan) { - text = 'Enable security scanning when you upgrade your plan.'; - const url = 'https://docs.docker.com/docker-cloud/builds/image-scan/'; - const link = ( - - Learn more about Docker Security Scanning - - ); - return ( -
    -
    - {shield} - {text} {link} -
    -
    - ); - } - - var nautilusUpsellClasses = classnames({ - [styles.nautilusUpsell]: true, - [styles.nautilusEnabled]: this.state.hasNautilus - }); - - text = [ - 'Monitor with Docker Security Scanning - available for your private ', - 'repositories for free while in preview.' - ].join(''); - return ( -
    - -
    - ); - }, - - render() { - const {JWT, currentPlan, updatePlan, plansList, isOrg} = this.props; - var action; - if (!JWT) { - action = ( -
    - Sign up or Log in -
    - ); - } else if (!currentPlan.plan || currentPlan.plan === CLOUD_METERED) { - action = 'Current Plan'; - } else if (updatePlan === CLOUD_METERED) { - action = ( -
    Removing Plan
    - ); - } else if (this.state.confirmPlan === 'free') { - action = ( -
    - Confirm or  - Cancel -
    - ); - } else { - action = Downgrade Plan; - } - let allPlans = defaultPlans; - if (!_.isEmpty(plansList)) { - allPlans = _.clone(plansList); - } - const privateRepos = isOrg ? '0' : '1'; - return ( - -
    - - - - Plan - - - Price - - - Private Repositories - - - Parallel Builds - - - - - Free - $0/mo - {privateRepos} - {privateRepos} - {action} - - {allPlans.map(mkPricingElement, this)} -
    - {this.renderNautilusUpsell()} -
    -
    -
    -
    - ); - } -}); - -export default connectToStores(PlansTable, - [PlansStore], - function({ getStore }, props) { - return getStore(PlansStore).getState(); - }); diff --git a/app/scripts/components/account/forms/AccountInfoForm.css b/app/scripts/components/account/forms/AccountInfoForm.css deleted file mode 100644 index 72cf57abed..0000000000 --- a/app/scripts/components/account/forms/AccountInfoForm.css +++ /dev/null @@ -1,21 +0,0 @@ -@import 'dux/css/colors.css'; - -.accountForm { - lost-flex-container: row; -} -.lostFormInputs { - lost-column: 2/3; -} -.accountButtonWrapper { - lost-column: 1/3; - align-self: flex-end; - > * { - lost-column: 1/2; - margin-bottom: 1rem; - } -} - -.error { - color: var(--primary-5); - margin-bottom: 0.3rem; -} diff --git a/app/scripts/components/account/forms/AccountInfoForm.jsx b/app/scripts/components/account/forms/AccountInfoForm.jsx deleted file mode 100644 index 72f34c38cc..0000000000 --- a/app/scripts/components/account/forms/AccountInfoForm.jsx +++ /dev/null @@ -1,133 +0,0 @@ -'use strict'; - -import React from 'react'; -import classnames from 'classnames'; -import connectToStores from 'fluxible-addons-react/connectToStores'; - -import AccountInfoFormStore from '../../../stores/AccountInfoFormStore'; -import SimpleInput from 'common/SimpleInput.jsx'; -import SaveSettings from '../../../actions/saveSettingsData'; -import updateAccountInfoFormField from '../../../actions/updateAccountInfoFormField'; -import Button from '@dux/element-button'; -import { SplitSection } from '../../common/Sections.jsx'; - -import styles from './AccountInfoForm.css'; -import FA from 'common/FontAwesome.jsx'; -import {STATUS as BASE_STATUS} from 'stores/common/Constants.js'; - -var AccountInfoForm = React.createClass({ - contextTypes: { - executeAction: React.PropTypes.func.isRequired - }, - _onChange(fieldKey) { - return (e) => { - this.context.executeAction(updateAccountInfoFormField, { - fieldKey, - fieldValue: e.target.value - }); - }; - }, - onSubmit: function(e) { - e.preventDefault(); - this.context.executeAction(SaveSettings, { - JWT: this.props.JWT, - username: this.props.user.username, - updateData: this.props.values - }); - }, - renderButton: function(STATUS) { - switch (STATUS) { - case BASE_STATUS.SUCCESSFUL: - return ( - - ); - case BASE_STATUS.ERROR: - return ( - - ); - case BASE_STATUS.ATTEMPTING: - return ( - - ); - default: - return ( - - ); - } - }, - render: function() { - const { - full_name, - company, - location, - profile_url, - gravatar_email - } = this.props.fields; - return ( - This information will be visible to all users of Docker Hub.

    }> -
    - -
    -
    - {full_name.error} -
    - - -
    - {company.error} -
    - - -
    - {location.error} -
    - - -
    - {profile_url.error} -
    - - -
    - {gravatar_email.error} -
    - -
    - -
    - { this.renderButton(this.props.STATUS) } -
    - -
    -
    - ); - } -}); - -export default connectToStores(AccountInfoForm, - [ - AccountInfoFormStore - ], - function({ getStore }, props) { - return getStore(AccountInfoFormStore).getState(); - }); diff --git a/app/scripts/components/account/forms/ChangePassForm.css b/app/scripts/components/account/forms/ChangePassForm.css deleted file mode 100644 index 5afebc5a6e..0000000000 --- a/app/scripts/components/account/forms/ChangePassForm.css +++ /dev/null @@ -1,31 +0,0 @@ -@import 'dux/css/colors.css'; -@import 'dux/css/box'; - -.changePassSave { - display: flex; - align-items: flex-end; -} - -.label { - color: #7a8491; -} - -.error { - color: var(--primary-5); - margin-bottom: 0.3rem; -} - -.wrapper { - lost-flex-container: row; -} -.buttons { - lost-column: 1/3; - align-self: flex-end; - > * { - margin-bottom: 1rem; - lost-column: 1/2; - } -} -.lostFormInputs { - lost-column: 2/3; -} diff --git a/app/scripts/components/account/forms/ChangePassForm.jsx b/app/scripts/components/account/forms/ChangePassForm.jsx deleted file mode 100644 index 3e10e2fb7a..0000000000 --- a/app/scripts/components/account/forms/ChangePassForm.jsx +++ /dev/null @@ -1,163 +0,0 @@ -'use strict'; - -import React, { PropTypes } from 'react'; -import connectToStores from 'fluxible-addons-react/connectToStores'; -import _ from 'lodash'; -import classnames from 'classnames'; - -import ChangePasswordStore from '../../../stores/ChangePasswordStore'; -import SimpleInput from 'common/SimpleInput.jsx'; -import changePass from '../../../actions/changePassword'; -import updateChangePassStore from '../../../actions/updateChangePassStore'; -import Button from '@dux/element-button'; -import { SplitSection } from '../../common/Sections.jsx'; - -import styles from './ChangePassForm.css'; - -var debug = require('debug')('ChangePassForm'); - -var ChangePassForm = React.createClass({ - contextTypes: { - getStore: PropTypes.func.isRequired, - executeAction: PropTypes.func.isRequired - }, - getDefaultProps: function() { - return { - JWT: '', - username: '' - }; - }, - getInitialState: function() { - return { - confpassErr: '' - }; - }, - onStoreChange: function() { - var store = this.context.getStore(ChangePasswordStore); - this.setState(store.getState()); - }, - oldPassChange: function(e) { - e.preventDefault(); - var oldpass = e.target.value; - var payload = { - oldpass: oldpass, - newpass: this.props.changePasswordStore.newpass, - confpass: this.props.changePasswordStore.confpass - }; - this.context.executeAction(updateChangePassStore, payload); - }, - newPassChange: function(e) { - e.preventDefault(); - var newpass = e.target.value; - var payload = { - oldpass: this.props.changePasswordStore.oldpass, - newpass: newpass, - confpass: this.props.changePasswordStore.confpass - }; - this.context.executeAction(updateChangePassStore, payload); - }, - confirmChange: function(e) { - var confpass = e.target.value; - var payload = { - oldpass: this.props.changePasswordStore.oldpass, - newpass: this.props.changePasswordStore.newpass, - confpass: confpass - }; - this.context.executeAction(updateChangePassStore, payload); - this.setState({ - confpassErr: false - }); - }, - onSubmit: function(e) { - e.preventDefault(); - var store = this.props.changePasswordStore; - if (store.confpass === store.newpass) { - var payload = { - JWT: this.props.JWT, - username: this.props.username, - oldpassword: this.props.changePasswordStore.oldpass, - newpassword: this.props.changePasswordStore.newpass - }; - this.context.executeAction(changePass, payload); - } else { - debug('passwords do not match'); - this.setState({ - confpassErr: true - }); - } - }, - render: function() { - var store = this.props.changePasswordStore; - var oldHasErr = _.has(store.err, 'old_password') || _.has(store.err, 'non_field_errors'); - var oldError; - var newHasErr = _.has(store.err, 'new_password'); - var newError; - if (oldHasErr) { - if (_.has(store.err, 'old_password')) { - oldError = store.err.old_password[0]; - } else { - oldError = store.err.non_field_errors[0]; - } - } - if (newHasErr) { - newError = store.err.new_password[0]; - } - - return ( - Please choose a password which is longer than 6 characters.

    }> -
    -
    -
    - - -
    - { oldError } -
    - - - -
    - { newError } -
    - - - -
    - { this.state.confpassErr ? 'Make sure passwords are identical' : '' } -
    - - -
    -
    - -
    -
    -
    -
    - ); - } -}); - -export default connectToStores(ChangePassForm, - [ChangePasswordStore], - function({ getStore }, props) { - return { - changePasswordStore: getStore(ChangePasswordStore).getState() - }; - }); diff --git a/app/scripts/components/account/forms/EmailForm.css b/app/scripts/components/account/forms/EmailForm.css deleted file mode 100644 index 8a176e8033..0000000000 --- a/app/scripts/components/account/forms/EmailForm.css +++ /dev/null @@ -1,17 +0,0 @@ -@import 'dux/css/colors.css'; -@import 'dux/css/box'; - -.addError { - padding: .5rem .5rem 0 .5rem; - color: var(--primary-5); -} - -.noBottomMargin { - width: 100%; - input { - margin-bottom: 0; - } - > * { - margin-bottom: 0; - } -} diff --git a/app/scripts/components/account/forms/EmailForm.jsx b/app/scripts/components/account/forms/EmailForm.jsx deleted file mode 100644 index 4e98950483..0000000000 --- a/app/scripts/components/account/forms/EmailForm.jsx +++ /dev/null @@ -1,121 +0,0 @@ -'use strict'; - -import React, { PropTypes } from 'react'; -import has from 'lodash/object/has'; -import classnames from 'classnames'; -import connectToStores from 'fluxible-addons-react/connectToStores'; -import Button from '@dux/element-button'; -import Card, { Block } from '@dux/element-card'; - -import { SplitSection } from 'common/Sections.jsx'; -import { FlexTable, FlexRow, FlexHeader, FlexItem } from 'common/FlexTable.jsx'; -import SimpleInput from 'common/SimpleInput'; -import EmailElement from './email/EmailElement.jsx'; -import addUserEmail from 'actions/addUserEmail.js'; -import addUserEmailChange from 'actions/addUserEmailChange.js'; -import setNewPrimaryEmail from 'actions/setNewPrimaryEmail'; -import EmailsStore from 'stores/EmailsStore'; - -import styles from './EmailForm.css'; - -var debug = require('debug')('EmailForm'); - -var EmailForm = React.createClass({ - - contextTypes: { - executeAction: React.PropTypes.func.isRequired - }, - propTypes: { - user: PropTypes.object.isRequired, - JWT: PropTypes.string.isRequired, - emails: PropTypes.array.isRequired, - addEmail: PropTypes.string, - addError: PropTypes.string, - emailConfirmations: PropTypes.object - }, - onAddEmailChange: function(e) { - e.preventDefault(); - this.context.executeAction(addUserEmailChange, {email: e.target.value}); - }, - saveNewEmail: function(e) { - e.preventDefault(); - this.context.executeAction(addUserEmail, { - JWT: this.props.JWT, - newEmail: this.props.addEmail, - user: this.props.user - }); - }, - setNewPrimary(id) { - return (e) => { - e.preventDefault(); - var payload = { - JWT: this.props.JWT, - username: this.props.user.username, - emailId: id - }; - this.context.executeAction(setNewPrimaryEmail, payload); - }; - }, - _mkEmailElement({id, user, primary, email, verified}) { - const {emailConfirmations} = this.props; - let emailStatus = ''; - if (has(emailConfirmations, id)) { - emailStatus = emailConfirmations[id]; - } - return (); - }, - render: function() { - const buttonVariant = !this.props.addError ? 'primary' : 'alert'; - let errorMsg; - if (this.props.addError) { - errorMsg = (
    {this.props.addError}
    ); - } - return ( -

    This email address will be used for all notifications and correspondence from Docker.

    -

    If you wish to designate a different email address as primary, first add a new address to your account and then click "make primary".

    )}> - - - -
    - - {errorMsg} - -
    - -
    - -
    -
    -
    - {this.props.emails.map(this._mkEmailElement)} -
    - - ); - } -}); - -export default connectToStores(EmailForm, - [ - EmailsStore - ], function({ getStore }, props) { - return getStore(EmailsStore).getState(); - }); diff --git a/app/scripts/components/account/forms/email/DeleteEmailElement.jsx b/app/scripts/components/account/forms/email/DeleteEmailElement.jsx deleted file mode 100644 index 64c16fdb85..0000000000 --- a/app/scripts/components/account/forms/email/DeleteEmailElement.jsx +++ /dev/null @@ -1,44 +0,0 @@ -'use strict'; - -import React, { PropTypes } from 'react'; -import deleteEmail from 'actions/deleteEmail.js'; -import { FlexItem } from 'common/FlexTable.jsx'; -import styles from './EmailComponents.css'; -import FA from 'common/FontAwesome.jsx'; - -export default React.createClass({ - displayName: 'deleteEmailElement', - propTypes: { - isPrimaryEmail: PropTypes.bool.isRequired, - emailid: PropTypes.number.isRequired, - user: PropTypes.string.isRequired, - JWT: PropTypes.string.isRequired - }, - contextTypes: { - executeAction: PropTypes.func.isRequired - }, - deleteEmail: function(e) { - e.preventDefault(); - var payload = { - JWT: this.props.JWT, - username: this.props.user, - delEmailID: this.props.emailid - }; - this.context.executeAction(deleteEmail, payload); - }, - render() { - if(this.props.isPrimaryEmail) { - return ( - - ); - } else { - return ( - - - - - - ); - } - } -}); diff --git a/app/scripts/components/account/forms/email/EmailComponents.css b/app/scripts/components/account/forms/email/EmailComponents.css deleted file mode 100644 index dc8c95a9c0..0000000000 --- a/app/scripts/components/account/forms/email/EmailComponents.css +++ /dev/null @@ -1,24 +0,0 @@ -@import 'dux/css/colors.css'; - -.emailAddress { - word-wrap: break-word; -} - -.emphasis { - color: var(--secondary-3); - font-weight: 800; -} - -.failed { - color: var(--primary-5); -} - -.remove { - color: var(--primary-5); - transition: color .15s ease; - align-self: center; -} - -.remove:hover { - color: var(--secondary-1); - } diff --git a/app/scripts/components/account/forms/email/EmailElement.jsx b/app/scripts/components/account/forms/email/EmailElement.jsx deleted file mode 100644 index 3fee719c9e..0000000000 --- a/app/scripts/components/account/forms/email/EmailElement.jsx +++ /dev/null @@ -1,56 +0,0 @@ -'use strict'; - -import React, { PropTypes } from 'react'; -import { FlexTable, FlexRow, FlexHeader, FlexItem } from 'common/FlexTable.jsx'; -import styles from './EmailComponents.css'; -import PrimaryEmail from './PrimaryEmail'; -import VerifiedOrResend from './VerifiedOrResend'; -import DeleteEmailElement from './DeleteEmailElement'; - -export default React.createClass({ - displayName: 'EmailElement', - propTypes: { - user: PropTypes.string.isRequired, - isPrimaryEmail: PropTypes.bool.isRequired, - emailid: PropTypes.number.isRequired, - email: PropTypes.string.isRequired, - isVerified: PropTypes.bool.isRequired, - JWT: PropTypes.string.isRequired, - setNewPrimary: PropTypes.func.isRequired, - STATUS: PropTypes.string - }, - render(){ - const { - JWT, - user, - isVerified, - email, - emailid, - isPrimaryEmail, - setNewPrimary, - STATUS - } = this.props; - return ( - - -
    {email}
    -
    - - - -
    - ); - } -}); diff --git a/app/scripts/components/account/forms/email/PrimaryEmail.jsx b/app/scripts/components/account/forms/email/PrimaryEmail.jsx deleted file mode 100644 index 991d7f130a..0000000000 --- a/app/scripts/components/account/forms/email/PrimaryEmail.jsx +++ /dev/null @@ -1,37 +0,0 @@ -'use strict'; - -import React, { PropTypes } from 'react'; -import { FlexItem } from 'common/FlexTable.jsx'; -import styles from './EmailComponents.css'; - -export default React.createClass({ - displayName: 'PrimaryEmail', - propTypes: { - isVerified: PropTypes.bool.isRequired, - isPrimaryEmail: PropTypes.bool.isRequired, - emailID: PropTypes.number.isRequired, - setNewPrimary: PropTypes.func.isRequired - }, - contextTypes: { - executeAction: PropTypes.func.isRequired - }, - render() { - if (!this.props.isVerified) { - return ( - - ); - } else if (this.props.isPrimaryEmail) { - return ( - - primary - - ); - } else { - return ( - - make primary - - ); - } - } -}); diff --git a/app/scripts/components/account/forms/email/VerifiedOrResend.jsx b/app/scripts/components/account/forms/email/VerifiedOrResend.jsx deleted file mode 100644 index 3bfb874368..0000000000 --- a/app/scripts/components/account/forms/email/VerifiedOrResend.jsx +++ /dev/null @@ -1,53 +0,0 @@ -'use strict'; - -import React, { PropTypes } from 'react'; -import resendConfirmationEmail from 'actions/resendConfirmationEmail'; -import { FlexItem } from 'common/FlexTable.jsx'; -import styles from './EmailComponents.css'; -import FA from 'common/FontAwesome.jsx'; -import { EMAILSTATUS } from 'stores/emailsstore/Constants'; - -export default React.createClass({ - displayName: 'VerifiedOrResend', - propTypes: { - isVerified: PropTypes.bool.isRequired, - email: PropTypes.string.isRequired, - emailid: PropTypes.number.isRequired, - STATUS: PropTypes.string - }, - contextTypes: { - executeAction: PropTypes.func.isRequired - }, - _resendConfirmation(e) { - e.preventDefault(); - this.context.executeAction(resendConfirmationEmail, { - JWT: this.props.JWT, - emailID: this.props.emailid - }); - }, - render() { - const { STATUS } = this.props; - if(this.props.isVerified){ - return ( - verified - ); - } else if (STATUS === EMAILSTATUS.ATTEMPTING) { - return (Sending ); - } else if (STATUS === EMAILSTATUS.SUCCESS) { - return (Email Sent!); - } else if (STATUS === EMAILSTATUS.FAILED) { - return ( - -
    Failed
    -
    - ); - } else { - return ( - - Resend Email - - ); - } - } -}); diff --git a/app/scripts/components/account/notificationSettings/EmailNotifForm.css b/app/scripts/components/account/notificationSettings/EmailNotifForm.css deleted file mode 100644 index 4fc8366809..0000000000 --- a/app/scripts/components/account/notificationSettings/EmailNotifForm.css +++ /dev/null @@ -1,25 +0,0 @@ -@import 'dux/css/colors.css'; - -.button { - margin-bottom: -1rem; -} - -.success { - border: 1px solid var(--primary-2); -} - -.formError { - border: 1px solid var(--primary-5); -} - -.checkbox { - padding-top: .5rem; -} - -.notification { - margin-bottom: 1rem; -} -.notification:hover { - cursor: pointer; - cursor: hand; -} diff --git a/app/scripts/components/account/notificationSettings/EmailNotifForm.jsx b/app/scripts/components/account/notificationSettings/EmailNotifForm.jsx deleted file mode 100644 index 0b229c47dd..0000000000 --- a/app/scripts/components/account/notificationSettings/EmailNotifForm.jsx +++ /dev/null @@ -1,158 +0,0 @@ -'use strict'; -import React, { PropTypes } from 'react'; -import _ from 'lodash'; -import classnames from 'classnames'; -import connectToStores from 'fluxible-addons-react/connectToStores'; - -import styles from './EmailNotifForm.css'; - -import EmailNotifStore from '../../../stores/EmailNotifStore.js'; -import deleteEmailNotifs from '../../../actions/deleteEmailNotifs'; -import resetNotifications from '../../../actions/resetNotifications.js'; -import saveEmailNotifs from '../../../actions/saveEmailNotifs'; -import updateNotifCheckbox from '../../../actions/updateNotifCheckbox.js'; -import { Button } from 'dux'; -import { SplitSection } from '../../common/Sections'; -var debug = require('debug')('EmailNotifForm'); - -var EmailNotifForm = React.createClass({ - displayName: 'EmailNotifForm', - contextTypes: { - executeAction: PropTypes.func.isRequired, - getStore: PropTypes.func.isRequired - }, - propTypes: { - user: PropTypes.object.isRequired, - JWT: PropTypes.string.isRequired - }, - onNotifCheckboxClick: function(cboxType, evt) { - this.context.executeAction(updateNotifCheckbox, cboxType); - }, - //TODO: Fix this when we have time to change the backend API. This sucks atm. - _getNotificationPayload: function(type) { - var nType = ''; - switch (type) { - case 'auto': - nType = 'trusted_build_fail'; - break; - case 'star': - nType = 'new_repo_star'; - break; - case 'comment': - nType = 'new_repo_comment'; - break; - } - return { - 'user': this.props.user.username, - 'notification': nType, - 'last_occurrence': '1970-01-01T00:00:00Z' - }; - }, - _getNotificationDeletePayload: function(type) { - switch (type) { - case 'auto': - return this.props.autoBuildNotificationID; - case 'star': - return this.props.starNotificationID; - case 'comment': - return this.props.imgCommentNotificationID; - default: - break; - } - }, - onNotifSubmit: function(e) { - e.preventDefault(); - var store = this.context.getStore(EmailNotifStore); - var changed = store.hasChanged.bind(store); - //TODO: this NEEDS refactoring once we discuss a better way to handle notification settings! eek. - if (changed('star')) { - if (this.props.starNotification) { - var nStar = this._getNotificationPayload('star'); - this.context.executeAction(saveEmailNotifs, {jwt: this.props.JWT, notification: nStar}); - } else { - var nStarDel = this._getNotificationDeletePayload('star'); - if(nStarDel > 0) { - this.context.executeAction(deleteEmailNotifs, {jwt: this.props.JWT, notificationID: nStarDel}); - } - } - } - if (changed('comment')) { - if (this.props.imgCommentNotification) { - var nComment = this._getNotificationPayload('comment'); - this.context.executeAction(saveEmailNotifs, {jwt: this.props.JWT, notification: nComment}); - } else { - var nCommentDel = this._getNotificationDeletePayload('comment'); - if(nCommentDel > 0) { - this.context.executeAction(deleteEmailNotifs, {jwt: this.props.JWT, notificationID: nCommentDel}); - } - } - } - if (changed('auto')) { - if (this.props.autoBuildNotification) { - var nAuto = this._getNotificationPayload('auto'); - this.context.executeAction(saveEmailNotifs, {jwt: this.props.JWT, notification: nAuto}); - } else { - var nAutoDel = this._getNotificationDeletePayload('auto'); - if(nAutoDel > 0) { - this.context.executeAction(deleteEmailNotifs, {jwt: this.props.JWT, notificationID: nAutoDel}); - } - } - } - }, - onNotifCancel: function(e) { - debug('resetting email notifications'); - this.context.executeAction(resetNotifications, ['notifications']); - }, - render: function() { - return ( - The following settings will control how email is sent based on the occurrence of specific events.

    }> -
    -
    -
    - -
    -
    - Notify me when my Repositories get starred -
    -
    -
    -
    - -
    -
    - Notify me when a comment is posted on my Repositories -
    -
    -
    -
    - -
    -
    - Notify me when an automated build fails -
    -
    -
    -
    - -
    -
    - -
    -
    -
    -
    - ); - } -}); - -export default connectToStores(EmailNotifForm, - [EmailNotifStore], function({ getStore }, props) { - return getStore(EmailNotifStore).getState(); - }); diff --git a/app/scripts/components/account/orgs/OrganizationAddTeam.jsx b/app/scripts/components/account/orgs/OrganizationAddTeam.jsx deleted file mode 100644 index a703271d72..0000000000 --- a/app/scripts/components/account/orgs/OrganizationAddTeam.jsx +++ /dev/null @@ -1,86 +0,0 @@ -'use strict'; -import React, {Component, PropTypes} from 'react'; -import DUXInput from 'common/DUXInput.jsx'; -import createOrgTeamAction from '../../../actions/createOrgTeam'; -import OrgTeamStore from '../../../stores/OrgTeamStore'; -import connectToStores from 'fluxible-addons-react/connectToStores'; -import Button from '@dux/element-button'; -import styles from './TeamProfile.css'; - -import { STATUS as ORG_STATUS } from '../../../stores/orgteamstore/Constants'; -const { string, array, func, object } = PropTypes; - -class OrganizationAddTeam extends Component { - static contextTypes = { - executeAction: func.isRequired - } - - static propTypes = { - JWT: string.isRequired, - onCancel: func, - name: string, - description: string, - members: array, - errorDetails: object, - success: string, - STATUS: string - } - - state = { - teamname: '', - teamdesc: '', - members: [] - } - - _handleCreateTeam = (e) => { - e.preventDefault(); - this.context.executeAction(createOrgTeamAction, - { - jwt: this.props.JWT, - orgName: this.props.params.user, - team: {name: this.state.teamname, description: this.state.teamdesc} }); - } - - _handleReset = (e) => { - e.preventDefault(); - } - - teamNameChange = (e) => { - this.setState({teamname: e.target.value}); - } - - teamDescChange = (e) => { - this.setState({teamdesc: e.target.value}); - } - - render() { - let maybeError; - if (this.props.errorDetails.detail) { - maybeError = {this.props.errorDetails.detail}; - } - return ( -
    -
    - - -
    - - -
    - {maybeError} - -
    - - ); - } -} - -export default connectToStores(OrganizationAddTeam, - [ - OrgTeamStore - ], - function({ getStore }, props) { - return getStore(OrgTeamStore).getState(); - }); diff --git a/app/scripts/components/account/orgs/OrganizationProfile.css b/app/scripts/components/account/orgs/OrganizationProfile.css deleted file mode 100644 index f0e10ae231..0000000000 --- a/app/scripts/components/account/orgs/OrganizationProfile.css +++ /dev/null @@ -1,12 +0,0 @@ -@import "dux/css/colors"; - -.visibility { - color: var(--black); - &, > input { - cursor: pointer; - } -} - -.label { - color: #7a8491; -} diff --git a/app/scripts/components/account/orgs/OrganizationProfile.jsx b/app/scripts/components/account/orgs/OrganizationProfile.jsx deleted file mode 100644 index 6c721405d0..0000000000 --- a/app/scripts/components/account/orgs/OrganizationProfile.jsx +++ /dev/null @@ -1,175 +0,0 @@ -'use strict'; - -import React from 'react'; -import connectToStores from 'fluxible-addons-react/connectToStores'; -import _ from 'lodash'; - -import saveOrgProfileAction from '../../../actions/saveOrgProfile'; -import toggleVisibility from '../../../actions/toggleVisibility.js'; -import OrganizationStore from '../../../stores/OrganizationStore'; -import PrivateRepoUsageStore from '../../../stores/PrivateRepoUsageStore.js'; -import SimpleInput from 'common/SimpleInput.jsx'; -import { SplitSection } from '../../common/Sections.jsx'; -import Route404 from '../../common/RouteNotFound404Page.jsx'; -import Button from '@dux/element-button'; -import styles from './OrganizationProfile.css'; - -var OrganizationProfile = React.createClass({ - contextTypes: { - executeAction: React.PropTypes.func.isRequired - }, - propTypes: { - currentOrg: React.PropTypes.shape({ - orgname: React.PropTypes.string, - full_name: React.PropTypes.string, - location: React.PropTypes.string, - company: React.PropTypes.string, - profile_url: React.PropTypes.string - }), - isOwner: React.PropTypes.bool.isRequired, - JWT: React.PropTypes.string, - error: React.PropTypes.string, - success: React.PropTypes.string, - defaultVisibility: React.PropTypes.oneOf(['public', 'private']) - }, - getInitialState: function() { - return { - orgname: this.props.currentOrg.orgname, - fullName: this.props.currentOrg.full_name, - location: this.props.currentOrg.location, - company: this.props.currentOrg.company, - profileUrl: this.props.currentOrg.profile_url, - gravatarEmail: this.props.currentOrg.gravatar_email, - defaultVisibility: this.props.defaultVisibility - }; - }, - onSubmit: function(e) { - e.preventDefault(); - var updatedOrg = { - full_name: this.state.fullName, - location: this.state.location, - company: this.state.company, - profile_url: this.state.profileUrl, - gravatar_email: this.state.gravatarEmail - }; - this.context.executeAction(saveOrgProfileAction, { - jwt: this.props.JWT, - orgname: this.state.orgname, - organization: updatedOrg - }); - this.context.executeAction(toggleVisibility, { - JWT: this.props.JWT, - username: this.state.orgname, - visibility: this.state.defaultVisibility - }); - }, - orgFullNameChange: function(e) { - this.setState({fullName: e.target.value}); - }, - orgCompanyChange: function(e) { - this.setState({company: e.target.value}); - }, - locationChange: function(e) { - this.setState({location: e.target.value}); - }, - profileUrlChange: function(e) { - this.setState({profileUrl: e.target.value}); - }, - gravatarEmailChange: function(e) { - this.setState({gravatarEmail: e.target.value}); - }, - toggleClick: function({ visibility }) { - return (e) => { - this.setState({defaultVisibility: visibility}); - }; - }, - render: function() { - var maybeError = ; - var maybeSuccess = ; - if (this.props.error) { - maybeError = {this.props.error}; - } else if(this.props.success) { - //TODO: this could be an alert box with a close icon that can be closed when the user wants to dismiss - //Or time out after some time (ideally i would like to see this as a notification and that's it) - maybeSuccess =

    {this.props.success}
    ; - } - if (this.props.isOwner) { - return ( -
    -
    - This information is private to users with access to this organization.

    }> -
    -
    -
    -
    - Default Visibility: -
    -
      -
    • - -
    • -
    • - -
    • -
    -
    - - - - - - - - - - - - - - - - - - {maybeError} - {maybeSuccess} - -
    -
    - ); - } else { - return ( - - ); - } - } -}); - -export default connectToStores(OrganizationProfile, - [ - OrganizationStore, - PrivateRepoUsageStore - ], - function({ getStore }, props) { - return _.merge({}, getStore(OrganizationStore).getState(), {defaultVisibility: getStore(PrivateRepoUsageStore).getState().defaultRepoVisibility}); - }); diff --git a/app/scripts/components/account/orgs/TeamProfile.css b/app/scripts/components/account/orgs/TeamProfile.css deleted file mode 100644 index b7cdc43037..0000000000 --- a/app/scripts/components/account/orgs/TeamProfile.css +++ /dev/null @@ -1,7 +0,0 @@ -@import "dux/css/box.css"; - -.addTeamButtonGroup { - button[type="submit"] { - margin-right: var(--default-margin); - } -} diff --git a/app/scripts/components/account/orgs/TeamProfile.jsx b/app/scripts/components/account/orgs/TeamProfile.jsx deleted file mode 100644 index 5fed357741..0000000000 --- a/app/scripts/components/account/orgs/TeamProfile.jsx +++ /dev/null @@ -1,102 +0,0 @@ -'use strict'; - -import React, {PropTypes, Component} from 'react'; -import saveTeamProfileAction from '../../../actions/saveTeamProfile'; -import deleteTeamProfileAction from '../../../actions/removeTeam'; -import DUXInput from 'common/DUXInput.jsx'; -import styles from './TeamProfile.css'; -import Button from '@dux/element-button'; -import _ from 'lodash'; - -const { string, object, bool, func } = PropTypes; - -export default class TeamProfile extends Component { - - static contextTypes = { - executeAction: func.isRequired - } - - static propTypes = { - JWT: string, - history: object.isRequired, - error: string, - success: string, - orgname: string, - clearError: func, - onDeleteTeam: func, - onUpdateTeam: func, - team: object - } - - state = { - teamName: this.props.team.name, - teamDesc: this.props.team.description - } - - onSubmit = (e) => { - e.preventDefault(); - var updatedTeam = { - name: this.state.teamName, - description: this.state.teamDesc - }; - this.context.executeAction(saveTeamProfileAction, { - jwt: this.props.JWT, - orgname: this.props.orgname, - teamname: this.props.team.name, - team: updatedTeam - }); - } - - onDelete = (e) => { - e.preventDefault(); - this.context.executeAction(deleteTeamProfileAction, { - jwt: this.props.JWT, - orgname: this.props.orgname, - teamname: this.props.team.name - }); - } - - teamNameChange = (e) => { - if (this.state.teamName !== 'owners') { - this.setState({teamName: e.target.value}); - } else { - this.setState({teamName: 'owners'}); - } - } - - teamDescChange = (e) => { - this.setState({teamDesc: e.target.value}); - } - - render() { - var maybeError = ; - var maybeSuccess = ; - if (this.props.error) { - maybeError = {this.props.error}; - } else if(this.props.success) { - //TODO: this could be an alert box with a close icon that can be closed when the user wants to dismiss - //Or time out after some time (ideally i would like to see this as a notification and that's it) - maybeSuccess =

    {this.props.success}
    ; - } - var maybeDeleteBtn; - if (this.state.teamName !== 'owners' && this.props.team.name === this.state.teamName) { - maybeDeleteBtn = (); - } - return ( -
    - - -
    - - {maybeDeleteBtn} -
    - {maybeError} - {maybeSuccess} - - ); - } -} diff --git a/app/scripts/components/account/services/GithubLinkScopes.jsx b/app/scripts/components/account/services/GithubLinkScopes.jsx deleted file mode 100644 index b4b56f52b0..0000000000 --- a/app/scripts/components/account/services/GithubLinkScopes.jsx +++ /dev/null @@ -1,86 +0,0 @@ -'use strict'; - -import React from 'react'; -import GithubLinkStore from '../../../stores/GithubLinkStore'; -import connectToStores from 'fluxible-addons-react/connectToStores'; -const debug = require('debug')('COMPONENT:GithubLinkScopes'); -import githubOathAction from '../../../actions/githubOauth'; - -import { SplitSection } from '../../common/Sections'; -import { Button } from 'dux'; - -var GithubLinkScopes = React.createClass({ - displayName: 'GithubLinkScopes', - contextTypes: { - executeAction: React.PropTypes.func.isRequired - }, - _generateGHStateString: function() { - //Generate random string - return Math.random().toString(36).substring(8); - }, - _limitedScope: function(evt) { - evt.preventDefault(); - var ss = this._generateGHStateString(); - window.open( - 'https://github.com/login/oauth/authorize?client_id=' + - this.props.githubClientID + - '&state=' + - ss, '_blank'); - this.context.executeAction(githubOathAction, {stateString: ss}); - }, - _recommendedScope: function(evt) { - evt.preventDefault(); - var ss = this._generateGHStateString(); - window.open( - 'https://github.com/login/oauth/authorize?client_id=' + - this.props.githubClientID + - '&scope=repo' + - '&state=' + - ss, '_blank'); - this.context.executeAction(githubOathAction, {stateString: ss}); - }, - render: function() { - return ( -
    -
    - -
    -
    -
    Public and Private (Recommended)
    -
      -
    • Read and Write access to public and private repositories. - (We only use write access to add service hooks and add deploy keys)
    • -
    • Required if you want to setup an Automated Build from a private GitHub repository.
    • -
    • Required if you want to use a private GitHub organization.
    • -
    • We will automatically configure the service hooks and deploy keys for you.
    • -
    -
    -
    - -
    -
    -
    Limited Access
    -
      -
    • Public read only access.
    • -
    • Only works with public repositories and organizations.
    • -
    • You will need to manually make changes to your repositories in order to use Automated Build.
    • -
    -
    -
    - -
    -
    -
    -
    - ); - } -}); - -export default connectToStores(GithubLinkScopes, - [ - GithubLinkStore - ], - function({ getStore }, props) { - return getStore(GithubLinkStore).getState(); - }); diff --git a/app/scripts/components/common/AlertBox.jsx b/app/scripts/components/common/AlertBox.jsx deleted file mode 100644 index 3a5d5f9f82..0000000000 --- a/app/scripts/components/common/AlertBox.jsx +++ /dev/null @@ -1,34 +0,0 @@ -'use strict'; - -import React, { Component, PropTypes } from 'react'; -const { oneOf, func } = PropTypes; -import { intents } from 'dux/dux/utils/props'; -import classnames from 'classnames'; -import _ from 'lodash'; - -export default class AlertBox extends Component { - static propTypes = { - intent: oneOf(intents), - onClick: func - } - - static defaultProps = { - onClick() {} - } - - render() { - const { intent } = this.props; - - const classes = classnames({ - 'alert-box': true, - [intent]: _.includes(intents, intent) - }); - - return ( -
    - {this.props.children} -
    - ); - } -} diff --git a/app/scripts/components/common/BlankSlate.css b/app/scripts/components/common/BlankSlate.css deleted file mode 100644 index 67bb58242c..0000000000 --- a/app/scripts/components/common/BlankSlate.css +++ /dev/null @@ -1,27 +0,0 @@ -@import 'dux/css/colors.css'; -.blankSlates { - background: #fff; - padding: 2.5rem; - h1 { - color: var(--secondary-7); - font-size: 2rem; - font-weight: 300; - } -} - -.link { - background: transparent; - border-radius: 3px; - border: 1px solid var(--silver); - color: var(--secondary-4); - margin: 0 .3rem .3rem 0; - padding: 1.8rem; - i { - font-size: 2.5em; - margin-bottom: 1rem; - } - &:hover { - background: #f4f9fc; - color: var(--secondary-4); - } -} diff --git a/app/scripts/components/common/BlankSlate.jsx b/app/scripts/components/common/BlankSlate.jsx deleted file mode 100644 index 28bf52acf7..0000000000 --- a/app/scripts/components/common/BlankSlate.jsx +++ /dev/null @@ -1,73 +0,0 @@ -'use strict'; - -import styles from './BlankSlate.css'; -import React, { PropTypes, Component } from 'react'; -import { Link } from 'react-router'; -import FA from './FontAwesome'; -import classnames from 'classnames'; - -const { string, object } = PropTypes; - -/* - * Blankslate - * - * Usage: - * - * - * - * - * - */ - -export class BlankSlates extends Component { - - static propTypes = { - title: string - } - - render() { - return ( -
    -
    -
    -

    {this.props.title}

    -

    {this.props.subtext}

    -
    -
    - {this.props.children} -
    -
    -
    - ); - } -} - -export class BlankSlate extends Component { - static defaultProps = { - query: {} - } - - render() { - const linkClasses = classnames({ - 'button': true, - [styles.link]: true - }); - - const { link, query, icon, title } = this.props; - return ( - -
    {title} - - ); - } -} - -BlankSlate.propTypes = { - link: string.isRequired, - icon: string.isRequired, - title: string, - subtext: string, - query: object -}; diff --git a/app/scripts/components/common/CSEngineBox.css b/app/scripts/components/common/CSEngineBox.css deleted file mode 100644 index 2cd6281e00..0000000000 --- a/app/scripts/components/common/CSEngineBox.css +++ /dev/null @@ -1,24 +0,0 @@ -@import "dux/css/colors"; - -.downloadFlexItem { - background: var(--white); - border: 1px solid var(--iron); - display: flex; - flex-flow: row nowrap; - flex-grow: 4; - flex-basis: 0; - padding: 1rem 1rem; - word-break: break-word; -} - -.curlHelp { - font-size: .875rem; - font-weight: 500; - margin-bottom: 1rem; -} - -.curlWrap { - width: 100%; - padding-left: 1rem; -} - diff --git a/app/scripts/components/common/CSEngineBox.jsx b/app/scripts/components/common/CSEngineBox.jsx deleted file mode 100644 index 8cfb33ea39..0000000000 --- a/app/scripts/components/common/CSEngineBox.jsx +++ /dev/null @@ -1,47 +0,0 @@ -'use strict'; - -import React, { PropTypes, Component } from 'react'; -import CopyCodeBox from 'common/CopyCodeBox'; -import { DEB, RPM } from 'common/data/csEngineInstructions'; -import styles from './CSEngineBox.css'; - -export default class CSEngineBox extends Component { - render() { - return ( -
    -
    -

    Install CS Engine

    -
    -
    - * Copy and run either the RPM or the DEB specific instructions in your terminal. -
    -
    -
    -
    - RPM - -
    -
    -
    -
    - DEB - - - - For more details about this installation,  - - view our documentation - - -
    -
    -
    -
    - ); - } -} diff --git a/app/scripts/components/common/Code.css b/app/scripts/components/common/Code.css deleted file mode 100644 index 0a5a8f177d..0000000000 --- a/app/scripts/components/common/Code.css +++ /dev/null @@ -1,83 +0,0 @@ -.code { - font-family: Consolas, Liberation Mono, Courier, monospace; - /** - * We scope everything rendered in markdown by the above computed - * class. Using :global ensures that we don't have to modify the parser - * to add classes (which would be a turrible idea) in that it styles - * everything *inside of* .code. - */ - :global { - - /** - * Syntax Highlighting - * - * Five-color theme from a single blue hue. - */ - .hljs, pre code[class*="lang-"] { - display: block; - overflow-x: auto; - padding: 0.5em; - background: #eaeef3; - -webkit-text-size-adjust: none; - white-space: pre; - } - - .hljs, - .hljs-list .hljs-built_in { - color: #00193a; - } - - .hljs-keyword, - .hljs-title, - .hljs-important, - .hljs-request, - .hljs-header, - .hljs-doctag { - font-weight: bold; - } - - .hljs-comment, - .hljs-chunk { - color: #738191; - } - - .hljs-string, - .hljs-title, - .hljs-parent, - .hljs-built_in, - .hljs-literal, - .hljs-filename, - .hljs-value, - .hljs-addition, - .hljs-tag, - .hljs-argument, - .hljs-link_label, - .hljs-blockquote, - .hljs-header, - .hljs-name { - color: #0048ab; - } - - .hljs-decorator, - .hljs-prompt, - .hljs-subst, - .hljs-symbol, - .hljs-doctype, - .hljs-regexp, - .hljs-preprocessor, - .hljs-pragma, - .hljs-pi, - .hljs-attribute, - .hljs-attr_selector, - .hljs-xmlDocTag, - .hljs-deletion, - .hljs-shebang, - .hljs-string .hljs-variable, - .hljs-link_url, - .hljs-bullet, - .hljs-sqbracket, - .hljs-phony { - color: #4c81c9; - } - } -} \ No newline at end of file diff --git a/app/scripts/components/common/Code.jsx b/app/scripts/components/common/Code.jsx deleted file mode 100644 index 99ab0adedc..0000000000 --- a/app/scripts/components/common/Code.jsx +++ /dev/null @@ -1,30 +0,0 @@ -'use strict'; - -import React, { PropTypes, Component } from 'react'; -import hljs from 'highlight.js'; -const debug = require('debug')('Code'); -import styles from './Code.css'; - -function renderCode(str) { - const { value } = hljs.highlightAuto(str); - return value; -} - -export default class Code extends Component { - render() { - if(!this.props.children) { - return null; - } - - const html = { - __html: renderCode(this.props.children) - }; - - return ( -
    -
    -
    - ); - } -} diff --git a/app/scripts/components/common/CopyCodeBox.css b/app/scripts/components/common/CopyCodeBox.css deleted file mode 100644 index 377eb21c63..0000000000 --- a/app/scripts/components/common/CopyCodeBox.css +++ /dev/null @@ -1,37 +0,0 @@ -@import "dux/css/box"; -@import "dux/css/colors"; - -.copyBox { - display: flex; - flex-flow: row; - flex-basis: 95%; - margin-right: 1rem; - margin-bottom: 1rem; - overflow-x: auto; - border: 1px solid var(--iron); - border-radius: var(--global-radius); - padding: 0.5rem; -} - -.code { - font-family: monospace; - font-size: .8125em; -} -.contentBox { - composes: code; - white-space: pre; -} - -.dollarBox { - composes: code; - font-weight: 600; - white-space: pre; - user-select: none; -} - -.wrapper { - display: flex; - flex-flow: row nowrap; - align-items: flex-start; - width: 100%; -} \ No newline at end of file diff --git a/app/scripts/components/common/CopyCodeBox.jsx b/app/scripts/components/common/CopyCodeBox.jsx deleted file mode 100644 index f1e7dfa9de..0000000000 --- a/app/scripts/components/common/CopyCodeBox.jsx +++ /dev/null @@ -1,75 +0,0 @@ -'use strict'; - -import React, { PropTypes, Component } from 'react'; -import { findDOMNode } from 'react-dom'; -import styles from './CopyCodeBox.css'; -import Button from '@dux/element-button'; -const debug = require('debug')('CopyCodeBox'); -import repeat from 'lodash/string/repeat'; -const { bool, number, string } = PropTypes; - -export default class CopyCodeBox extends Component { - static propTypes = { - content: string.isRequired, - dollar: bool, - lines: number - } - - static defaultProps = { - dollar: false, - lines: 1 - } - - selectContents = (e) => { - const content = findDOMNode(this.refs.content); - let range; - if ( document.selection ) { - range = document.body.createTextRange(); - range.moveToElementText(content); - range.select(); - } else if ( window.getSelection ) { - range = document.createRange(); - range.selectNodeContents(content); - window.getSelection().removeAllRanges(); - window.getSelection().addRange(range); - } - } - - copyContentsToClipboard = (e) => { - /* Works in Chrome and Firefox 41.x - * TODO: Does not work in Safari - */ - this.selectContents(e); - try { - const success = document.execCommand('copy'); - debug(`Copy worked: ${success}`); - } catch (err) { - debug('Cannot copy.'); - } - } - render() { - const { content, dollar, lines } = this.props; - let dollarDiv; - const button = ( - - ); - if (dollar) { - const inner = repeat('$ \n', lines); - dollarDiv = ( -
    {inner}
    - ); - } - return ( -
    -
    - {dollarDiv} -
    {content}
    -
    - {button} -
    - ); - } -} diff --git a/app/scripts/components/common/DUXInput-b.css b/app/scripts/components/common/DUXInput-b.css deleted file mode 100644 index c5e308bfe3..0000000000 --- a/app/scripts/components/common/DUXInput-b.css +++ /dev/null @@ -1,9 +0,0 @@ -@import "dux/css/colors"; - -:root { - --input-text-color: var(--white); - --label-color: var(--secondary-5); - --highlight-color: var(--primary-color); -} - -@import "./DUXInput-base.css"; \ No newline at end of file diff --git a/app/scripts/components/common/DUXInput-base.css b/app/scripts/components/common/DUXInput-base.css deleted file mode 100644 index d43814cea0..0000000000 --- a/app/scripts/components/common/DUXInput-base.css +++ /dev/null @@ -1,101 +0,0 @@ -/* - * API: - * --label-color - * --input-text-color - * --alert-color - * --highlight-color - */ - -input.duxInput { - padding: 10px 10px 10px 5px; - border: none; - border-bottom: 1px solid gray; - margin: 0; - color: var(--input-text-color); -} -.duxInput:focus { - outline: none; -} - -.group { - position: relative; - margin-bottom: 35px; -} - -.hasError { - border-bottom-color: var(--alert-color); -} - -.hasError .label { - color: var(--alert-color); -} - -.hasError .bar:before, .hasError .bar:after { - background: var(--alert-color); -} - -.label { - color: var(--label-color); - font-weight: normal; - position: absolute; - pointer-events: none; - top: -20px; - transition: 0.2s ease all; -} - -/* BOTTOM BARS ================================= */ -.bar { - position:relative; - display:block; - -} -.bar:before, .bar:after { - content: ''; - height: 2px; - width: 0; - bottom: 0; - position: absolute; - background: var(--highlight-color); - transition: 0.2s ease all; - } -.bar:before { - left: 50%; -} -.bar:after { - right: 50%; -} - -/* HIGHLIGHTER ================================== */ -.highlight { - position: absolute; - height: 60%; - width: 100px; - top: 25%; - left: 0; - pointer-events: none; - transition: 0.2s ease all; - opacity: 0.5; -} - -.duxInput:focus ~ .bar:before { - width: 50%; -} -.duxInput:focus ~ .bar:after { - width: 50%; -} - -.duxInput:focus ~ .highlight { - -webkit-animation: inputHighlighter 0.3s ease; -} - -/* ANIMATIONS ================ */ -@-webkit-keyframes inputHighlighter { - from { - background: var(--highlight-color); - } - to { - width:0; - background:transparent; - } -} - diff --git a/app/scripts/components/common/DUXInput.css b/app/scripts/components/common/DUXInput.css deleted file mode 100644 index fe01e15184..0000000000 --- a/app/scripts/components/common/DUXInput.css +++ /dev/null @@ -1,9 +0,0 @@ -@import "dux/css/colors"; - -:root { - --input-text-color: var(--black); - --label-color: var(--secondary-3); - --highlight-color: var(--primary-color); -} - -@import "./DUXInput-base.css" diff --git a/app/scripts/components/common/DUXInput.jsx b/app/scripts/components/common/DUXInput.jsx deleted file mode 100644 index 722f984db7..0000000000 --- a/app/scripts/components/common/DUXInput.jsx +++ /dev/null @@ -1,130 +0,0 @@ -'use strict'; - -import variantA from './DUXInput.css'; -import variantB from './DUXInput-b.css'; - -import React, { - Component, - PropTypes -} from 'react'; -import { findDOMNode } from 'react-dom'; -const { any, func, string, bool, oneOf } = PropTypes; -import classnames from 'classnames'; -import _ from 'lodash'; -import AlertBox from 'common/AlertBox'; -const debug = require('debug')('DUXInput'); - -export default class DUXInput extends Component { - - static propTypes = { - className: string, - error: string, - hasError: bool.isRequired, - name: string, - onChange: func.isRequired, - success: string, - type: oneOf('hidden text password email search'.split(' ')), - value: string, - variant: string - } - - static defaultProps = { - onChange() { - debug('No onChange function set for Input'); - }, - value: '', - hasError: false, - error: '', - type: 'text', - success: '', - name: '' - } - - focusInput = () => { - findDOMNode(this.refs.input).focus(); - } - - state = { - value: '' - } - - _onChange = (e) => { - // Set local state - const { value } = e.target; - this.setState({ value }); - - // Pass control to onChange controller. Usually a form. - this.props.onChange(e); - } - - componentWillReceiveProps(props) { - /** - * State should be tracked globally in a parent component. As - * such, we need to check the passed in prop against the current - * (local) state value to avoid overwriting the input value. - * - * This prevents a bug which resulted in the cursor being "jumped" - * to the end of an input after every character. - */ - if (props.value !== this.state.value) { - this.setState({ - value: props.value - }); - } - } - - render() { - /** - * Theme variant is accepted through the props. - */ - const { variant, name } = this.props; - const styles = variant !== 'b' ? variantA : variantB; - - /** - * If there is an error, display it - */ - let maybeError = ; - if(this.props.hasError && this.props.error) { - maybeError = {this.props.error}; - } - - /** - * If there is a success message, display it - */ - let maybeSuccess = ; - if(this.props.success) { - /** - * TODO: This shouldn't be a property of the input in the way - * that it currently exists. A field-level success state should - * be very minimal. - * - * OLD_TODO: this could be an alert box with a close icon that can be - * closed when the user wants to dismiss or time out after some - * time (ideally i would like to see this as a notification and - * that's it) - */ - maybeSuccess = {this.props.success}; - } - - const groupClasses = classnames({ - [styles.group]: true, - [styles.hasError]: this.props.hasError - }); - - return ( -
    - - - - {maybeError} - {maybeSuccess} -
    - ); - } -} diff --git a/app/scripts/components/common/FancyInput.css b/app/scripts/components/common/FancyInput.css deleted file mode 100644 index 44264aa907..0000000000 --- a/app/scripts/components/common/FancyInput.css +++ /dev/null @@ -1,76 +0,0 @@ -@import "dux/css/colors.css"; -@import "dux/css/box.css"; - -.inputDiv { - width: 100%; - margin-bottom: 2rem; - > input.default { - padding: 10px 10px 10px 5px; - border: none; - border-bottom: 1px solid #cbcbcb; - margin: 0; - color: #465f77; - &:focus { - outline: none; - } - &:focus::placeholder { - transition: opacity .5s ease; - opacity: .5; - } - } - &.hasError > input { - border-bottom: 1px solid var(--alert-color); - } -} - -.white { - > input.default { - color: var(--white); - border-bottom: 1px solid #465f77; - &::placeholder { - color: #7891b0; - } - } -} - -.hasError { - border-bottom-color: var(--alert-color); - border-radius: var(--global-radius); -} - -.hasError .bar:before, .hasError .bar:after { - background: var(--alert-color); -} - -.bar { - position:relative; - display:block; -} -.bar:before, .bar:after { - content: ''; - height: 2px; - width: 0; - bottom: 0; - position: absolute; - background: var(--primary-color); - transition: 0.2s ease all; - } -.bar:before { - left: 50%; -} -.bar:after { - right: 50%; -} -.default:focus ~ .bar:before { - width: 50%; -} -.default:focus ~ .bar:after { - width: 50%; -} - -.error { - position: absolute; - color: var(--alert-color); - font-weight: 200; - margin: 0 .5rem; -} diff --git a/app/scripts/components/common/FancyInput.jsx b/app/scripts/components/common/FancyInput.jsx deleted file mode 100644 index dd851a808f..0000000000 --- a/app/scripts/components/common/FancyInput.jsx +++ /dev/null @@ -1,99 +0,0 @@ -'use strict'; - -import React, { - Component, - PropTypes -} from 'react'; -import { findDOMNode } from 'react-dom'; -import classnames from 'classnames'; -import styles from './FancyInput.css'; -const { any, func, string, bool, oneOf } = PropTypes; -const debug = require('debug')('SimpleInput'); - -export default class FancyInput extends Component { - static propTypes = { - autoFocus: bool, - hasError: bool, - error: string, - name: string, - onChange: func.isRequired, - placeholder: string, - readOnly: bool, - type: oneOf('hidden text password email search'.split(' ')), - value: any.isRequired, - variant: oneOf(['white']) - } - - static defaultProps = { - hasError: false, - error: '', - onChange() { - debug('No onChange function set for Input'); - }, - value: '', - placeholder: '', - type: 'text', - name: '' - } - - state = { - value: '' - } - - _onChange = (e) => { - // Set local state - const { value } = e.target; - this.setState({ value }); - - // Pass control to onChange controller. Usually a form. - this.props.onChange(e); - } - - componentWillReceiveProps(props) { - /** - * State should be tracked globally in a parent component. As - * such, we need to check the passed in prop against the current - * (local) state value to avoid overwriting the input value. - * - * This prevents a bug which resulted in the cursor being "jumped" - * to the end of an input after every character. - */ - if (props.value !== this.state.value) { - this.setState({ - value: props.value - }); - } - } - - render() { - const { hasError, - error, - name, - placeholder, - readOnly, - type, - value, - variant, - autofocus } = this.props; - const groupClass = classnames({ - [styles.inputDiv]: true, - [styles.white]: variant === 'white', - [styles.hasError]: hasError - }); - - return ( -
    - - -
    {error}
    -
    - ); - } -} diff --git a/app/scripts/components/common/FlexTable.css b/app/scripts/components/common/FlexTable.css deleted file mode 100644 index c05d32354c..0000000000 --- a/app/scripts/components/common/FlexTable.css +++ /dev/null @@ -1,92 +0,0 @@ -@import 'dux/css/colors.css'; -@import 'dux/css/box.css'; - -.defaultBorder { - border: 1px solid var(--secondary-5); -} - -.inACardBorder { - border-bottom: 1px solid var(--secondary-5); -} - -.flexTable { - border-radius: 3px; - color: var(--secondary-2); - display: flex; - flex-flow: column; - justify-content: center; - font-size: 1rem; - font-weight: 400; - line-height: 1.5; - margin-bottom: 1.25rem; -} - -.flexHeader { - background: #f1f6fb; - border-bottom: 1px solid var(--secondary-5); - border-top-left-radius: var(--global-radius); - border-top-right-radius: var(--global-radius); - display: flex; - font-weight: 400; - font-size: 1rem; - padding: 0.3rem; - width: 100%; -} - -.flexRow { - background: var(--white); - border-bottom: 1px solid #e5e5e5; - display: flex; - padding: 0.3rem; - width: 100%; -} - -.flexRow:nth-child(2n+1) { - background: #f9f9f9; -} - -.flexRow:last-child { - border-bottom: 0; - border-bottom-right-radius: var(--global-radius); - border-bottom-left-radius: var(--global-radius); -} - -.selectableFlexRow { - composes: flexRow; - &:hover { - background: var(--silver); - cursor: pointer; - } -} - -.flexItem { - display: flex; - flex-flow: row nowrap; - flex-basis: 0; - padding-left: 1rem; - padding-right: 1rem; - word-break: break-word; -} - -.flexItemPadding { - padding-top: .75rem; - padding-bottom: .75rem; -} - -.flexEnd { - justify-content: flex-end; -} - -@each $num in 1, 2, 3, 4, 5, 6 { - .flexItemGrow$(num) { - flex-grow: $num; - } -} - -.error { - border: 1px solid var(--primary-5); -} - -.success { - border: 1px solid var(--primary-2); -} diff --git a/app/scripts/components/common/FlexTable.jsx b/app/scripts/components/common/FlexTable.jsx deleted file mode 100644 index 0e9b2bfb5b..0000000000 --- a/app/scripts/components/common/FlexTable.jsx +++ /dev/null @@ -1,113 +0,0 @@ -'use strict'; - -import React, { Component, PropTypes } from 'react'; -const { number, bool, func, string } = PropTypes; -import includes from 'lodash/collection/includes'; -import styles from './FlexTable.css'; -import classnames from 'classnames'; - -export class FlexTable extends Component { - static propTypes = { - success: bool, - error: bool, - isWrappedInACard: bool - }; - - static defaultProps = { - isWrappedInACard: false - }; - - render() { - const { error, isWrappedInACard, success } = this.props; - const tableClass = classnames({ - [styles.flexTable]: true, - [styles.defaultBorder]: !isWrappedInACard, - [styles.inACardBorder]: isWrappedInACard, - [styles.success]: success, - [styles.error]: error - }); - - return ( -
    - {this.props.children} -
    - ); - } -} - -export class FlexRow extends Component { - static propTypes = { - onMouseOver: func, - onMouseLeave: func, - onClick: func, - selectable: bool, - className: string - } - - render() { - const { - onClick, - onMouseOver, - onMouseLeave, - selectable - } = this.props; - - let className = (selectable) ? styles.selectableFlexRow : styles.flexRow; - if (this.props.className) { - className += ` ${this.props.className}`; - } - - return ( -
    - {this.props.children} -
    - ); - } -} - -export class FlexHeader extends Component { - - render() { - return ( -
    - {this.props.children} -
    - ); - } -} - -export class FlexItem extends Component { - - static propTypes = { - grow: number, - end: bool, - noPadding: bool - } - - static defaultProps = { - grow: 1, - noPadding: false - } - - render() { - //Optional itemClass usually used for setting widths - //noPadding removes top and bottom padding - const { grow, end, noPadding } = this.props; - - const itemClass = classnames({ - [styles.flexItem]: true, - [styles.flexEnd]: end, - [styles.flexItemPadding]: !noPadding, - [styles[`flexItemGrow${grow}`]]: includes([1, 2, 3, 4, 5, 6], grow) - }); - - return ( -
    - {this.props.children} -
    - ); - } -} diff --git a/app/scripts/components/common/FontAwesome.jsx b/app/scripts/components/common/FontAwesome.jsx deleted file mode 100644 index 7a09848dd1..0000000000 --- a/app/scripts/components/common/FontAwesome.jsx +++ /dev/null @@ -1,54 +0,0 @@ -'use strict'; - -import React, { Component, PropTypes } from 'react'; -const { oneOf, string, bool } = PropTypes; -import classnames from 'classnames'; -import _ from 'lodash'; -var debug = require('debug')('FontAwesomeIcon'); - -const sizes = ['lg', '2x', '3x', '4x', '5x']; -const animations = ['spin', 'pulse']; -const flips = ['horizontal', 'vertical']; -const rotations = [90, 180, 270]; - -export default class FontAwesome extends Component { - static propTypes = { - icon: string.isRequired, - - animate: oneOf(animations), - fixedWidth: bool, - flip: oneOf(flips), - invert: bool, - rotate: oneOf(rotations), - size: oneOf(sizes), - stack: bool - } - render() { - - const { - animate, - fixedWidth, - flip, - icon, - invert, - rotate, - size, - stack - } = this.props; - - const classes = classnames({ - 'fa': true, - 'fa-fw': fixedWidth, - 'fa-inverse': invert, - [icon]: true, - [`fa-${animate}`]: _.includes(animations, animate), - [`fa-${size}`]: _.includes(sizes, size) && !stack, - [`fa-flip-${flip}`]: _.includes(flips, flip), - [`fa-rotate-${rotate}`]: _.includes(rotations, rotate), - [`fa-stack-${size}`]: _.includes(sizes, size) && stack - }); - - return (); - } -} - diff --git a/app/scripts/components/common/LiLink.jsx b/app/scripts/components/common/LiLink.jsx deleted file mode 100644 index e97162573f..0000000000 --- a/app/scripts/components/common/LiLink.jsx +++ /dev/null @@ -1,17 +0,0 @@ -'use strict'; - -import React from 'react'; -const debug = require('debug')('LiLink: '); -import { Link } from 'react-router'; - -export default class LiLink extends Link { - isActive() { - const { to, query, onlyActiveOnIndex } = this.props; - return this.context.history.isActive(to, query, onlyActiveOnIndex); - } -//In order to show active state on nav links, we need the active class on the li element -//Dependant on Foundation .active class - render() { - return
  • {super.render()}
  • ; - } -} diff --git a/app/scripts/components/common/ListSelector.css b/app/scripts/components/common/ListSelector.css deleted file mode 100644 index fb0cfaa9e4..0000000000 --- a/app/scripts/components/common/ListSelector.css +++ /dev/null @@ -1,32 +0,0 @@ -@import "dux/css/colors.css"; -@import "dux/css/box.css"; - -.header { - font-weight: 400; - padding: 0.5rem; - margin: 0; - background-color: var(--silver); - border: 1px solid var(--secondary-5); - border-top-left-radius: var(--global-radius); - border-top-right-radius: var(--global-radius); -} - -.listSelectorItems { - background: #fff; - list-style: none; - padding: 0; - margin: 0; - border: 1px solid var(--secondary-5); - border-bottom-left-radius: var(--global-radius); - border-bottom-right-radius: var(--global-radius); -} - -.listSelectorItems li { - padding: .5rem; - border-bottom: 1px solid var(--secondary-5); -} - -.listSelectorItems li:hover { - background-color: var(--silver); - cursor: pointer; -} \ No newline at end of file diff --git a/app/scripts/components/common/ListSelector.jsx b/app/scripts/components/common/ListSelector.jsx deleted file mode 100644 index b6fc7f132c..0000000000 --- a/app/scripts/components/common/ListSelector.jsx +++ /dev/null @@ -1,33 +0,0 @@ -'use strict'; - -import React, { PropTypes, Component } from 'react'; -import { StrippedModule } from 'dux'; -import styles from './ListSelector.css'; -import _ from 'lodash'; - -const { string, arrayOf, node } = PropTypes; - -export default class ListSelector extends Component { - - static propTypes = { - header: node, - items: arrayOf(node) - } - - render() { - var header = null; - if (_.isString(this.props.header)) { - header = (
    {this.props.header}
    ); - } else if (_.isObject(this.props.header)) { - header =
    {this.props.header}
    ; - } - - return ( - - {header} -
      - {this.props.items} -
    -
    ); - } -} diff --git a/app/scripts/components/common/Pagination.jsx b/app/scripts/components/common/Pagination.jsx deleted file mode 100644 index 213cc40157..0000000000 --- a/app/scripts/components/common/Pagination.jsx +++ /dev/null @@ -1,119 +0,0 @@ -'use strict'; - -import React, { - PropTypes, - createClass -} from 'react'; -import classnames from 'classnames'; -import _ from 'lodash'; -var debug = require('debug')('Pagination'); - -function noop(e) { - e.preventDefault(); -} - -var Page = createClass({ - displayName: 'Page', - propTypes: { - _onClick: PropTypes.func.isRequired, - pageNumber: PropTypes.number.isRequired, - currentPage: PropTypes.number.isRequired - }, - render() { - var classes = classnames({ - 'current': this.props.currentPage === this.props.pageNumber - }); - - return ( -
  • - {this.props.pageNumber} -
  • - ); - } -}); - -function mkPage(pageNumber) { - return ( - - ); -} - -export default createClass({ - displayName: 'Pagination', - propTypes: { - next: PropTypes.string, - prev: PropTypes.string, - currentPage: PropTypes.number.isRequired, - pageSize: PropTypes.number.isRequired, - onChangePage: PropTypes.func.isRequired - }, - _onClick(pageNumber) { - return (e) => { - //Check if currentPage is to the right of ellipsis and the last from the beginning or the end - //based on whether it is the beginning side or end side, update the page ranges - e.preventDefault(); - this.props.onChangePage(pageNumber); - }; - }, - render() { - var paginationComponent; - // is there a page before this one? - var previousPageExists = !!this.props.prev; - // is there a page after this one? - var nextPageExists = !!this.props.next; - var currentPage = [this.props.currentPage].map(mkPage, this); - var prevClasses = classnames({ - 'arrow': true, - 'unavailable': !previousPageExists - }); - - var nextClasses = classnames({ - 'arrow': true, - 'unavailable': !nextPageExists - }); - - var prevPage = null; - if (previousPageExists) { - prevPage = [( -
  • «
  • - ), ( -
  • {this.props.currentPage - 1}
  • - )]; - } - - var nextPage = null; - if (nextPageExists) { - nextPage = [( -
  • {this.props.currentPage + 1}
  • - ), ( -
  • »
  • - )]; - } - - if (nextPageExists || previousPageExists) { - paginationComponent = ( -
      - {prevPage} - {currentPage} - {nextPage} -
    - ); - } - - return ( -
    - {paginationComponent} -
    - ); - } -}); diff --git a/app/scripts/components/common/PendingDeleteRepositoryItem.css b/app/scripts/components/common/PendingDeleteRepositoryItem.css deleted file mode 100644 index ba66ee2e53..0000000000 --- a/app/scripts/components/common/PendingDeleteRepositoryItem.css +++ /dev/null @@ -1,84 +0,0 @@ -@import "dux/css/colors.css"; -@import "dux/css/box.css"; - -.pendingDeleteItem { - background: var(--white); - border: 1px solid var(--secondary-5); - border-radius: var(--global-radius); - color: var(--secondary-2); - display: flex; - flex-flow: row; - margin: 1rem 0; - font-weight: 500; - cursor: not-allowed; - - &:hover { - border-color: var(--primary-5); - .action { - background-color: var(--primary-1); - color: white; - border-color: var(--primary-1); - } - } -} - -.repoName { - color: var(--primary-1); -} -.avatar { - width: 50px; - height: 50px; - border-radius: var(--global-radius); -} -.officialAvatar { - background: var(--primary-color); -} - -/* sections */ -.section { - display: flex; - border-left: 1px solid var(--secondary-5); - padding: 1rem; -} -.head { - composes: section; - flex-grow: 1; - flex-flow: row; - &:first-child { - border-left: 0; - } -} - -.action { - composes: section; - background-color: var(--secondary-5); - color: var(--secondary-4); - flex-flow: column; - i { - position: relative; - top: 0.5rem; - left: 1.2rem; - } -} -.text { - margin-top: 1.2rem; - margin-left: 0.4rem; - font-size: 0.7rem; -} - -/* "Visibility" Classes */ -.title { - padding-left: 1rem; - padding-right: 1rem; -} -.labels { - color: var(--secondary-4); -} -.pendingDelete { - color: var(--primary-5); -} -/* utility */ -.flexible { - display: flex; - flex: 1; -} diff --git a/app/scripts/components/common/PendingDeleteRepositoryItem.jsx b/app/scripts/components/common/PendingDeleteRepositoryItem.jsx deleted file mode 100644 index 228864aa0d..0000000000 --- a/app/scripts/components/common/PendingDeleteRepositoryItem.jsx +++ /dev/null @@ -1,58 +0,0 @@ -'use strict'; - -import styles from './PendingDeleteRepositoryItem.css'; -import React, { PropTypes, Component } from 'react'; -let { func, string } = PropTypes; -import classnames from 'classnames'; -import FA from 'common/FontAwesome'; -import { mkAvatarForNamespace, isOfficialAvatarURL } from 'utils/avatar'; - -/** - * PendingDeleteRepositoryItem will show only the name and namespace - */ - -export default class PendingDeleteRepositoryItem extends Component { - - static propTypes = { - namespace: string.isRequired, - name: string.isRequired - } - - render() { - - const { - name, - namespace - } = this.props; - - const repoDisplayName = namespace + '/' + name; - const avatar = mkAvatarForNamespace(namespace, name); - const avatarClass = classnames({ - [styles.avatar]: true, - [styles.officialAvatar]: isOfficialAvatarURL(avatar) - }); - - return ( -
  • -
    -
    -
    -
    -
    -
    { repoDisplayName }
    - Deleting... -
    -
    -
    -
    - -
    DETAILS
    -
    -
    -
  • - ); - } -} diff --git a/app/scripts/components/common/RepositoriesList.jsx b/app/scripts/components/common/RepositoriesList.jsx deleted file mode 100644 index a8511c69c4..0000000000 --- a/app/scripts/components/common/RepositoriesList.jsx +++ /dev/null @@ -1,113 +0,0 @@ -'use strict'; - -import React, { PropTypes, createClass } from 'react'; -const { array, bool, element, func, oneOfType } = PropTypes; -import PendingDeleteRepositoryItem from './PendingDeleteRepositoryItem'; -import RepositoryListItem from './RepositoryListItem'; -import { PENDING_DELETE } from 'common/enums/RepoStatus'; -import has from 'lodash/object/has'; - -var debug = require('debug')('RepositoriesList'); - -function mkRepoListItem(repo) { - - const { - is_automated, - is_official, - is_private, - name, - namespace, - pull_count, - repo_name, - star_count, - status - } = repo; - /** - * TODO: after snakecase to camelcase in hub-js-sdk is done remove - * explicit props - */ - if(has(repo, 'is_private')) { - repo.isPrivate = is_private; - } - if(has(repo, 'is_official')) { - repo.isOfficial = is_official; - } - if(has(repo, 'is_offical')) { - // This is a legit typo in the ES results - repo.isOfficial = repo.is_offical; - } - if(has(repo, 'repo_name')) { - repo.repoName = repo_name; - } - - let key = repo_name || (namespace + '/' + name); - - if (status === PENDING_DELETE) { - return ( - - ); - } else { - return ( - - ); - } -} - -var BlankSlate = createClass({ - displayName: 'BlankSlate', - render() { - return ( -
    -
    -
    -

    No Repositories Yet.

    - Create Repository -
    -
    -
    - ); - } -}); - -export default createClass({ - displayName: 'RepositoriesList', - propTypes: { - blankSlate: element, - repos: array.isRequired - }, - getDefaultProps() { - return { - blankSlate: (), - repos: [] - }; - }, - render() { - const { - blankSlate, - repos - } = this.props; - - let content = blankSlate; - - if(repos && repos.length > 0) { - content = ( -
    -
      - {repos.map(mkRepoListItem, this)} -
    -
    - ); - } - - return ( -
    - {content} -
    - ); - } -}); diff --git a/app/scripts/components/common/RepositoryListItem.css b/app/scripts/components/common/RepositoryListItem.css deleted file mode 100644 index c1ee0eeca1..0000000000 --- a/app/scripts/components/common/RepositoryListItem.css +++ /dev/null @@ -1,111 +0,0 @@ -@import "dux/css/colors.css"; -@import "dux/css/box.css"; - -.repositoryListItem { - background: var(--white); - border: 1px solid var(--secondary-5); - border-radius: var(--global-radius); - color: var(--secondary-2); - display: flex; - flex-flow: row; - margin: 1rem 0; - font-weight: 500; - - &:hover { - border-color: var(--primary-1); - .action { - background-color: var(--primary-1); - color: white; - border-color: var(--primary-1); - } - } -} -.repoName { - color: var(--primary-color); -} -.avatar { - width: 60px; - height: 60px; - border-radius: var(--global-radius); - display: flex; -} -.img { - align-self: center; -} -.officialAvatar { - background: var(--primary-color); -} - -/* sections */ -.section { - display: flex; - border-left: 1px solid var(--secondary-5); - padding: 1rem; -} -.head { - composes: section; - flex-grow: 1; - flex-flow: row; - &:first-child { - border-left: 0; - } -} -.stats { - composes: section; - min-width: 100px; - text-align: center; - flex-flow: row; -} -.action { - composes: section; - background-color: var(--secondary-5); - color: var(--secondary-4); - flex-flow: column; - i { - position: relative; - top: 0.5rem; - left: 1.2rem; - } -} -.text { - margin-top: 1.2rem; - margin-left: 0.4rem; - font-size: 0.7rem; -} -/* Stats Boxes */ -.labelValue { - padding-top: 0.25rem; - margin: 0 auto; -} -.value { - margin-bottom: 0.25rem; - color: var(--secondary-4); -} -.subLabel { - color: var(--secondary-4); -} -/* "Visibility" Classes */ -.title { - padding-left: 1rem; - padding-right: 1rem; -} -.labels { - color: var(--secondary-4); -} -/*.official { - color: var(--primary-1); -}*/ -.public { - color: color(var(--primary-1) blackness(50%)); -} -.private { - color: var(--secondary-4); -} -.automated { - color: var(--secondary-4); -} -/* utility */ -.flexible { - display: flex; - flex: 1; -} diff --git a/app/scripts/components/common/RepositoryListItem.jsx b/app/scripts/components/common/RepositoryListItem.jsx deleted file mode 100644 index fbedea3372..0000000000 --- a/app/scripts/components/common/RepositoryListItem.jsx +++ /dev/null @@ -1,326 +0,0 @@ -'use strict'; - -import styles from './RepositoryListItem.css'; -import React, { PropTypes, createClass, Component } from 'react'; -let { string, number } = PropTypes; -import { Link } from 'react-router'; -import classnames from 'classnames'; -import FA from 'common/FontAwesome'; -import numeral from 'numeral'; -import { mkAvatarForNamespace, isOfficialAvatarURL } from 'utils/avatar'; -import isFinite from 'lodash/lang/isFinite'; - -var debug = require('debug')('RepositoryListItem'); - -/* TODO: Should dedupe these render methods */ - -/** - * RepositoryListItem has to handle two versions of a Repository data - * structure. One comes from ElasticSearch, and one comes from Postgres - * - * ElasticSearch: - * - * -- Official - * { - * "repo_name": "ubuntu", - * "is_offical": true, - * "is_automated": false, - * "short_description": "", - * "repo_owner": null, - * "pull_count": 9, - * "star_count": 2 - * } - * - * -- Normal - * { - * "repo_name": "cpuguy83/ubuntu", - * "is_offical": false, - * "is_automated": false, - * "short_description": "ubuntu but more awesome", - * "repo_owner": null, - * "pull_count": 2, - * "star_count": 0 - * } - * - * Postgres: - * - * --Official - * --Normal - * { - * "last_updated": null, - * "pull_count": 9, - * "star_count": 2, - * "can_edit": true, - * "is_automated": false, - * "is_private": false, - * "full_description": null, - * "description": "", - * "status": 1, - * "namespace": "library", - * "name": "ubuntu", - * "user": "jlhawn" - * } - */ - -class Stats extends Component { - static propTypes: { - title: string, - value: number, - inBuckets: bool - } - - formatNumber(n) { - if (n < 1000) { - return numeral(n).format('0a'); - } - return numeral(n).format('0.0a').toUpperCase(); - } - - /** - * Buckets to format the number: - * 10M + - * 5M + - * 1M + - * 500k + - * 100k + - * 50k + - * 10k + - */ - formatBucketedNumber(n) { - if (n < 10000) { - return this.formatNumber(n); - } else if(n < 50000) { - return '10K+'; - } else if(n < 100000) { - return '50K+'; - } else if(n < 500000) { - return '100K+'; - } else if(n < 1000000) { - return '500K+'; - } else if(n < 5000000) { - return '1M+'; - } else if(n < 10000000) { - return '5M+'; - } else { - return '10M+'; - } - } - - render() { - const { value, title, inBuckets } = this.props; - - let statValue; - - if (isFinite(value)) { - if (inBuckets) { - statValue = this.formatBucketedNumber(value); - } else { - statValue = this.formatNumber(value); - } - } else { - return null; - } - - return ( -
    -
    -
    {statValue}
    -
    {title.toUpperCase()}
    -
    -
    - ); - } -} - -var PostgresRepo = createClass({ - displayName: 'PostgresRepo', - propTypes: { - namespace: PropTypes.string.isRequired, - name: PropTypes.string.isRequired, - status: PropTypes.number, - description: PropTypes.string, - fullDescription: PropTypes.string, - isPrivate: PropTypes.bool, - isAutomated: PropTypes.bool, - isOfficial: PropTypes.bool, - starCount: PropTypes.number, - pullCount: PropTypes.number - }, - render() { - /** - * Since Official Repos don't show their namespace (library), - * we use this to chop that part off if we need to by redefining - * this variable. - */ - var repoDisplayName = this.props.namespace + '/' + this.props.name; - var linkTo = `/r/${repoDisplayName}/`; - - /** - * visibility can be 'official', 'public' or 'private', with an - * appropriate class to match. - */ - var visibility = null; - var visibilityClasses = {}; - /** - * autobuild is set if this repository is an automated build, otherwise - * we rely on `null` to render nothing. - */ - var autobuild = null; - - if(this.props.isOfficial || this.props.namespace === 'library') { - - visibility = 'official'; - visibilityClasses = classnames({ - [styles.official]: true - }); - repoDisplayName = this.props.name || this.props.repo_name; - linkTo = `/_/${this.props.name}/`; - - } else { - - visibility = 'private'; - if(!this.props.isPrivate) { - visibility = 'public'; - } - visibilityClasses = classnames({ - [styles.public]: !this.props.isPrivate, - [styles.private]: this.props.isPrivate - }); - - if(this.props.isAutomated) { - autobuild = | automated build; - } - } - - const avatar = mkAvatarForNamespace(this.props.namespace, this.props.name); - const avatarClass = classnames({ - [styles.avatar]: true, - [styles.officialAvatar]: isOfficialAvatarURL(avatar) - }); - - return ( -
  • - -
    -
    -
    -
    -
    {repoDisplayName}
    - {visibility} - {autobuild}
    -
    -
    - - -
    - -
    DETAILS
    -
    - -
  • - ); - } -}); - - -var ElasticRepo = createClass({ - displayName: 'ElasticRepo', - propTypes: { - repoName: PropTypes.string.isRequired, - isOfficial: PropTypes.bool.isRequired, - isAutomated: PropTypes.bool.isRequired, - pullCount: PropTypes.number.isRequired, - starCount: PropTypes.number.isRequired - }, - render() { - var repoDisplayName = this.props.repoName; - var linkTo; - - /** - * visibility can be 'official', 'public' or 'private', with an - * appropriate class to match. - */ - var visibility = null; - var visibilityClasses = {}; - /** - * autobuild is set if this repository is an automated build, otherwise - * we rely on `null` to render nothing. - */ - var autobuild = null; - - if(this.props.isOfficial) { - - visibility = 'official'; - visibilityClasses = classnames({ - [styles.official]: true - }); - linkTo = `/_/${this.props.repoName}/`; - - } else { - - let [namespace, splat] = this.props.repoName.split('/'); - linkTo = `/r/${namespace}/${splat}/`; - - if(this.props.isPrivate) { - visibility = 'private'; - } else { - visibility = 'public'; - } - visibilityClasses = classnames({ - [styles.public]: !this.props.isPrivate, - [styles.private]: this.props.isPrivate - }); - - if(this.props.isAutomated) { - autobuild = | automated build; - } - } - - const avatar = mkAvatarForNamespace(this.props.namespace, this.props.repoName); - const avatarClass = classnames({ - [styles.avatar]: true, - [styles.officialAvatar]: isOfficialAvatarURL(avatar) - }); - - return ( -
  • - -
    -
    -
    -
    {repoDisplayName}
    -
    - {visibility} - {autobuild}
    -
    -
    - - -
    - -
    DETAILS
    -
    - -
  • - ); - } -}); - -export default class RepositoryListItem extends Component { - render() { - debug(this.props); - if(this.props.repoName) { - // Render a repo from ElasticSearch - return ( - - ); - } else { - // Render a repo from Postgres - return ( - - ); - } - } -} diff --git a/app/scripts/components/common/RepositoryNameInput.jsx b/app/scripts/components/common/RepositoryNameInput.jsx deleted file mode 100644 index 4a53602878..0000000000 --- a/app/scripts/components/common/RepositoryNameInput.jsx +++ /dev/null @@ -1,42 +0,0 @@ -'use strict'; - -import React, { Component, PropTypes } from 'react'; -import SimpleInput from './SimpleInput'; -const {array, func, string} = PropTypes; - -export default class RepositoryNameInput extends Component { - static propTypes = { - namespaces: array.isRequired, - selectedNamespace: string.isRequired, - repoName: string.isRequired, - onRepoNameChange: func.isRequired, - onNamespaceChange: func.isRequired, - inputClass: string - } - - render() { - - var namespaceOptions = this.props.namespaces.map(function(item, idx) { - return (); - }); - - return ( -
    -
    - -
    -
    - -
    -
    - ); - } -} diff --git a/app/scripts/components/common/RouteNotFound404Page.css b/app/scripts/components/common/RouteNotFound404Page.css deleted file mode 100644 index e1f73119e0..0000000000 --- a/app/scripts/components/common/RouteNotFound404Page.css +++ /dev/null @@ -1,40 +0,0 @@ -@import 'dux/css/colors.css'; -.wrap { - background: var(--docker-dark); - height: 100%; - text-align: center; -} - -.messageModule { - animation: fadein 0.3s; - padding: 1.5rem 0 0 0; - margin: 4rem 0; - width: 800px; -} - -@keyframes fadein { - from { - opacity: 0; - } - to { - opacity: 1; - } -} - -.heading { - color: #71859d; - font-size: 6rem; - font-weight: 400; -} - -.subheading { - color: #cbd5df; - font-weight: 400; -} - -.message { - color: #71859d; - margin: 0 auto; - padding: .5rem; - font-size: 1.1rem; -} diff --git a/app/scripts/components/common/RouteNotFound404Page.jsx b/app/scripts/components/common/RouteNotFound404Page.jsx deleted file mode 100644 index 1eb6acedff..0000000000 --- a/app/scripts/components/common/RouteNotFound404Page.jsx +++ /dev/null @@ -1,26 +0,0 @@ -'use strict'; - -import React from 'react'; -import { Module } from 'dux'; -import styles from './RouteNotFound404Page.css'; - -var RouteNotFound404Page = React.createClass({ - displayName: 'RouteNotFound404Page', - render: function() { - return ( -
    -
    -
    -
    -

    404

    -

    Page Not Found

    -

    Sorry, but the page you were trying to view does not exist.

    -
    -
    -
    -
    - ); - } -}); - -module.exports = RouteNotFound404Page; diff --git a/app/scripts/components/common/Row.jsx b/app/scripts/components/common/Row.jsx deleted file mode 100644 index 7d73456638..0000000000 --- a/app/scripts/components/common/Row.jsx +++ /dev/null @@ -1,12 +0,0 @@ -'use strict'; - -import React, { createClass } from 'react'; - -export default createClass({ - displayName: 'Row', - render() { - return ( -
    {this.props.children}
    - ); - } -}); diff --git a/app/scripts/components/common/Sections.css b/app/scripts/components/common/Sections.css deleted file mode 100644 index 7c52eabcbb..0000000000 --- a/app/scripts/components/common/Sections.css +++ /dev/null @@ -1,3 +0,0 @@ -.section { - padding: 1rem 2rem; -} diff --git a/app/scripts/components/common/Sections.jsx b/app/scripts/components/common/Sections.jsx deleted file mode 100644 index 57ed33e7b7..0000000000 --- a/app/scripts/components/common/Sections.jsx +++ /dev/null @@ -1,67 +0,0 @@ -'use strict'; - -import React, { Component, PropTypes } from 'react'; -const { string, node, object, oneOfType, bool } = PropTypes; -import Card, { Block } from '@dux/element-card'; -import styles from './Sections.css'; - -export class SplitSection extends Component { - static propTypes = { - title: string, - subtitle: node, - /** - * module is a props passthrough for precision control over how - * Module displays. An example is setting the `intent` on a module. - */ - module: oneOfType([object, bool]) - }; - static defaultProps = { - module: true - }; - - render() { - var children; - if (this.props.module) { - children = ( - - - {this.props.children} - - - ); - } else { - children = this.props.children; - } - - return ( -
    -
    -
    {this.props.title}
    -
    - {this.props.subtitle} -
    -
    -
    - { children } -
    -
    - ); - } -} - -export class FullSection extends Component { - static propTypes = { - title: string - }; - - render() { - return ( -
    -
    -
    {this.props.title}
    -
    - {this.props.children} -
    - ); - } -} diff --git a/app/scripts/components/common/SimpleInput.css b/app/scripts/components/common/SimpleInput.css deleted file mode 100644 index 562b6227f7..0000000000 --- a/app/scripts/components/common/SimpleInput.css +++ /dev/null @@ -1,23 +0,0 @@ -@import "dux/css/colors.css"; -@import "dux/css/box.css"; - -input.default { - background-color: var(--white); - border-radius: var(--global-radius); -&:focus { - border: 1px solid var(--primary-1); - background-color: var(--white); - } -} - -input.error { - border: 1px solid var(--primary-5); - border-radius: var(--global-radius); -&:focus { - border: 1px solid var(--primary-5); - } -} - -.inputDiv { - width: 100%; -} \ No newline at end of file diff --git a/app/scripts/components/common/SimpleInput.jsx b/app/scripts/components/common/SimpleInput.jsx deleted file mode 100644 index bf8af06b4c..0000000000 --- a/app/scripts/components/common/SimpleInput.jsx +++ /dev/null @@ -1,100 +0,0 @@ -'use strict'; - -import React, { - Component, - PropTypes -} from 'react'; -import { findDOMNode } from 'react-dom'; -import styles from './SimpleInput.css'; -const { any, func, string, bool, oneOf } = PropTypes; -const debug = require('debug')('SimpleInput'); - -/* - * A simpler version of DUXInput without errors / alert boxes - * that is a full field (not a line) - */ -export default class SimpleInput extends Component { - static propTypes = { - autoFocus: bool, - hasError: bool, - name: string, - onChange: func.isRequired, - placeholder: string, - readOnly: bool, - type: oneOf('hidden text password email search'.split(' ')), - value: any.isRequired - } - - static defaultProps = { - hasError: false, - onChange() { - debug('No onChange function set for Input'); - }, - value: '', - placeholder: '', - type: 'text', - name: '' - } - - focusInput = () => { - findDOMNode(this.refs.input).focus(); - } - - state = { - value: '' - } - - _onChange = (e) => { - // Set local state - const { value } = e.target; - this.setState({ value }); - - // Pass control to onChange controller. Usually a form. - this.props.onChange(e); - } - - componentWillReceiveProps(props) { - /** - * State should be tracked globally in a parent component. As - * such, we need to check the passed in prop against the current - * (local) state value to avoid overwriting the input value. - * - * This prevents a bug which resulted in the cursor being "jumped" - * to the end of an input after every character. - */ - if (props.value !== this.state.value) { - this.setState({ - value: props.value - }); - } - } - - componentDidMount() { - const { autoFocus } = this.props; - if (autoFocus) { - this.focusInput(); - } - } - - render() { - const { hasError, - name, - placeholder, - readOnly, - type, - value } = this.props; - const inputClass = hasError ? styles.error : styles.default; - return ( -
    - -
    - ); - } -} diff --git a/app/scripts/components/common/SimpleTextArea.css b/app/scripts/components/common/SimpleTextArea.css deleted file mode 100644 index 280e2ae2d6..0000000000 --- a/app/scripts/components/common/SimpleTextArea.css +++ /dev/null @@ -1,5 +0,0 @@ -@import "dux/css/box.css"; - -.textarea { - border-radius: var(--global-radius); -} \ No newline at end of file diff --git a/app/scripts/components/common/SimpleTextArea.jsx b/app/scripts/components/common/SimpleTextArea.jsx deleted file mode 100644 index d6c76e12c9..0000000000 --- a/app/scripts/components/common/SimpleTextArea.jsx +++ /dev/null @@ -1,89 +0,0 @@ -'use strict'; - -import React, { - Component, - PropTypes -} from 'react'; -import { findDOMNode } from 'react-dom'; -import styles from './SimpleTextArea.css'; -const { any, func, string, number } = PropTypes; -const debug = require('debug')('SimpleTextArea'); - -/* - * A simpler version of DUXInput without errors / alert boxes - * that is a text area - */ -export default class SimpleTextArea extends Component { - static propTypes = { - cols: number, - name: string, - onChange: func.isRequired, - placeholder: string, - rows: number, - value: any.isRequired - } - - static defaultProps = { - onChange() { - debug('No onChange function set for Input'); - }, - cols: 2, - rows: 100, - value: '', - placeholder: '', - name: '' - } - - focusInput = () => { - findDOMNode(this.refs.textarea).focus(); - } - - state = { - value: '' - } - - _onChange = (e) => { - // Set local state - const { value } = e.target; - this.setState({ value }); - - // Pass control to onChange controller. Usually a form. - this.props.onChange(e); - } - - componentWillReceiveProps(props) { - /** - * State should be tracked globally in a parent component. As - * such, we need to check the passed in prop against the current - * (local) state value to avoid overwriting the input value. - * - * This prevents a bug which resulted in the cursor being "jumped" - * to the end of an input after every character. - */ - if (props.value !== this.state.value) { - this.setState({ - value: props.value - }); - } - } - - render() { - const { cols, - rows, - name, - placeholder, - value } = this.props; - return ( -
    - - ); - const submit = this.updateLongDescription; - return ( - - -
    -
    - {input} - {maybeError} -
    -
      -
    • - -
    • -
    • - -
    • -
    -
    -
    -
    -
    -
    - ); - } - - render() { - const { - canEdit, - isEditing, - successfulSave, - fields - } = this.props; - const { longDescription } = this.props.values; - let cardHeading = `Full Description`; - - if (isEditing) { - cardHeading = `Full Description (Optional, Limit 25,000 Characters)`; - return this.renderForm(cardHeading); - } else { - const headingActions = canEdit ? [{ - key: 'edit', - icon: 'fa-edit', - action: this.toggleEditMode - }] : []; - let formattedDescription; - if (!longDescription) { - formattedDescription = ( -
    -

    - Full description is empty for this repo. -

    -
    ); - } else { - formattedDescription = ({longDescription}); - } - const maybeSuccessClass = classnames({ - [styles.successfulSave]: successfulSave - }); - - let maybeSuccess = ; - if (successfulSave) { - maybeSuccess = ( -
    - {fields.longDescription.success} -
    - ); - } - return ( - - -
    - {maybeSuccess} - {formattedDescription} -
    -
    -
    - ); - } - } -} - -export default connectToStores(RepoFullDescription, - [RepoDetailsLongDescriptionFormStore], - function({ getStore }, props) { - return getStore(RepoDetailsLongDescriptionFormStore).getState(); - }); diff --git a/app/scripts/components/repo/repo_details/info/RepoShortDescription.css b/app/scripts/components/repo/repo_details/info/RepoShortDescription.css deleted file mode 100644 index 4f653e3006..0000000000 --- a/app/scripts/components/repo/repo_details/info/RepoShortDescription.css +++ /dev/null @@ -1,32 +0,0 @@ -@import "dux/css/colors.css"; -@import "dux/css/box.css"; - -input.textArea { - background-color: var(--white); - &:focus { - border: 1px solid var(--primary-1); - background-color: var(--white); - } -} -.text { - margin-bottom: var(--default-margin); -} -input.error { - border: 1px solid var(--primary-5); - &:focus { - border: 1px solid var(--primary-5); - } -} -.errorText { - composes: text; - color: var(--primary-5); -} - -.successText { - composes: text; - color: var(--primary-2); -} - -.successfulSave { - border: 1px solid var(--primary-2); -} \ No newline at end of file diff --git a/app/scripts/components/repo/repo_details/info/RepoShortDescription.jsx b/app/scripts/components/repo/repo_details/info/RepoShortDescription.jsx deleted file mode 100644 index a300c5d028..0000000000 --- a/app/scripts/components/repo/repo_details/info/RepoShortDescription.jsx +++ /dev/null @@ -1,179 +0,0 @@ -'use strict'; - -import React, { PropTypes, Component } from 'react'; -import connectToStores from 'fluxible-addons-react/connectToStores'; -import attemptChangeShortDescription from 'actions/attemptChangeShortDescription'; -import RepoDetailsShortDescriptionFormStore from 'stores/RepoDetailsShortDescriptionFormStore'; -import shortDescriptionUpdateFormField from 'actions/shortDescriptionUpdateFormField'; -import toggleShortDescriptionEdit from 'actions/toggleShortDescriptionEdit'; -import Card, { Block } from '@dux/element-card'; -import { Button } from 'dux'; -import classnames from 'classnames'; -import styles from './RepoShortDescription.css'; -import SimpleInput from 'common/SimpleInput'; -const { string, object, bool, number, func, shape } = PropTypes; -const debug = require('debug')('RepoShortDescription'); - - -class RepoShortDescription extends Component { - static propTypes = { - canEdit: bool.isRequired, - name: string.isRequired, - namespace: string.isRequired, - JWT: string, - isEditing: bool.isRequired, - successfulSave: bool, - values: shape({ - shortDescription: string - }) - } - - static contextTypes = { - executeAction: func.isRequired - } - - static defaultProps = { - successfulSave: false, - isEditing: false - } - - toggleEditMode = (e) => { - this.context.executeAction(toggleShortDescriptionEdit, { isEditing: !this.props.isEditing }); - } - - onChange = (fieldKey) => { - return (e) => { - this.context.executeAction(shortDescriptionUpdateFormField, { - fieldKey, - fieldValue: e.target.value - }); - }; - } - - updateShortDescription = (event) => { - event.preventDefault(); - const { JWT, - name, - namespace - } = this.props; - const { shortDescription } = this.props.values; - this.context.executeAction(attemptChangeShortDescription, - { - jwt: JWT, - repoShortName: namespace + '/' + name, - shortDescription: shortDescription - }); - } - renderForm = (cardHeading) => { - let maybeError = ; - const shortDesc = this.props.fields.shortDescription; - const currentShortDesc = this.props.values.shortDescription; - const maxChars = 100; - let hasError = false; - if (shortDesc.hasError) { - /* check for error from request (post submit). success is handled by non-edit card */ - maybeError = (
    {shortDesc.error}
    ); - hasError = true; - } else if (currentShortDesc.length > maxChars) { - /* check for typed input that's too long - not caught until submit otherwise */ - const tooMany = currentShortDesc.length - maxChars; - - const msg = `Maximum ${maxChars} characters. You are over the limit by: ${tooMany}`; - maybeError = (
    {msg}
    ); - hasError = true; - } - const intent = hasError ? 'alert' : 'primary'; - const textAreaClass = classnames({ - [styles.textArea]: true, - [styles.error]: hasError - }); - const input = ( - - ); - const submit = this.updateShortDescription; - return ( - - -
    -
    - {input} - {maybeError} -
    -
      -
    • - -
    • -
    • - -
    • -
    -
    -
    -
    -
    -
    - ); - } - - render() { - const { - canEdit, - isEditing, - successfulSave, - fields - } = this.props; - const { shortDescription } = this.props.values; - let cardHeading = `Short Description`; - - if (isEditing) { - cardHeading = `Short Description (Optional, Limit 100 Characters)`; - return this.renderForm(cardHeading); - } else { - let headingActions = canEdit ? [{ - key: 'edit', - icon: 'fa-edit', - action: this.toggleEditMode - }] : []; - let maybeSuccessClass = classnames({ - [styles.successfulSave]: successfulSave - }); - let maybeSuccess = ; - if (successfulSave) { - maybeSuccess = (
    - {fields.shortDescription.success} -
    ); - } - return ( - - -
    - {maybeSuccess} - {shortDescription || 'Short description is empty for this repo.'} -
    -
    -
    - ); - } - } -} - -export default connectToStores(RepoShortDescription, - [RepoDetailsShortDescriptionFormStore], - function({ getStore }, props) { - return getStore(RepoDetailsShortDescriptionFormStore).getState(); - }); diff --git a/app/scripts/components/repo/repo_details/nautilusUtils.js b/app/scripts/components/repo/repo_details/nautilusUtils.js deleted file mode 100644 index f6a911cda1..0000000000 --- a/app/scripts/components/repo/repo_details/nautilusUtils.js +++ /dev/null @@ -1,63 +0,0 @@ -'use strict'; - -const keyMirror = require('keymirror'); -import forEach from 'lodash/collection/forEach'; -import trim from 'lodash/string/trim'; - -export const mkComponentId = (component) => { - const { component: name, version } = component; - const id = version ? `${name}:${version}` : `${name}:`; - return trim(id); -}; - -export const mapCvss = (cvss) => { - if (cvss <= 0) { - return 'secure'; - } - if (cvss < 4) { - return 'minor'; - } - if (cvss < 7) { - return 'major'; - } - return 'critical'; -}; - -// Get a map of component key to its highest CVSS score -// { bgaes: 4.5, } -export const getHighestComponentCvss = (components, vulnerabilities) => { - let highestComponentCvss = {}; - forEach(components, (c, compName) => { - let cvssMax = 0; - forEach(c.vulnerabilities, v => { - let { cvss } = vulnerabilities[v]; - if (cvss > cvssMax) { - cvssMax = cvss; - } - }); - highestComponentCvss[compName] = cvssMax; - }); - return highestComponentCvss; -}; - -// Given a list of severities returns the highest severity string using mapCvss -// Usage: -// getHighestSeverity([0.5, 2, 4]) -// getHighestSeverity(...cvssList) -export const getHighestSeverity = (...cvss) => { - if (cvss.length === 0) { - return -1; - } - let maxScore = 0; - for (let i in cvss) { - if (cvss[i] > maxScore) { - maxScore = cvss[i]; - } - } - return mapCvss(maxScore); -}; - -export const consts = keyMirror({ - FAILED: null, - IN_PROGRESS: null -}); diff --git a/app/scripts/components/repo/repo_details/scannedTag/ComponentGrid.css b/app/scripts/components/repo/repo_details/scannedTag/ComponentGrid.css deleted file mode 100644 index 14c5447c8b..0000000000 --- a/app/scripts/components/repo/repo_details/scannedTag/ComponentGrid.css +++ /dev/null @@ -1,5 +0,0 @@ -.componentGrid { - display: flex; - flex-flow: row wrap; - align-content: flex-start; -} diff --git a/app/scripts/components/repo/repo_details/scannedTag/ComponentGrid.jsx b/app/scripts/components/repo/repo_details/scannedTag/ComponentGrid.jsx deleted file mode 100644 index 0112e09fe7..0000000000 --- a/app/scripts/components/repo/repo_details/scannedTag/ComponentGrid.jsx +++ /dev/null @@ -1,70 +0,0 @@ -'use strict'; - -import React, { Component, PropTypes } from 'react'; -const { object, array, func, string } = PropTypes; -import { mapCvss, getHighestSeverity } from '../nautilusUtils.js'; -import styles from './ComponentGrid.css'; -import Square from './Square'; -import forEach from 'lodash/collection/forEach'; -import { mkComponentId } from '../nautilusUtils'; - -export default class ComponentGrid extends Component { - static propTypes = { - componentsSortedBySeverity: array.isRequired, - onClick: func, - selectedComponent: string, - vulnerabilities: object - } - - static defaultProps = { - selectedComponent: '' - } - - getNumVulnsBySeverity = (component) => { - const { vulnerabilities: vulns } = this.props; - let numVulns = { - critical: 0, - major: 0, - minor: 0, - secure: 0 - }; - forEach(component.vulnerabilities, (v) => { - numVulns[mapCvss(vulns[v].cvss)]++; - }); - return numVulns; - } - - mkComponentSquare = (component) => { - const { selectedComponent, onClick, vulnerabilities: vulns } = this.props; - const componentFullName = mkComponentId(component); - const isSelected = selectedComponent === componentFullName; - const numVulnsBySeverity = this.getNumVulnsBySeverity(component); - let severity = 'secure'; - if (numVulnsBySeverity.critical) { - severity = 'critical'; - } else if (numVulnsBySeverity.major) { - severity = 'major'; - } else if (numVulnsBySeverity.minor) { - severity = 'minor'; - } - - return ( - - ); - } - - render() { - const { componentsSortedBySeverity } = this.props; - return ( -
    - { componentsSortedBySeverity.map(this.mkComponentSquare) } -
    - ); - } -} diff --git a/app/scripts/components/repo/repo_details/scannedTag/Layer.css b/app/scripts/components/repo/repo_details/scannedTag/Layer.css deleted file mode 100644 index 69374b57f3..0000000000 --- a/app/scripts/components/repo/repo_details/scannedTag/Layer.css +++ /dev/null @@ -1,82 +0,0 @@ -@import 'dux/css/box.css'; -@import 'dux/css/colors.css'; -/* Note: tooltip CSS is globally styled in styles/vender-overrides/rc-tooltip.css */ - -.grey { - color: #CECED9; -} - -.row { - padding: 1rem 0 1rem 1.5rem; - position: relative; -} - -.unselectedRow { - composes: row; - border-top: 1px solid #E4E4E4; -} - -.selectedRow { - composes: row; - border: 1px solid #E4E4E4; - border-radius: var(--global-radius); -} - -/* remove top border for unselected row following a selected row */ -.selectedRow + .unselectedRow { - border-top: none; -} - -.check { - color: #6BCEC0; -} - -.chevron { - color: #CECED9; - cursor: pointer; - display: inline-block; - float: right; - margin: 6px 0; -} - -.layerSize { - composes: grey; - display: inline-block; - font-size: 0.8rem; -} - -.dockerCommandLine { - text-overflow: ellipsis; - overflow: hidden; - width:100%; - display: inline; - margin-right: 0.5rem; - font-size: 1.1rem; - color: #78828F; -} -a .dockerCommandLine { - color: #22b8eb; -} - -.title { - margin-bottom: 0.5rem; -} - -.layerNum { - position: absolute; - left: -5px; - color: #bbb; - top: 2px; - font-weight: 500; -} - -.baseLayerLabel { - background-color: #E7E7E7; - color: var(--jumbo); - border-radius: var(--global-radius); - padding: 0.2rem 0.5rem; -} - -.numVulnerableComps { - margin-right: 0.5rem; -} diff --git a/app/scripts/components/repo/repo_details/scannedTag/Layer.jsx b/app/scripts/components/repo/repo_details/scannedTag/Layer.jsx deleted file mode 100644 index 0ed47f870b..0000000000 --- a/app/scripts/components/repo/repo_details/scannedTag/Layer.jsx +++ /dev/null @@ -1,234 +0,0 @@ -'use strict'; - -import React, { Component, PropTypes } from 'react'; -import ComponentGrid from './ComponentGrid'; -import LayerVulnerabilitiesTable from './LayerVulnerabilitiesTable'; -import size from 'lodash/collection/size'; -import map from 'lodash/collection/map'; -const { object, shape, string, bool, func, number } = PropTypes; -import styles from './Layer.css'; -import FontAwesome from 'common/FontAwesome'; -import ui from 'redux-ui'; -import numeral from 'numeral'; -import forEach from 'lodash/collection/forEach'; -import { getHighestComponentCvss, mapCvss } from '../nautilusUtils.js'; -import Tooltip from 'rc-tooltip'; -import classnames from 'classnames'; -import { VelocityComponent } from 'velocity-react'; -const debug = require('debug')('hub:Layer'); - -// Layer is a row in the table of layers for a ScannedTag -@ui({ - state: { - selectedComponent: '', - isExpanded: false, - // if a component is selected and unselected, should the table still show? - shouldReturnToExpanded: false - } -}) -export default class Layer extends Component { - //vulnerabilities and components are just for this layer - static propTypes = { - ui: shape({ - selectedComponent: string, - isExpanded: bool, - shouldReturnToExpanded: bool - }), - updateUI: func, - - layerNum: number, - components: object.isRequired, - layer: object.isRequired, - vulnerabilities: object.isRequired - } - - truncateStringInMiddle = (str, max = 25, sep = `...`) => { - //don't truncate if it's less than max chars - const sepLen = sep.length; - const len = str.length; - if (len < max || sepLen > max) { return str; } - const n = -0.5 * (max - len - sepLen); - const center = len / 2; - return str.substr(0, center - n) + sep + str.substr(len - center + n); - } - - mkTitleRow = () => { - const { components, layer, vulnerabilities, ui: { isExpanded } } = this.props; - const truncateAtChars = 45; - let titleText = layer.docker_command_line; - if (titleText.length > truncateAtChars) { - titleText = this.truncateStringInMiddle(layer.docker_command_line, truncateAtChars); - } - //add link to clickable rows - let title =
    { titleText }
    ; - if (size(layer.components)) { - title = ( - -
    - { titleText } -
    -
    - ); - } - //add tooltip - const instruction = ( - { layer.docker_command_line }
    } - placement='top' - mouseEnterDelay={ 0.1 } - mouseLeaveDelay={ 0.3 } - align={ { overflow: { adjustY: 0 } } }> - { title } - - ); - const layerSize =
    Compressed size: { numeral(layer.size).format('0.0b') }
    ; - let chevron; - if (size(components)) { - chevron = ( -
    - - - -
    - ); - } - return
    { instruction }{ layerSize } { chevron }
    ; - } - - mkLine = (numVulnerableComps, numComps, layerType) => { - let vulnComps, baseLayer; - if (!numComps) { - vulnComps = ( - - No components in this layer - - ); - } else if (!numVulnerableComps && numComps) { - vulnComps = ( - - -  No vulnerable components - - ); - } else if (numVulnerableComps === 1) { - vulnComps = 1 vulnerable component; - } else if (numComps) { - //nothing for layers with no components - vulnComps = {numVulnerableComps} vulnerable components; - } - - // add base layer tag if relevant - if (layerType === 'BASE') { - baseLayer = Base Layer; - } - return
    {vulnComps} {baseLayer}
    ; - } - - toggleExpanded = () => { - const { updateUI } = this.props; - const { selectedComponent, isExpanded, shouldReturnToExpanded } = this.props.ui; - if (!!selectedComponent && isExpanded) { - //clear selected component when closing - updateUI('selectedComponent', ''); - } - updateUI('shouldReturnToExpanded', !shouldReturnToExpanded); - updateUI('isExpanded', !isExpanded); - } - - selectComponent = (componentId) => { - const { updateUI } = this.props; - const { isExpanded, shouldReturnToExpanded } = this.props.ui; - if (!isExpanded && !!componentId) { - updateUI('isExpanded', true); - } - //close the layer if it was closed before you selected then unselected a component - if (isExpanded && !componentId && !shouldReturnToExpanded) { - updateUI('isExpanded', false); - } - updateUI('selectedComponent', componentId); - } - - viewAll = () => { - const { updateUI } = this.props; - const { selectedComponent } = this.props.ui; - //can only be triggered when isExpanded && selectedComponent !== '' - updateUI('selectedComponent', ''); - } - - sortComponentsBySeverity = (highestComponentCvss) => { - //layer may not have any components - const { components } = this.props; - if (!size(components)) { - return []; - } - return map(components, (c, key) => { - return { ...c, key }; - }).sort( (c1, c2) => { - return highestComponentCvss[c2.key] - highestComponentCvss[c1.key]; - }); - } - - getNumVulnerableComponents = (highestComponentCvss) => { - const { components } = this.props; - let numVulnComps = 0; - forEach(components, (c, key) => { - //get the component's highest cvss and the severity of it - if (mapCvss(highestComponentCvss[key]) !== 'secure') { - numVulnComps++; - } - }); - return numVulnComps; - } - - render() { - const { selectedComponent, isExpanded } = this.props.ui; - const { components, layer, vulnerabilities } = this.props; - // map of { componentName: highestCvss } - const highestComponentCvss = getHighestComponentCvss(components, vulnerabilities); - const componentsSortedBySeverity = this.sortComponentsBySeverity(highestComponentCvss); - //nothing displayed for non-base layers with no components - let maybeLine, maybeTable; - const numComps = size(components); - if (numComps && isExpanded) { - maybeTable = ( - - ); - } - if (!isExpanded) { - const numVulnerableComponents = this.getNumVulnerableComponents(highestComponentCvss); - maybeLine = this.mkLine(numVulnerableComponents, numComps, layer.type); - } - let maybeGrid; - //text is displayed instead of table when there are no components (#NOP) - if (numComps) { - maybeGrid = ( - - ); - } - const rowClasses = classnames({ - 'row': true, - [styles.unselectedRow]: !isExpanded, - [styles.selectedRow]: isExpanded - }); - return ( -
    -
    - { (this.props.layerNum + 1) } - { this.mkTitleRow() } - { maybeLine } - { maybeTable } -
    -
    - { maybeGrid } -
    -
    - ); - } -} diff --git a/app/scripts/components/repo/repo_details/scannedTag/LayerVulnerabilitiesTable.css b/app/scripts/components/repo/repo_details/scannedTag/LayerVulnerabilitiesTable.css deleted file mode 100644 index fc36086c1e..0000000000 --- a/app/scripts/components/repo/repo_details/scannedTag/LayerVulnerabilitiesTable.css +++ /dev/null @@ -1,61 +0,0 @@ -.grey { - color: #B1B5B9; -} - -hr.border { - color: #E4E4E4; - margin: 0.5rem 0 0.5rem; -} - -.headerText { - composes: grey; - text-transform: uppercase; - margin: 0.5rem 0 0.25rem; - font-weight: 500; - font-size: 0.85rem; -} - -.critical { - color: #EB3E46; -} - -.major { - color: #FF8546; -} - -.minor { - color: #FFC458; -} - -.secure { - color: #D3DFDD; -} - -.licenseType { - composes: grey; - font-size: 0.8rem; -} - -.severity { - text-align: right; -} - -.vulnerabilityLines { - margin-bottom: 0.25rem; -} - -.viewAll { - composes: grey; - border-top: 1px solid #C4CDDA; - border-bottom: 1px solid #C4CDDA; - text-align: center; - padding: 0.5rem 0; - cursor: pointer; - text-transform: uppercase; - font-size: 0.85rem; - margin-top: 0.5rem; -} - -.wrapWords { - word-wrap: break-word; -} diff --git a/app/scripts/components/repo/repo_details/scannedTag/LayerVulnerabilitiesTable.jsx b/app/scripts/components/repo/repo_details/scannedTag/LayerVulnerabilitiesTable.jsx deleted file mode 100644 index 5b860ece99..0000000000 --- a/app/scripts/components/repo/repo_details/scannedTag/LayerVulnerabilitiesTable.jsx +++ /dev/null @@ -1,162 +0,0 @@ -'use strict'; - -import React, { Component, PropTypes } from 'react'; -const { object, bool, array, func, string } = PropTypes; -import styles from './LayerVulnerabilitiesTable.css'; -import { mapCvss, mkComponentId } from '../nautilusUtils.js'; -import forEach from 'lodash/collection/forEach'; -import capitalize from 'lodash/string/capitalize'; -import FontAwesome from 'common/FontAwesome'; -import classnames from 'classnames'; -import Tooltip from 'rc-tooltip'; - -export default class LayerVulnerabilitiesTable extends Component { - static propTypes = { - componentsSortedBySeverity: array.isRequired, - selectedComponent: string, - isExpanded: bool, - viewAll: func, - vulnerabilities: object.isRequired - } - - static defaultProps = { - selectedComponent: '' - } - - mkHeader = () => { - return ( -
    - -
    Component
    -
    Vulnerability
    -
    Severity
    -
    -
    - ); - } - - mkComponentArea = (fullName, license, license_type) => { - return ( -
    -
    { fullName }
    -
    - { `${license}:${capitalize(license_type)} License` } -
    -
    - ); - } - - mkVulnerabilityArea = (fullName, vulns) => { - if (!vulns.length) { - return
    No known vulnerabilities
    ; - } - return vulns.map( v => { - const tooltipContent = ( -
    -
    { v.cve }
    -
    { v.summary }
    -
    - ); - return ( - - - - ); - }); - } - - mkSeverityArea = (fullName, vulns) => { - if (!vulns.length) { - let classes = classnames({ - [styles.secure]: true, - [styles.vulnerabilityLines]: true, - [styles.severity]: true - }); - return
    N/A
    ; - } - return vulns.map( v => { - let classes = classnames({ - [styles[v.severity]]: true, - [styles.vulnerabilityLines]: true, - [styles.severity]: true - }); - return ( -
    - { capitalize(v.severity) } -
    - ); - }); - } - - mkComponentRow = (component) => { - const { - license, - license_type, - component: name, - version, - vulnerabilities - } = component; - const { selectedComponent, vulnerabilities: layerVulnerabilities } = this.props; - const id = mkComponentId(component); - // only render this row if there is NOT a selected component OR this is the selected component - let content; - if (!selectedComponent || selectedComponent === id) { - const fullName = version ? `${name} ${version}` : name; - const componentArea = this.mkComponentArea(fullName, license, license_type); - let componentVulns = []; - forEach(vulnerabilities, (v) => { - const vuln = layerVulnerabilities[v]; - //add severity key to vuln object: ex. severity: 'minor' - componentVulns.push({ ...vuln, severity: mapCvss(vuln.cvss)}); - }); - //sort component vulnerabilities by cvss so most vulnerable is first - componentVulns.sort((v1, v2) => v2.cvss - v1.cvss); - const vulnerabilityArea = this.mkVulnerabilityArea(fullName, componentVulns); - const severityArea = this.mkSeverityArea(fullName, componentVulns); - content = ( -
    -

    -
    {componentArea}
    -
    {vulnerabilityArea}
    -
    {severityArea}
    -
    - ); - } - return content; - } - - render() { - const { - componentsSortedBySeverity, - selectedComponent, - isExpanded, - viewAll - } = this.props; - let viewAllSection; - if (selectedComponent) { - viewAllSection = ( -
    - { `View All `} -
    - ); - } - return ( -
    - { this.mkHeader() } - { componentsSortedBySeverity.map(this.mkComponentRow) } - { viewAllSection } -
    - ); - } -} diff --git a/app/scripts/components/repo/repo_details/scannedTag/ScanHeader.css b/app/scripts/components/repo/repo_details/scannedTag/ScanHeader.css deleted file mode 100644 index 6ecdfbf0e3..0000000000 --- a/app/scripts/components/repo/repo_details/scannedTag/ScanHeader.css +++ /dev/null @@ -1,50 +0,0 @@ -@import 'dux/css/colors.css'; - -/* Top section with vulnerability counts */ -.verticalSpacing { - line-height: 1.2rem; -} - -.headerRow { - padding-bottom: 1rem; -} - -.vulnerabilityText { - composes: verticalSpacing; - font-size: 1.2rem; - padding-bottom: 0.5rem; -} - -.feedback { - composes: verticalSpacing; - text-align: right; -} - -.feedbackLink { - color: var(--secondary-5); -} - -/* same color as layer titles */ -.lastScanned { - color: #78828f; -} - -.inlineBlock { - display: inline-block; -} - -.bigCheck { - composes: inlineBlock; - color: #6bcec0; - padding-right: 1rem; -} - -/* Layers and Components section */ -.tableHeader { - border-top: 1px solid #E4E4E4; - padding: 0.5rem 0; -} - -.componentsTitle { - padding-left: 1rem; -} diff --git a/app/scripts/components/repo/repo_details/scannedTag/ScanHeader.jsx b/app/scripts/components/repo/repo_details/scannedTag/ScanHeader.jsx deleted file mode 100644 index 5b33a5ff5f..0000000000 --- a/app/scripts/components/repo/repo_details/scannedTag/ScanHeader.jsx +++ /dev/null @@ -1,64 +0,0 @@ -'use strict'; - -import React from 'react'; -import styles from './ScanHeader.css'; -import capitalize from 'lodash/string/capitalize'; -import size from 'lodash/collection/size'; -import FontAwesome from 'common/FontAwesome'; -import moment from 'moment'; -import { consts } from '../nautilusUtils'; - -const ScanHeader = ({ scan, componentsBySeverity }) => { - const { critical, major, minor, secure } = componentsBySeverity; - const { reponame, tag, sha256sum, completed_at, latest_scan_status } = scan; - const numTotalComponents = critical.length + major.length + minor.length + secure.length; - const numVulnerableComponents = numTotalComponents - secure.length; - const components = numTotalComponents === 1 ? `component` : `components`; - const isOrAre = numVulnerableComponents === 1 ? `is` : `are`; - const lastScanned = latest_scan_status === consts.IN_PROGRESS ? `New scan in progress, showing results from ${moment(completed_at).fromNow()}` : `Scanned ${moment(completed_at).fromNow()}`; - let vulnText, vulnArea; - if (!numVulnerableComponents) { - vulnText =
    Your image is clean! No known vulnerabilities were found.
    ; - vulnArea = ( -
    -
    - -
    -
    -
    {vulnText}
    -
    {lastScanned}
    -
    -
    - ); - } else { - vulnText = `${numVulnerableComponents} of ${numTotalComponents} ${components} ${isOrAre} vulnerable`; - vulnArea = ( -
    -
    {vulnText}
    -
    {lastScanned}
    -
    - ); - } - const feedback = ( - - Provide Feedback - - ); - return ( -
    -
    -
    - {vulnArea} -
    -
    {feedback}
    -
    -
    -
    Layers
    -
    Components
    -
    -
    - ); -}; - -export default ScanHeader; diff --git a/app/scripts/components/repo/repo_details/scannedTag/Square.css b/app/scripts/components/repo/repo_details/scannedTag/Square.css deleted file mode 100644 index fccd037205..0000000000 --- a/app/scripts/components/repo/repo_details/scannedTag/Square.css +++ /dev/null @@ -1,59 +0,0 @@ -.square { - margin-right: 1px; - margin-bottom: 1px; - width: 50px; - height: 50px; - cursor: pointer; - user-select: none; -} - -.square:hover { - border: 1px solid black; -} - -.solid { - opacity: 1; -} - -.faded { - opacity: 0.4; -} - -.outline { - border: 1px solid black; -} - -.component { - color: #B1B5B9; - text-transform: uppercase; - font-weight: 500; - font-size: 0.85rem; -} - -.tooltipSquare { - display: inline-block; - width: 11px; - height: 11px; - vertical-align: middle; - margin-right: .25rem; -} - -.vulnLineWrapper { - padding-top: 0.25rem; -} - -.critical { - background-color: #EB3E46; -} - -.major { - background-color: #FF8546; -} - -.minor { - background-color: #FFC458; -} - -.secure { - background-color: #D3DFDD; -} diff --git a/app/scripts/components/repo/repo_details/scannedTag/Square.jsx b/app/scripts/components/repo/repo_details/scannedTag/Square.jsx deleted file mode 100644 index abc557fd80..0000000000 --- a/app/scripts/components/repo/repo_details/scannedTag/Square.jsx +++ /dev/null @@ -1,110 +0,0 @@ -'use strict'; - -import React, { Component, PropTypes } from 'react'; -const { object, bool, func, shape, oneOf, number } = PropTypes; -import classnames from 'classnames'; -import styles from './Square.css'; -import capitalize from 'lodash/string/capitalize'; -import Tooltip from 'rc-tooltip'; -import { mkComponentId } from '../nautilusUtils.js'; -const severities = ['critical', 'major', 'minor', 'secure']; - -export default class Square extends Component { - static propTypes = { - component: object.isRequired, - isSelected: bool, - isLayerSelected: bool, - numVulnsBySeverity: shape({ - critical: number, - major: number, - minor: number - }), - onClick: func.isRequired, - severity: oneOf(severities) - } - - static defaultProps = { - isSelected: false, - isLayerSelected: false, - severity: 'secure' - } - - onClick = (e) => { - const { isSelected, component } = this.props; - if (isSelected) { - //unselect component - this.props.onClick(''); - } else { - // Note: this is the ID that normalizr uses to refer to components - this.props.onClick(mkComponentId(component)); - } - } - - mkTooltipContent = () => { - const { component, version } = this.props.component; - const { critical, major, minor } = this.props.numVulnsBySeverity; - let vulnList = ( -
    -
    { this.mkTooltipVulnLine('critical', critical) }
    -
    { this.mkTooltipVulnLine('major', major) }
    -
    { this.mkTooltipVulnLine('minor', minor) }
    -
    - ); - if (!critical && !major && !minor) { - vulnList =
    { this.mkTooltipVulnLine('secure') }
    ; - } - return ( -
    -
    COMPONENT
    -
    { `${component} ${version}` }
    - { vulnList } -
    - ); - } - - // Create line with square for inside tooltip, ex: `[] 4 Critical Vulnerabilities` - mkTooltipVulnLine = (severity, num) => { - if (!num && severity !== 'secure') { - return null; - } - const v = num === 1 ? `Vulnerability` : `Vulnerabilities`; - const squareClasses = classnames({ - [styles[severity]]: true, - [styles.tooltipSquare]: true - }); - const text = severity === 'secure' ? `No Known Vulnerabilities` : `${num} ${capitalize(severity)} ${v}`; - return ( -
    -   - { text } -
    - ); - } - - render() { - const { component, version } = this.props.component; - const tooltipId = `square-${component}-${version}`; - const tooltipContent = this.mkTooltipContent(); - const { isLayerSelected, isSelected, severity } = this.props; - const squareClasses = classnames({ - [styles.square]: true, - //layer is not selected or this component is selected - [styles.solid]: !isLayerSelected || isSelected, - //another component is selected - [styles.faded]: isLayerSelected && !isSelected, - [styles.outline]: isSelected, - [styles[severity]]: true - }); - return ( - -
    -   -
    -
    - ); - } -} diff --git a/app/scripts/components/repo/repo_details/scannedTag/selectors.js b/app/scripts/components/repo/repo_details/scannedTag/selectors.js deleted file mode 100644 index ddfdd32924..0000000000 --- a/app/scripts/components/repo/repo_details/scannedTag/selectors.js +++ /dev/null @@ -1,85 +0,0 @@ -'use strict'; - -import { Map } from 'immutable'; -import { createSelector } from 'reselect'; -import { mapCvss, getHighestSeverity } from '../nautilusUtils.js'; -import values from 'lodash/object/values'; -import forEach from 'lodash/collection/forEach'; - - -// Returns the specific tag's scan for the current route -export const getScan = state => { - // When requesting the scan from the API we only ever get one scan back. - // This means that to get our scan we use the first value in our scan object. - // TODO: When we move to redux-simple-router we can use the router's state - // to create the object key as you'd expect. - const vals = values(state.scans.get('scan', new Map()).toJS()); - if (vals.length === 0) { - return null; - } - return vals[0]; -}; - -export const getVulnerabilities = (state) => - state.scans.get('vulnerability', new Map()).toJS(); - -export const getComponents = (state) => - state.scans.get('component', new Map()).toJS(); - -export const getLayers = (state) => - state.scans.get('blob', new Map()).toJS(); - -/** - * Returns a JS object containing component keys sorted into severity adjectives - * @return object {critical: [CompKey, CompKey], major: [], minor: [], secure: []} - */ -export const getComponentsBySeverity = createSelector( - [getComponents, getVulnerabilities], - (comps, vulns) => { - let map = { - critical: [], - major: [], - minor: [], - secure: [] - }; - //for each component in this scan get all the vulnerability cvss scores in an array - //and return the highest - forEach(comps, (componentDetail, componentKey) => { - //componentDetail.vulnerabilities is either null or has vuln keys - const { vulnerabilities } = componentDetail; - if (vulnerabilities === null || !vulnerabilities.length) { - map.secure.push(componentKey); - } else { - let cvssScores = []; - forEach(vulnerabilities, (v) => { - cvssScores.push(vulns[v].cvss); - }); - map[getHighestSeverity(...cvssScores)].push(componentKey); - } - }); - return map; - } -); - -/** - * Returns a JS object containing layer.index as keys (sha is not unique), - * with an object containing only that layer's vulnerabilities as the value. - * The object with vulnerabilies will be a subset of all vulnerabilities - * @return object { 0: [Vuln, Vuln], 1: [Vuln], ... } - */ -export const getVulnerabilitiesByLayer = createSelector( - [getLayers, getComponents, getVulnerabilities], - (layers, components, vulnerabilities) => { - let map = {}; - forEach(layers, l => { - let layerVulnerabilities = {}; - forEach(l.components, c => { - forEach(components[c].vulnerabilities, v => { - layerVulnerabilities[v] = vulnerabilities[v]; - }); - }); - map[l.index] = layerVulnerabilities; - }); - return map; - } -); diff --git a/app/scripts/components/repo/repo_details/tags/DeleteTagArea.css b/app/scripts/components/repo/repo_details/tags/DeleteTagArea.css deleted file mode 100644 index fda8ff4288..0000000000 --- a/app/scripts/components/repo/repo_details/tags/DeleteTagArea.css +++ /dev/null @@ -1,22 +0,0 @@ -@import "dux/css/box.css"; -@import "dux/css/colors.css"; - -.confirmDelete { - color: var(--primary-5); -} -.confirmDelete:hover { - color: color(var(--primary-5) blackness(15%)); -} - -.delete { - color: var(--secondary-5); - transition: color .15s ease-in-out; - align-self: center; -} -.delete:hover { - color: var(--primary-5); -} - -.error { - color: var(--primary-5); -} diff --git a/app/scripts/components/repo/repo_details/tags/DeleteTagArea.jsx b/app/scripts/components/repo/repo_details/tags/DeleteTagArea.jsx deleted file mode 100644 index 4eb3ecff56..0000000000 --- a/app/scripts/components/repo/repo_details/tags/DeleteTagArea.jsx +++ /dev/null @@ -1,70 +0,0 @@ -'use strict'; - -import React, { PropTypes, Component } from 'react'; -import { ATTEMPTING, ERROR } from 'reduxConsts'; -const { func, instanceOf } = PropTypes; -import styles from './DeleteTagArea.css'; -import FA from 'common/FontAwesome'; -import { StatusRecord } from 'records'; -const debug = require('debug')('hub:deleteTagArea'); - -export default class DeleteTagArea extends Component { - // default status comes from StatusRecord - static propTypes = { - status: instanceOf(StatusRecord), - deleteTag: func - } - - state = { - confirmingDelete: false - } - - confirmDelete = (e) => { - this.setState({ - confirmingDelete: true - }); - } - - cancelConfirm = () => { - this.setState({ - confirmingDelete: false - }); - } - - render() { - const { deleteTag, status: { status } } = this.props; - const { confirmingDelete } = this.state; - let content; - if (status === ERROR) { - content = ( -
    - Deletion Failed -
    - ); - } else if (status === ATTEMPTING) { - content = ( -
    - Deleting  -
    - ); - } else if (confirmingDelete) { - content = ( - - ); - } else { - content = ( - - - - ); - } - return content; - } -} diff --git a/app/scripts/components/repo/repo_details/tags/ErrorBar.css b/app/scripts/components/repo/repo_details/tags/ErrorBar.css deleted file mode 100644 index 0faaf05e1d..0000000000 --- a/app/scripts/components/repo/repo_details/tags/ErrorBar.css +++ /dev/null @@ -1,9 +0,0 @@ -@import 'dux/css/colors.css'; - -.bar { - height: 100%; - width: 100%; - display: inline-block; - background-color: var(--iron); - user-select: none; -} diff --git a/app/scripts/components/repo/repo_details/tags/ErrorBar.jsx b/app/scripts/components/repo/repo_details/tags/ErrorBar.jsx deleted file mode 100644 index f277767452..0000000000 --- a/app/scripts/components/repo/repo_details/tags/ErrorBar.jsx +++ /dev/null @@ -1,10 +0,0 @@ -'use strict'; - -import React, { PropTypes, Component } from 'react'; -import styles from './ErrorBar.css'; - -export default class ErrorBar extends Component { - render() { - return
     
    ; - } -} diff --git a/app/scripts/components/repo/repo_details/tags/InProgressBar.css b/app/scripts/components/repo/repo_details/tags/InProgressBar.css deleted file mode 100644 index 29bb491b77..0000000000 --- a/app/scripts/components/repo/repo_details/tags/InProgressBar.css +++ /dev/null @@ -1,9 +0,0 @@ -@import 'dux/css/colors.css'; - -.gradient { - height: 100%; - width: 100%; - display: inline-block; - user-select: none; - background-image: repeating-linear-gradient(-45deg, var(--iron), var(--iron) 12px, var(--base) 0, var(--base) 24px); -} diff --git a/app/scripts/components/repo/repo_details/tags/InProgressBar.jsx b/app/scripts/components/repo/repo_details/tags/InProgressBar.jsx deleted file mode 100644 index 85be1df782..0000000000 --- a/app/scripts/components/repo/repo_details/tags/InProgressBar.jsx +++ /dev/null @@ -1,10 +0,0 @@ -'use strict'; - -import React, { PropTypes, Component } from 'react'; -import styles from './InProgressBar.css'; - -export default class InProgressBar extends Component { - render() { - return
     
    ; - } -} diff --git a/app/scripts/components/repo/repo_details/tags/ScannedTagRow.css b/app/scripts/components/repo/repo_details/tags/ScannedTagRow.css deleted file mode 100644 index 5ae99cd0c0..0000000000 --- a/app/scripts/components/repo/repo_details/tags/ScannedTagRow.css +++ /dev/null @@ -1,41 +0,0 @@ -.lineSpacing { - line-height: 1rem; -} - -.linePadding { - padding-bottom: 0.5rem; -} - -.smallText { - font-size: 0.9rem; -} - -.green { - color: #7DCCC0; -} - -.grey { - color: #7A8492; -} - -.icon { - margin-right: 0.5rem; -} - -.tagSize { - composes: lineSpacing; - composes: smallText; - color: #CECED9; -} - -.tagName { - composes: lineSpacing; - margin-right: 0.5rem; - font-size: 1.2rem; -} - - -.vulnerabilityBarWrapper { - height: 1rem; - width: 350px; -} diff --git a/app/scripts/components/repo/repo_details/tags/ScannedTagRow.jsx b/app/scripts/components/repo/repo_details/tags/ScannedTagRow.jsx deleted file mode 100644 index 77f7379be5..0000000000 --- a/app/scripts/components/repo/repo_details/tags/ScannedTagRow.jsx +++ /dev/null @@ -1,174 +0,0 @@ -'use strict'; - -import React, { PropTypes, Component } from 'react'; -import { Link } from 'react-router'; -const { func, object, shape, string, number, bool, instanceOf } = PropTypes; -import DeleteTagArea from './DeleteTagArea'; -import { FlexRow, FlexItem } from 'common/FlexTable.jsx'; -import VulnerabilityBar from './VulnerabilityBar'; -import InProgressBar from './InProgressBar'; -import ErrorBar from './ErrorBar'; -import bytesToSize from '../../../utils/bytesToSize'; -const debug = require('debug')('ScannedTagRow'); -import FontAwesome from 'common/FontAwesome'; -import classnames from 'classnames'; -import styles from './ScannedTagRow.css'; -import { StatusRecord } from 'records'; -import moment from 'moment'; -import { consts } from '../nautilusUtils'; - -//Renders a tag row for the Tags table with Nautilus Scan information -export default class ScannedTagRow extends Component { - - static propTypes = { - actions: shape({ - deleteRepoTag: func - }), - - tag: shape({ - name: string.isRequired, - full_size: number, - critical: number, - healthy: number, - major: number, - minor: number - }), - JWT: string.isRequired, - name: string.isRequired, - namespace: string.isRequired, - canEdit: bool.isRequired, - status: instanceOf(StatusRecord) - } - - static defaultProps = { - canEdit: false - } - - deleteTag = (e) => { - const { JWT, name, namespace, tag, actions } = this.props; - const tagName = tag.name; - actions.deleteRepoTag({ JWT, namespace, name, tagName }); - } - - render = () => { - const { - tag, - canEdit, - namespace, - name: repoName, - status - } = this.props; - const { - name, - full_size, - last_scanned, - critical, - healthy: secure, - major, - minor, - latest_scan_status - } = tag; - // this is the default value, indicating that no scan results exist - const isFirstScan = moment(last_scanned).isSame('0001-01-01T00:00:00Z'); - // A scan is in progress or failed but we have stale results to show - const scanInProgress = latest_scan_status === consts.IN_PROGRESS && !isFirstScan; - // A scan is in progress or failed and we don't have prior results to show - const newScanInProgress = latest_scan_status === consts.IN_PROGRESS && isFirstScan; - const newScanFailed = latest_scan_status === consts.FAILED && isFirstScan; - - const numVulnerableComponents = critical + major + minor; - const vulnerabilityTextClass = classnames({ - [styles.lineSpacing]: true, - [styles.grey]: true - }); - const vulnerabilityIconClass = classnames({ - [styles.lineSpacing]: true, - [styles.green]: !numVulnerableComponents, - [styles.grey]: numVulnerableComponents || newScanInProgress || newScanFailed, - [styles.icon]: true - }); - let icon, text, bar, lastScanned, titleLink; - if (newScanInProgress) { - icon = 'fa-refresh'; - text = `Scanning image for vulnerabilities...`; - bar = ; - lastScanned = `Scan in progress...`; - titleLink = name; - } else if (newScanFailed) { - icon = 'fa-minus-circle'; - text = `Could not complete image scan`; - bar = ; - lastScanned = `Scan failed`; - titleLink = name; - } else { - const numVulns = numVulnerableComponents ? 'vulnerabilities' : 'no known vulnerabilities'; - text = `This image has ${numVulns}`; - icon = numVulnerableComponents ? 'fa-exclamation-circle' : 'fa-check'; - bar = ( - - ); - //Do not expose refresh scanner failure if scan results exist - lastScanned = scanInProgress ? `New scan in progress...` : `Scanned ${moment(last_scanned).fromNow()}`; - titleLink = {name}; - } - const vulnerabilityArea = ( -
    -
    - - - - - {text} - -
    -
    - {bar} -
    -
    - ); - const lastScannedClasses = classnames({ - [styles.lineSpacing]: true, - [styles.smallText]: true, - [styles.grey]: true - }); - const tagNameClasses = classnames({ - [styles.tagName]: true, - [styles.grey]: newScanInProgress || newScanFailed - }); - const titleArea = ( -
    -
    - - {titleLink} - - - Compressed size: {bytesToSize(full_size)} - -
    -
    - {lastScanned} -
    -
    - ); - let deleteArea; - if (canEdit) { - deleteArea = ( - - ); - } - - return ( - - {titleArea} - {vulnerabilityArea} - {deleteArea} - - ); - } -} diff --git a/app/scripts/components/repo/repo_details/tags/UnscannedTagRow.jsx b/app/scripts/components/repo/repo_details/tags/UnscannedTagRow.jsx deleted file mode 100644 index 5baac35de8..0000000000 --- a/app/scripts/components/repo/repo_details/tags/UnscannedTagRow.jsx +++ /dev/null @@ -1,72 +0,0 @@ -'use strict'; -import React, { PropTypes, Component } from 'react'; -const { func, object, shape, string, number, bool, instanceOf } = PropTypes; -import DeleteTagArea from './DeleteTagArea'; -import { FlexRow, FlexItem } from 'common/FlexTable.jsx'; -import bytesToSize from '../../../utils/bytesToSize'; -const debug = require('debug')('UnscannedTagRow'); -import { StatusRecord } from 'records'; -import moment from 'moment'; - -//Renders a tag row for the Tags table that does not have Nautilus Scan information -export default class UnscannedTagRow extends Component { - static propTypes = { - actions: shape({ - deleteRepoTag: func - }), - - tag: shape({ - name: string.isRequired, - full_size: number - }), - JWT: string.isRequired, - name: string.isRequired, - namespace: string.isRequired, - canEdit: bool.isRequired, - status: instanceOf(StatusRecord) - } - - static defaultProps = { - canEdit: false - } - - deleteTag = (e) => { - const { JWT, name, namespace, tag } = this.props; - const tagName = tag.name; - this.props.actions.deleteRepoTag({ JWT, namespace, name, tagName }); - } - - render() { - const { - tag, - canEdit, - namespace, - name: repoName, - status - } = this.props; - const { name, full_size, last_updated } = tag; - - let deleteArea; - if (canEdit) { - deleteArea = ( - - ); - } - - const lastUpdated = last_updated ? moment(last_updated).fromNow() : `Unavailable`; - - return ( - - {name} - {bytesToSize(full_size)} - {lastUpdated} - - {deleteArea} - - - ); - } -} diff --git a/app/scripts/components/repo/repo_details/tags/VulnerabilityBar.jsx b/app/scripts/components/repo/repo_details/tags/VulnerabilityBar.jsx deleted file mode 100644 index 7baff85afa..0000000000 --- a/app/scripts/components/repo/repo_details/tags/VulnerabilityBar.jsx +++ /dev/null @@ -1,65 +0,0 @@ -'use strict'; - -import React, { PropTypes, Component } from 'react'; -const { number } = PropTypes; - -export default class VulnerabilityBar extends Component { - static propTypes = { - critical: number, - secure: number, - major: number, - minor: number - } - - getStyle = (severity, num, total) => { - const colors = { - critical: `#E8404B`, - major: `#FD854E`, - minor: `#FED954`, - secure: `#7DCCC0` - }; - - let width; - if (total) { - width = num / total * 100; - } else if (severity === 'secure'){ - width = 100; - } else { - width = 0; - } - - return { - width: `${width}%`, - backgroundColor: colors[severity], - display: `inline-block`, - height: `100%`, - userSelect: 'none' - }; - - } - - render() { - const { - critical, - secure, - major, - minor - } = this.props; - const total = critical + secure + major + minor; - const criticalStyle = this.getStyle('critical', critical, total); - const majorStyle = this.getStyle('major', major, total); - const minorStyle = this.getStyle('minor', minor, total); - const secureStyle = this.getStyle('secure', secure, total); - const wrapperStyle = { width: `100%` }; - - return ( -
    -
     
    -
     
    -
     
    -
     
    -
    - ); - - } -} diff --git a/app/scripts/components/repo/repo_details/tags/selectors.js b/app/scripts/components/repo/repo_details/tags/selectors.js deleted file mode 100644 index 07cc2e5104..0000000000 --- a/app/scripts/components/repo/repo_details/tags/selectors.js +++ /dev/null @@ -1,65 +0,0 @@ -'use strict'; - -import { createSelector } from 'reselect'; -import { Map, List } from 'immutable'; -import filter from 'lodash/collection/filter'; -import size from 'lodash/collection/size'; -import map from 'lodash/collection/map'; -import values from 'lodash/object/values'; - - -// Returns all repository tags (unordered) -export const getRepoTags = (state) => { - const reponame = state.repos.get('name', ''); - const namespace = state.repos.get('namespace', ''); - // We need to use toJS() to deeply convert tags from immutable to objects. - // We also return an array because getScannedTags and getUnscannedTags return - // arrays - keeping things consistent. - return values(state.tags.getIn([namespace, reponame, 'tags'], new Map()).toJS()); -}; - -// Returns all repository tags in the order of the hub API -// Note: This does _not_ return any tags that are returned by nautilus but not hub -// so we use the getRepoTags for the scannedTag selector -export const getRepoTagsInOrder = (state) => { - const reponame = state.repos.get('name', ''); - const namespace = state.repos.get('namespace', ''); - // We need to use toJS() to deeply convert tags from immutable to objects. - // We also return an array because getScannedTags and getUnscannedTags return - // arrays - keeping things consistent. - let orderedTags = state.tags.getIn([namespace, reponame, 'result'], []); - if (orderedTags.toArray) { - orderedTags = orderedTags.toArray(); - } - const tags = state.tags.getIn([namespace, reponame, 'tags'], new Map()).toJS(); - return map(orderedTags, (tagId) => tags[tagId]); -}; - - -// Returns only tags which have been scanned by nautilus -export const getScannedTags = createSelector( - [getRepoTags], - (tags) => { - // If the tag has a 'healthy' key then this has been scanned by nautilus - return filter(tags, (tag) => tag.healthy !== undefined); - } -); -// Number of tags scanned by nautilus -export const getScannedTagCount = createSelector( - [getScannedTags], - (tags) => size(tags) -); - -// getUnscannedTags returns only tags **not** scanned by nautilus -export const getUnscannedTags = createSelector( - [getRepoTagsInOrder], - (tags) => { - // If healthy is undefined this tag only has a hub response - return filter(tags, (tag) => tag.healthy === undefined); - } -); - -export const getUnscannedTagCount = createSelector( - [getUnscannedTags], - (tags) => size(tags) -); diff --git a/app/scripts/components/repositories/AutoBuildSetupForm.css b/app/scripts/components/repositories/AutoBuildSetupForm.css deleted file mode 100644 index c078308f01..0000000000 --- a/app/scripts/components/repositories/AutoBuildSetupForm.css +++ /dev/null @@ -1,49 +0,0 @@ -@import "dux/css/box.css"; -@import "dux/css/colors.css"; - -.errorText { - white-space: pre; -} - -.input { - margin-right: var(--default-margin); -} - -.formContainer { - margin-top: var(--default-margin); -} - -.error { - color: var(--primary-5); - font-size: .875rem; - margin-bottom: 0.3rem; -} - -/* TODO: this is also used in EnterpriseTrialForm.css | a candidate to be in colors.css */ -.label { - color: #7a8491; - font-weight: 500; - sup { - font-size: 1rem; - vertical-align: text-bottom; - } -} - -.customizeLabel { - composes: label; - margin-bottom: 0.5rem; -} - -.floatRight { - float: right; - margin-right: 1rem; -} - -.globalError { - composes: error; - composes: floatRight; -} - -.select { - border-radius: var(--global-radius); -} \ No newline at end of file diff --git a/app/scripts/components/repositories/AutoBuildSetupForm.jsx b/app/scripts/components/repositories/AutoBuildSetupForm.jsx deleted file mode 100644 index 19d03c80af..0000000000 --- a/app/scripts/components/repositories/AutoBuildSetupForm.jsx +++ /dev/null @@ -1,410 +0,0 @@ -'use strict'; - -import React, { PropTypes } from 'react'; -import findIndex from 'lodash/array/findIndex'; -import includes from 'lodash/collection/includes'; -import omit from 'lodash/object/omit'; -import map from 'lodash/collection/map'; -import AutoBuildTagsInput from './AutoBuildTagsInput.jsx'; -import connectToStores from 'fluxible-addons-react/connectToStores'; -import RepositoryNameInput from 'common/RepositoryNameInput.jsx'; -import SimpleTextArea from 'common/SimpleTextArea.jsx'; -import AutobuildStore from '../../stores/AutobuildStore'; -import AutobuildConfigStore from '../../stores/AutobuildConfigStore'; -import AutobuildSourceRepositoriesStore from '../../stores/AutobuildSourceRepositoriesStore'; -import RepoStore from '../../stores/RepositoryPageStore'; -import UserStore from '../../stores/UserStore'; -import createAutobuild from '../../actions/createAutobuild'; -import updateAutobuildFormField from '../../actions/updateAutobuildFormField.js'; -import getSettingsData from 'actions/getSettingsData'; -import { PageHeader } from 'dux'; -import AlertBox from 'common/AlertBox'; -import Card, { Block } from '@dux/element-card'; -import Button from '@dux/element-button'; -import { validateRepositoryName } from '../utils/validateRepositoryName'; -import { STATUS as COMMONSTATUS } from '../../stores/common/Constants'; -import Markdown from '@dux/element-markdown'; - -const { - ATTEMPTING -} = COMMONSTATUS; - -const buildTagsClientSideError = 'No empty strings allowed for docker tag (or) source tag/branch name specification.'; - -import styles from './AutoBuildSetupForm.css'; - -const { - array, - bool, - func, - number, - object, - oneOf, - shape, - string -} = PropTypes; - -var AutoBuildSetupForm = React.createClass({ - contextTypes: { - executeAction: func.isRequired - }, - propTypes: { - user: object.isRequired, - JWT: string.isRequired, - ownedNamespaces: array.isRequired, - configStore: shape({ - description: string, - isPrivate: oneOf(['private', 'public']).isRequired, - name: string.isRequired, - namespace: string.isRequired, - sourceRepoName: string.isRequired, - STATUS: string.isRequired - }), - sourceRepositories: shape({ - type: string.isRequired - }) - }, - getInitialState: function() { - return { - isActive: true, - buildTags: this.defaultBuildTags, - clientSideError: '', - advancedMode: false - }; - }, - /*eslint-disable camelcase*/ - - /* - * By default, if the input is empty for source tag/branch name, send the string: '{sourceref}' & 'master' - * By default, if the input is empty for docker tag name, send the string with regex for all matches & 'latest' - */ - defaultBuildTags: [ - { - id: 'tag-0', - name: 'latest', - source_type: 'Branch', - source_name: 'master', - dockerfile_location: '/' - }, - { - id: 'tag-1', - name: '{sourceref}', - source_type: 'Branch', - source_name: '/^([^m]|.[^a]|..[^s]|...[^t]|....[^e]|.....[^r]|.{0,5}$|.{7,})/', - dockerfile_location: '/' - } - ], - getBuildTagsToSend: function() { - let bTags = this.state.buildTags; - return map(bTags, (tag) => { - return omit(tag, 'id'); - }); - }, - /*eslint-enable camelcase */ - _handleCreate: function(evt) { - evt.preventDefault(); - const { username } = this.props.user; - const { buildTags, isActive } = this.state; - const { description, isPrivate, name, namespace, sourceRepoName } = this.props.configStore; - const { type } = this.props.sourceRepositories; - - const params = this.props.params; - const sourceRepoFallback = `${params.sourceRepoNamespace}/${params.sourceRepoName}`; - - if (!validateRepositoryName(name.toLowerCase())) { - //check if the repo name is valid | client side check - this.setState({ - clientSideError: `No spaces and special characters other than '.' and '-' are allowed. -Repository names should not begin/end with a '.' or '-'.` - }); - } else { - - var newAutobuild = { - user: username, - namespace: namespace, - name: name.toLowerCase(), - description: description, - is_private: isPrivate === 'private', - build_name: sourceRepoName.toLowerCase() || sourceRepoFallback.toLowerCase(), - provider: type.toLowerCase(), - active: isActive, - tags: this.getBuildTagsToSend() - }; - - this.context.executeAction(createAutobuild, {JWT: this.props.JWT, autobuildConfig: newAutobuild}); - } - }, - _onActiveStateChange: function(e) { - this.setState({isActive: !this.state.isActive}); - }, - _getTagIndex: function(id) { - return findIndex(this.state.buildTags, function(tag) { - return (tag.id === id); - }); - }, - _setTagState: function(id, prop, value) { - let bTags = this.state.buildTags; - bTags[this._getTagIndex(id)][prop] = value; //find tag and update property - this.setState({ - buildTags: bTags - }); - }, - _onTagRemoved: function(id) { - //Remove tag, when user removes it from the form - let bTags = this.state.buildTags; - bTags.splice(this._getTagIndex(id), 1); - this.setState({ - buildTags: bTags - }); - }, - _onTagAdded: function(tag) { - let bTags = this.state.buildTags; - bTags.push(tag); - this.setState({ - buildTags: bTags - }); - }, - _resetBuildTagsError: function() { - //Reset clientSideError on change - if (this.state.clientSideError === buildTagsClientSideError) { - this.setState({ - clientSideError: '' - }); - } - }, - _onSourceNameChange: function(tagId, e) { - let sourceName = e.target.value; - let sourceType = this.state.buildTags[this._getTagIndex(tagId)].sourceType; - if (sourceName === '' && sourceType && sourceType === 'Branch') { - sourceName = '/^([^m]|.[^a]|..[^s]|...[^t]|....[^e]|.....[^r]|.{0,5}$|.{7,})/'; - } else if (sourceName === '' && sourceType && sourceType === 'Tag') { - sourceName = '/.*/'; - } else { - this._resetBuildTagsError(); - //Strip trailing and leading spaces. If we end up with empty string, throw an error. - if (sourceName.trim() === '') { - this.setState({ - clientSideError: buildTagsClientSideError - }); - } - } - this._setTagState(tagId, 'source_name', sourceName.trim()); - }, - _onSourceTypeChange: function(tagId, e) { - this._setTagState(tagId, 'source_type', e.target.value); - }, - _onDockerfileLocationChange: function(tagId, e) { - this._setTagState(tagId, 'dockerfile_location', e.target.value); - }, - _onTagChange: function(tagId, e) { - let tagName = e.target.value; - if (tagName === '') { - tagName = '{sourceref}'; - } - this._setTagState(tagId, 'name', tagName.trim()); - }, - _updateForm(fieldKey) { - return (e) => { - if (fieldKey === 'namespace') { - this.setState({ - currentNamespace: e.target.value - }); - this.context.executeAction(getSettingsData, { - JWT: this.props.JWT, - username: e.target.value, - repoType: 'autobuild' - }); - } else if (fieldKey === 'name' && this.state.clientSideError) { - this.setState({ - clientSideError: '' - }); - } - this.context.executeAction(updateAutobuildFormField, { - fieldKey, - fieldValue: e.target.value - }); - }; - }, - componentWillReceiveProps: function(nextProps) { - const { name, namespace, success, STATUS } = nextProps.configStore; - //If autobuild was created successfully - if (STATUS.SUCCESSFUL || success) { - this.props.history.pushState(null, `/r/${namespace}/${name.toLowerCase()}/`); - } - }, - customTagsConfig: function() { - this.setState({ - advancedMode: true, - buildTags: [] - }); - }, - defaultTagsConfig: function() { - this.setState({ - advancedMode: false, - buildTags: this.defaultBuildTags - }); - }, - render: function() { - - const { - description, - error, - isPrivate, - name, - namespace, - success, - STATUS - } = this.props.configStore; - - /* start error/success handling */ - let maybeSuccess = ; - if (success) { - maybeSuccess = {success}; - } - - let nameError; - let nameErrorContent = error.dockerhub_repo_name; - if(nameErrorContent) { - nameError = nameErrorContent; - } - - let descriptionError; - if(error.description) { - descriptionError = error.description; - } - - let privateRepoError; - if(error.is_private) { - privateRepoError = error.is_private; - } - - let buildTagsError; - if (error.buildTags) { - buildTagsError = error.buildTags; - } - - let maybeError = null; - let errorDetail = error.detail || this.state.clientSideError; - if (errorDetail) { - maybeError = ( -
    -
    - {errorDetail} -
    -
    - ); - } - /* end error handling */ - - //Check if user has passed in namespace as query | verify if they have access to it - let currentUserNamespace = this.props.location.query.namespace; - if (!includes(this.props.ownedNamespaces, currentUserNamespace)) { - //If they don't have access to the namespace set in the query param ? then fallback to default namespace - currentUserNamespace = this.props.user.namespace; - } - let tagsConfigList = null; - - if (this.state.advancedMode) { - tagsConfigList = ( -
    -
    -
    Customize Autobuild Tags
    - -
    - {buildTagsError} -
    - -
    - ); - } - - return ( -
    - -
    -
    - - -
    -
    -
    - -
    - {nameError} -
    - -
    -
    - -
    - {privateRepoError} -
    - -
    -
    - -
    - {descriptionError} -
    - - - {/* advanced mode */} - {tagsConfigList} -
    - {maybeError} -
    -
    - -
    -
    - - {maybeSuccess} -
    -
    -
    -
    -
    - ); - } -}); - -export default connectToStores(AutoBuildSetupForm, - [ - AutobuildSourceRepositoriesStore, - AutobuildConfigStore, - UserStore - ], - function({ getStore }, props){ - return { - sourceRepositories: getStore(AutobuildSourceRepositoriesStore).getState(), - configStore: getStore(AutobuildConfigStore).getState(), - ownedNamespaces: getStore(UserStore).getNamespaces() - }; - }); diff --git a/app/scripts/components/repositories/AutoBuildTagsInput.jsx b/app/scripts/components/repositories/AutoBuildTagsInput.jsx deleted file mode 100644 index c5b4c52e53..0000000000 --- a/app/scripts/components/repositories/AutoBuildTagsInput.jsx +++ /dev/null @@ -1,159 +0,0 @@ -'use strict'; - -import React from 'react'; -import { FlexTable, Header, Item } from 'common/TagsFlexTable'; -import AutoBuildTagsInputItem from './AutoBuildTagsInputItem.jsx'; - -const AutoBuildTagsInput = React.createClass({ - contextTypes: { - getStore: React.PropTypes.func.isRequired - }, - propTypes: { - repo: React.PropTypes.string.isRequired, - onTagRemoved: React.PropTypes.func.isRequired, - onTagAdded: React.PropTypes.func.isRequired, - onSourceTypeChange: React.PropTypes.func.isRequired, - onSourceNameChange: React.PropTypes.func.isRequired, - onDockerfileLocationChange: React.PropTypes.func.isRequired - }, - getInitialState: function() { - const masterDefaultRow = { - row: 'row-0', - sourceType: 'Branch', - sourceName: 'master', - sign: 'plus', - tag: 'latest', - fileLocation: '/', - tagId: 'tag-0' - }; - const dynamicTagRow = { - row: 'row-1', - sourceType: 'Branch', - sourceName: '', - sign: 'minus', - tag: '', - fileLocation: '/', - tagId: 'tag-1' - }; - return { - currentRows: [ - this.makeRow(masterDefaultRow), - this.makeRow(dynamicTagRow) - ] - }; - }, - _handleBtnClickAdd: function(e) { - e.preventDefault(); - let rows = this.state.currentRows; - let idx = this.state.currentRows.length; - const row = { - row: 'row-' + idx, - sourceType: 'Branch', - sourceName: '', - sign: 'minus', - tag: '', - fileLocation: '/', - tagId: 'tag-' + idx - }; - const newRow = this.makeRow(row); - this.setState({ - currentRows: rows.concat(newRow) - }); - //Make an empty build tag that will get updated on edit - const bTag = { - id: 'tag-' + idx, - sourceType: 'Branch', - sourceName: '', - fileLocation: '/', - tagName: '' - }; - this.props.onTagAdded(this.makeBuildTag(bTag)); - }, - makeRow: function(rowObj) { - const { - row, - sourceType, - sourceName, - sign, - tag, - fileLocation, - tagId - } = rowObj; - - return ( - - ); - }, - makeBuildTag: function(newBuildTag) { - const { - id, - sourceType, - sourceName, - fileLocation, - tagName - } = newBuildTag; - /*eslint-disable camelcase */ - /* By default, if the input is empty for source tag/branch name, send the string: '{sourceref}'*/ - /* By default, if the input is empty for docker tag name, send the string with the regex for all matches */ - return { - id: id, - name: tagName === '' ? '{sourceref}' : tagName, - source_type: sourceType, - source_name: sourceName === '' ? '/^([^m]|.[^a]|..[^s]|...[^t]|....[^e]|.....[^r]|.{0,5}$|.{7,})/' : sourceName, - dockerfile_location: fileLocation - }; - /*eslint-enable camelcase */ - }, - componentDidMount: function() { - const masterBuildTag = { - id: 'tag-0', - sourceType: 'Branch', - sourceName: 'master', - fileLocation: '/', - tagName: 'latest' - }; - const dynamicBuildTag = { - id: 'tag-1', - sourceType: 'Branch', - sourceName: '', - fileLocation: '/', - tagName: '' - }; - this.props.onTagAdded( - this.makeBuildTag(masterBuildTag) - ); - this.props.onTagAdded( - this.makeBuildTag(dynamicBuildTag) - ); - }, - render: function() { - return ( - -
    - Push Type - Name - Dockerfile Location - Docker Tag - -
    - { this.state.currentRows } -
    - ); - } -}); - -module.exports = AutoBuildTagsInput; diff --git a/app/scripts/components/repositories/AutoBuildTagsInputItem.css b/app/scripts/components/repositories/AutoBuildTagsInputItem.css deleted file mode 100644 index 754af1558e..0000000000 --- a/app/scripts/components/repositories/AutoBuildTagsInputItem.css +++ /dev/null @@ -1,28 +0,0 @@ -@import 'dux/css/colors.css'; -@import 'dux/css/box.css'; - -.faBtn { - cursor: pointer; - user-select: none; - margin-left: auto; - margin-right: auto; - margin-top: 0.8rem; -} - -.addBtn { - composes: faBtn; - color: var(--success-color); -} - -.removeBtn { - composes: faBtn; - color: var(--alert-color); -} - -.select { - border-radius: var(--global-radius); -} - -input.rounded { - border-radius: var(--global-radius); -} \ No newline at end of file diff --git a/app/scripts/components/repositories/AutoBuildTagsInputItem.jsx b/app/scripts/components/repositories/AutoBuildTagsInputItem.jsx deleted file mode 100644 index 17a1cb06f9..0000000000 --- a/app/scripts/components/repositories/AutoBuildTagsInputItem.jsx +++ /dev/null @@ -1,123 +0,0 @@ -'use strict'; - -import React, {PropTypes} from 'react'; -import { Row, Header, Item } from 'common/TagsFlexTable'; -import FA from 'common/FontAwesome'; -import styles from './AutoBuildTagsInputItem.css'; -import Button from '@dux/element-button'; -const {func, string} = PropTypes; - -const AutoBuildTagsInputItem = React.createClass({ - propTypes: { - row: string.isRequired, - sign: string.isRequired, - tagId: string.isRequired, - tagName: string.isRequired, - removeItem: func.isRequired, - sourceName: string.isRequired, - sourceType: string.isRequired, - fileLocation: string.isRequired, - handleBtnClick: func.isRequired, - onSourceTypeChange: func.isRequired, - onSourceNameChange: func.isRequired, - onTagChange: func.isRequired, - onDockerfileLocationChange: func.isRequired - }, - getInitialState: function() { - return { - hidden: false, - sourceType: 'Branch' - }; - }, - _handleHide: function(e) { - e.preventDefault(); - e.stopPropagation(); - this.setState({ - hidden: true - }); - this.props.removeItem(this.props.tagId); - }, - onSourceTypeChange: function(e) { - this.setState({ - sourceType: e.target.value - }); - this.props.onSourceTypeChange(e); - }, - componentDidMount: function() { - this.setState({ - tag: this.props.tagName - }); - }, - render: function() { - - let sourceNamePlaceholder; - let tagNamePlaceholder; - - //Support to show default rule for each type of rule in the UI - const branchesOrTags = this.state.sourceType === 'Branch' ? 'branches' : 'tags'; - const branchOrTag = this.state.sourceType === 'Branch' ? 'branch' : 'tag'; - if (this.state.sourceType === 'Branch') { - sourceNamePlaceholder = 'All branches except master'; - } else { - sourceNamePlaceholder = '/.*/ This targets all tags'; - } - tagNamePlaceholder = `Same as ${branchOrTag}`; - - const { - fileLocation, - handleBtnClick, - onDockerfileLocationChange, - onTagChange, - onSourceNameChange, - row, - sign, - sourceName, - sourceType, - tagName - } = this.props; - - let item = null; - if (!this.state.hidden) { - item = ( - - - - - - - - - - - - - - - - - - - - ); - } - - return item; - } -}); - -module.exports = AutoBuildTagsInputItem; diff --git a/app/scripts/components/repositories/Autobuild.jsx b/app/scripts/components/repositories/Autobuild.jsx deleted file mode 100644 index 5b8d7cf080..0000000000 --- a/app/scripts/components/repositories/Autobuild.jsx +++ /dev/null @@ -1,102 +0,0 @@ -'use strict'; - -import AutobuildStore from '../../stores/AutobuildStore'; -import Route404 from '../common/RouteNotFound404Page.jsx'; -import AutobuildBlankSlate from './AutobuildBlankSlate.jsx'; -import React, { PropTypes, cloneElement } from 'react'; -import { Link } from 'react-router'; -import connectToStores from 'fluxible-addons-react/connectToStores'; -import { SecondaryNav } from 'dux'; -import LiLink from '../common/LiLink'; -const debug = require('debug')('COMPONENT:Autobuild'); - -let AutobuildSourcesNav = React.createClass({ - displayName: 'AutobuildSourcesNav', - propTypes: { - namespace: PropTypes.string, - githubAccount: PropTypes.object, - bitbucketAccount: PropTypes.object - }, - _checkAccountsAndGetLinks: function() { - var liLinks = []; - if (this.props.githubAccount) { - liLinks.push( - - GitHub ({this.props.githubAccount.login}) - ); - } - - if (this.props.bitbucketAccount) { - liLinks.push( - - Bitbucket ({this.props.bitbucketAccount.login}) - ); - } - - if (!this.props.githubAccount || !this.props.bitbucketAccount) { - liLinks.push( Link Accounts); - } - - return liLinks; - }, - render: function() { - var liLinks = this._checkAccountsAndGetLinks(); - return ( -
    - -
      - {liLinks} -
    -
    -
    - ); - } -}); - -var Autobuild = React.createClass({ - propTypes: { - user: React.PropTypes.object, - JWT: React.PropTypes.string - }, - contextTypes: { - executeAction: React.PropTypes.func.isRequired - }, - render: function() { - if (!this.props.JWT) { - return ( - - ); - } else if (!this.props.githubAccount && !this.props.bitbucketAccount) { - return ( -
    - - -
    - ); - } else { - return ( -
    - - {this.props.children && cloneElement(this.props.children, { - user: this.props.user, - JWT: this.props.JWT, - githubAccount: this.props.githubAccount, - bitbucketAccount: this.props.bitbucketAccount - })} -
    - ); - } - } -}); - -export default connectToStores(Autobuild, - [ - AutobuildStore - ], - function({ getStore }, props) { - return getStore(AutobuildStore).getState(); - }); diff --git a/app/scripts/components/repositories/AutobuildBlankSlate.css b/app/scripts/components/repositories/AutobuildBlankSlate.css deleted file mode 100644 index 7de08e056a..0000000000 --- a/app/scripts/components/repositories/AutobuildBlankSlate.css +++ /dev/null @@ -1,6 +0,0 @@ -@import "dux/css/box.css"; -@import "dux/css/colors.css"; - -.row { - margin-top: var(--default-margin); -} diff --git a/app/scripts/components/repositories/AutobuildBlankSlate.jsx b/app/scripts/components/repositories/AutobuildBlankSlate.jsx deleted file mode 100644 index df12b31f36..0000000000 --- a/app/scripts/components/repositories/AutobuildBlankSlate.jsx +++ /dev/null @@ -1,41 +0,0 @@ -'use strict'; - -import React, { PropTypes } from 'react'; -import Card, { Block } from '@dux/element-card'; -import FA from 'common/FontAwesome'; -import styles from './AutobuildBlankSlate.css'; -import { Link } from 'react-router'; - -var AutobuildBlankSlate = React.createClass({ - displayName: 'AutobuildBlankSlate', - propTypes: { - slateItems: React.PropTypes.element - }, - render() { - var slateItems = null; - if (!this.props.slateItems) { - slateItems = ( -
    -

    You haven't linked to GitHub or Bitbucket yet.

    - Link Accounts -
    - ); - } else { - slateItems = this.props.slateItems; - } - - return ( -
    -
    - - - {slateItems} - - -
    -
    - ); - } -}); - -module.exports = AutobuildBlankSlate; diff --git a/app/scripts/components/repositories/AutobuildIndex.css b/app/scripts/components/repositories/AutobuildIndex.css deleted file mode 100644 index 4059a66e80..0000000000 --- a/app/scripts/components/repositories/AutobuildIndex.css +++ /dev/null @@ -1,28 +0,0 @@ -@import "dux/css/box.css"; -@import "dux/css/colors.css"; - -.row { - margin-top: var(--default-margin); -} - -.link { - display: block; - background: white; - border-radius: var(--global-radius); - border: 1px solid var(--silver); - color: var(--secondary-4); - margin: 0 .3rem .3rem 0; - padding: 1.8rem; - i { - font-size: 6rem; - margin-bottom: 1rem; - } - &:hover { - background: #f4f9fc; - color: var(--secondary-4); - } - &:focus { - background: color(#f4f9fc blackness(10%)); - color: var(--secondary-4); - } -} diff --git a/app/scripts/components/repositories/AutobuildIndex.jsx b/app/scripts/components/repositories/AutobuildIndex.jsx deleted file mode 100644 index 23158f62e7..0000000000 --- a/app/scripts/components/repositories/AutobuildIndex.jsx +++ /dev/null @@ -1,67 +0,0 @@ -'use strict'; - -import React, { PropTypes, Component } from 'react'; -import { Link } from 'react-router'; -import FA from 'common/FontAwesome'; -import classnames from 'classnames'; -import styles from './AutobuildIndex.css'; - -export default class AutobuildIndex extends Component { - static propTypes = { - githubAccount: PropTypes.object, - bitbucketAccount: PropTypes.object - } - - render() { - let githubText; - let githubLink; - let bitbucketText; - let bitbucketLink; - const linkClasses = classnames({ - 'button': true, - [styles.link]: true - }); - - if (this.props.githubAccount) { - githubLink = `/add/automated-build/${this.props.params.userNamespace}/github/orgs/`; - githubText = ( -

    Create Auto-build

    - ); - } else { - githubLink = '/account/authorized-services/'; - githubText = ( -

    Link Account

    - ); - } - if (this.props.bitbucketAccount) { - bitbucketLink = `/add/automated-build/${this.props.params.userNamespace}/bitbucket/orgs/`; - bitbucketText = ( -

    Create Auto-build

    - ); - } else { - bitbucketLink = '/account/authorized-services/'; - bitbucketText = ( -

    Link Account

    - ); - } - - return ( -
    -
    - - {githubText} - -

    Github

    - -
    -
    - - {bitbucketText} - -

    Bitbucket

    - -
    -
    - ); - } -} diff --git a/app/scripts/components/repositories/LinkedAccountSourcesForm.css b/app/scripts/components/repositories/LinkedAccountSourcesForm.css deleted file mode 100644 index 32e2acd73a..0000000000 --- a/app/scripts/components/repositories/LinkedAccountSourcesForm.css +++ /dev/null @@ -1,3 +0,0 @@ -.arrowSelect { - margin-top: 0.3rem; -} \ No newline at end of file diff --git a/app/scripts/components/repositories/LinkedAccountSourcesForm.jsx b/app/scripts/components/repositories/LinkedAccountSourcesForm.jsx deleted file mode 100644 index 4ba18daac6..0000000000 --- a/app/scripts/components/repositories/LinkedAccountSourcesForm.jsx +++ /dev/null @@ -1,163 +0,0 @@ -'use strict'; -import React, { Component, PropTypes } from 'react'; -import { Link } from 'react-router'; -import _ from 'lodash'; -import AutobuildBlankSlate from './AutobuildBlankSlate.jsx'; -import AutobuildSourceRepositoriesStore from '../../stores/AutobuildSourceRepositoriesStore'; -import selectSourceRepoForAutobuild from '../../actions/selectSourceRepoForAutobuild'; -import ListSelector from '../common/ListSelector.jsx'; -import FilterBar from '../filter/FilterBar.jsx'; -import FA from 'common/FontAwesome'; -import connectToStores from 'fluxible-addons-react/connectToStores'; -import styles from './LinkedAccountSourcesForm.css'; - -const debug = require('debug')('COMPONENT:LinkedAccountSourcesForm'); -const { array, func } = PropTypes; - -class LinkedAccountSourcesForm extends Component{ - - static propTypes = { - repos: array - } - - static contextTypes = { - executeAction: func.isRequired - } - - state = { - selectedRepos: [], - selectedUserOrg: {} - } - - _handleUserOrgClick = (userOrOrg) => { - //Clicked on user or org, show the repositories under that user or organization - this.setState({ - selectedUserOrg: userOrOrg, - selectedRepos: userOrOrg.repo_list - }); - } - - _handleRepoClick = (item, currentType) => { - //Replace all "/" with "-" if they exist, so route is always valid - item.name = item.name.replace(/[/]/g, '-'); - this.props.history.pushState(null, - `/add/automated-build/${currentType.toLowerCase()}/form/${this.state.selectedUserOrg.name}/${item.name}/`, - {namespace: this.props.params.userNamespace} - ); - //Set the source repository in the store, so the autobuild configuration form can get to it - this.context.executeAction(selectSourceRepoForAutobuild, item); - } - - _makeUserOrgList = (list) => { - var userAndOrgsList = list.map(function(item, idx) { - var imgAvatar = item.avatar_url; - var selectedArrow; - if (this.state.selectedUserOrg.name === item.name) { - selectedArrow = ; - } - return ( -
  • -
    -   {item.name} - {selectedArrow} -
    -
  • ); - }, this); - return userAndOrgsList; - } - - _makeReposList = (list) => { - var links = []; - var currentType = this.props.type; - var _this = this; - const namespace = this.state.selectedUserOrg.name; - if (currentType) { - links = list.map(function(item, idx) { - return ( -
  • - {item.name} -
  • ); - }); - } - return links; - } - - _filterRepos = (query) => { - //e.preventDefault(); - if (query) { - this.setState({ - selectedRepos: _.filter(this.state.selectedRepos, function (repo) { - return repo.name.indexOf(query) !== -1; - }) - }); - } else { - this.setState({ - selectedRepos: this.state.selectedUserOrg.repo_list - }); - } - } - - componentDidMount = () => { - //Set the first element as selected if there is none selected - if (_.isEmpty(this.state.selectedUserOrg) && this.props.repos) { - var selected = this.props.repos[0]; - this.setState({ - selectedUserOrg: selected, - selectedRepos: selected.repo_list - }); - } - } - - componentWillReceiveProps = (nextProps) => { - //Set the first element as selected if there is none selected - if (nextProps.repos && nextProps.repos.length > 0) { - var selected = nextProps.repos[0]; - this.setState({ - selectedUserOrg: selected, - selectedRepos: selected.repo_list - }); - } - } - - render() { - if (this.props.repos) { - var currentUserAndOrgs = this._makeUserOrgList(this.props.repos); - var currentRepos = []; - if (currentUserAndOrgs && currentUserAndOrgs.length > 0) { - currentRepos = this._makeReposList(this.state.selectedRepos); - } - var filterBar = (); - return ( -
    -
    -
    -
    - -
    -
    - -
    -
    -
    - ); - } else { - const slateItem = ( -
    -

    -  An error occurred while trying to connect to {this.props.type}. -

    -
    Link your account here.
    -
    - ); - return (); - } - } -} - -export default connectToStores(LinkedAccountSourcesForm, - [ - AutobuildSourceRepositoriesStore - ], - function({ getStore }, props) { - return getStore(AutobuildSourceRepositoriesStore).getState(); - }); diff --git a/app/scripts/components/repositories/RepositoryBlock.jsx b/app/scripts/components/repositories/RepositoryBlock.jsx deleted file mode 100644 index 2fabeaf3f7..0000000000 --- a/app/scripts/components/repositories/RepositoryBlock.jsx +++ /dev/null @@ -1,62 +0,0 @@ -'use strict'; - -import React, { PropTypes } from 'react'; -import { Link } from 'react-router'; - -export default React.createClass({ - displayName: 'RepositoryBlock', - propTypes: { - namespace: PropTypes.string.isRequired, - name: PropTypes.string.isRequired, - status: PropTypes.number, - description: PropTypes.string, - fullDescription: PropTypes.string, - isPrivate: PropTypes.bool, - // trusted means Automated Build - isTrusted: PropTypes.bool, - isOfficial: PropTypes.bool, - starCount: PropTypes.number, - pullCount: PropTypes.number - }, - getDefaultProps: function() { - return { - status: 0, - description: '', - fullDescription: '', - isPrivate: true, - isTrusted: false, - isOfficial: false, - starCount: 0, - pullCount: 0 - }; - }, - render: function() { - return (
  • -
    -
    -
    - -
    -
    -
    - {this.props.namespace} -
    - {this.props.name} -
    - {this.props.isPrivate ? 'Private' : 'Public'} - {this.props.isTrusted ? ' | Automated Build' : ''} -
    -
    -
    -
    -

    {this.props.description}

    -
    -
    -

    {this.props.starCount} STARS

    -

    {this.props.pullCount} DOWNLOADS

    -
    -
    -
  • - ); - } -}); diff --git a/app/scripts/components/search/ResultsNotFound.css b/app/scripts/components/search/ResultsNotFound.css deleted file mode 100644 index 0853d05e32..0000000000 --- a/app/scripts/components/search/ResultsNotFound.css +++ /dev/null @@ -1,39 +0,0 @@ -@import 'dux/css/colors.css'; - -.wrap { - height: 100%; - text-align: center; -} - -.messageModule { - animation: fadein 0.3s; - padding: 1.5rem 0 0 0; - margin: 4rem 0; -} - -@keyframes fadein { - from { - opacity: 0; - } - to { - opacity: 1; - } -} - -.heading { - color: #71859d; - font-size: 3rem; - font-weight: 400; - -} - -.subheading { - color: var(--secondary-7); -} - -.message { - color: #71859d; - margin: 0 auto; - padding: .5rem; - font-size: 1.1rem; -} diff --git a/app/scripts/components/search/ResultsNotFound.jsx b/app/scripts/components/search/ResultsNotFound.jsx deleted file mode 100644 index 7cd4a3e226..0000000000 --- a/app/scripts/components/search/ResultsNotFound.jsx +++ /dev/null @@ -1,35 +0,0 @@ -'use strict'; - -import React, { Component } from 'react'; -import styles from './ResultsNotFound.css'; - -/* - * A component similar to the RouteNotFound404Page meant for no results - * from a search or filter. Any of the props can be customized beyond text, ex: - * } /> - * to include a search icon. - */ -export default class ResultsNotFound extends Component { - - static defaultProps = { - heading: 'Sorry!', - subheading: 'We couldn\'t find any results for this search.', - message: 'Please double check your input and try again.' - } - - render() { - return ( -
    -
    -
    -
    -

    {this.props.heading}

    -

    {this.props.subheading}

    -

    {this.props.message}

    -
    -
    -
    -
    - ); - } -} diff --git a/app/scripts/components/search/Search.jsx b/app/scripts/components/search/Search.jsx deleted file mode 100644 index e4ce222e00..0000000000 --- a/app/scripts/components/search/Search.jsx +++ /dev/null @@ -1,153 +0,0 @@ -'use strict'; -import React, { PropTypes } from 'react'; -import FluxibleMixin from 'fluxible-addons-react/FluxibleMixin'; - -import Pagination from '../common/Pagination.jsx'; -import ResultsNotFound from './ResultsNotFound.jsx'; -import SearchStore from './../../stores/SearchStore'; -import SearchBar from './SearchBar.jsx'; -import Spinner from '../Spinner.jsx'; -import FA from '../common/FontAwesome'; -import RepositoriesList from '../common/RepositoriesList'; -import { PageHeader } from 'dux'; -import _ from 'lodash'; -import findKey from 'lodash/object/findKey'; -import DocumentTitle from 'react-document-title'; - -var debug = require('debug')('COMPONENT:Search'); - -var _getQueryParams = function(state) { - //transition to will always have `q` appended as query param at the very least - //Other query params like: `s` -> sort by | `t=User` -> user | `t=Organization` -> Org | `f=official` - // `f=automated_builds` | `s=date_created`, `s=last_updated`, `s=alphabetical`, `s=stars`, `s=downloads` - // `s=pushes` - var queryParams = { - q: state.query || '', - page: state.page || 1, - isAutomated: state.isAutomated || 0, - isOfficial: state.isOfficial || 0, - pullCount: state.pullCount || 0, - starCount: state.starCount || 0 - }; - return queryParams; -}; - -var Search = React.createClass({ - mixins: [FluxibleMixin], - statics: { - storeListeners: [SearchStore] - }, - contextTypes: { - getStore: React.PropTypes.func.isRequired - }, - getInitialState: function() { - return this.context.getStore(SearchStore).getState(); - }, - //on Search Store Change - onChange: function() { - //When a search query has been submitted - var state = this.context.getStore(SearchStore).getState(); - this.setState(state); - }, - _getCurrentFilter: function() { - const query = this.props.location.query; - return findKey(query, (val, key) => { - return val === '1' && key !== 'q' && key !== 'page'; - }); - }, - _retransitionToSearch: function() { - this.props.history.pushState(null, '/search/', _getQueryParams(this.state)); - }, - _onFilterChange: function(event) { - event.preventDefault(); - if (event.target.value === 'isAutomated') { - this.setState({isAutomated: 1, isOfficial: 0, starCount: 0, pullCount: 0}, this._retransitionToSearch); - } else if (event.target.value === 'isOfficial') { - this.setState({isOfficial: 1, isAutomated: 0, starCount: 0, pullCount: 0}, this._retransitionToSearch); - } if (event.target.value === 'starCount') { - this.setState({starCount: 1, isOfficial: 0, isAutomated: 0, pullCount: 0}, this._retransitionToSearch); - } else if (event.target.value === 'pullCount') { - this.setState({pullCount: 1, isOfficial: 0, starCount: 0, isAutomated: 0}, this._retransitionToSearch); - } else if (event.target.value === 'all') { - this.setState({pullCount: 0, isOfficial: 0, starCount: 0, isAutomated: 0}, this._retransitionToSearch); - } - }, - _onChangePage(pageNumber) { - pageNumber = parseInt(pageNumber, 10); - this.setState({ - page: pageNumber - }, function() { - this.props.history.pushState(null, '/search/', _getQueryParams(this.state)); - }); - }, - _renderMessage() { - var message; - if (this.state.count === 0) { - if (this.state.isAutomated === '0' && this.state.isOfficial === '0') { - message = _.isEmpty(this.state.query) ? `Your search is empty!` : `Your search of '${this.state.query}' did not match any repository names or descriptions.`; - } else { - let filterType = this.state.isAutomated === '1' ? 'automated builds' : 'official repositories'; - message = `There are no ${filterType} matching '${this.state.query}'. Try removing this filter to see more results.`; - } - return ( -
    -
    - } message={ message } /> -
    -
    - ); - } else { - return ; - } - }, - _renderFilterBar() { - if (this.state.count === 0 && this.state.isAutomated === '0' && this.state.isOfficial === '0') { - return ; - } else { - return ( -
    -
    - -
    -
    - ); - } - }, - render: function() { - var maybePagination; - if (this.state.results && this.state.results.length > 0 && this.state.count > 10) { - maybePagination = ( - -
    -
    - -
    -
    -
    - ); - } - return ( - -
    - -
    -
    - { this._renderFilterBar() } - - {maybePagination} -
    -
    -
    - ); - } -}); -module.exports = Search; diff --git a/app/scripts/components/search/SearchBar.css b/app/scripts/components/search/SearchBar.css deleted file mode 100644 index 46c8b37690..0000000000 --- a/app/scripts/components/search/SearchBar.css +++ /dev/null @@ -1,17 +0,0 @@ -@import "dux/css/box"; - -input.searchInput { - background: #405165; - border: 1px solid #4c5968; - border-radius: var(--global-radius); - color: #fff; - padding-left: 24px; -} - -.fa { - position: relative; - color: white; - max-width: 1rem; - top: -7px; - left: 6px; -} \ No newline at end of file diff --git a/app/scripts/components/search/SearchBar.jsx b/app/scripts/components/search/SearchBar.jsx deleted file mode 100644 index 86994c2df3..0000000000 --- a/app/scripts/components/search/SearchBar.jsx +++ /dev/null @@ -1,84 +0,0 @@ -'use strict'; -import React from 'react'; -import FluxibleMixin from 'fluxible-addons-react/FluxibleMixin'; -import SearchStore from '../../stores/SearchStore'; -import styles from './SearchBar.css'; -import FA from '../common/FontAwesome'; - -var debug = require('debug')('COMPONENT:SearchBar'); - -var _getQueryParams = function(state) { - //transition to will always have `q` appended as query param at the very least - //Other query params like: `s` -> sort by | `t=User` -> user | `t=Organization` -> Org | `f=official` - // `f=automated_builds` | `s=date_created`, `s=last_updated`, `s=alphabetical`, `s=stars`, `s=downloads` - // `s=pushes` - var queryParams = { - q: state.query || '', - page: state.page || 1, - isAutomated: state.isAutomated || 0, - isOfficial: state.isOfficial || 0, - starCount: state.starCount || 0, - pullCount: state.pullCount || 0 - }; - return queryParams; -}; - -var SearchBar = React.createClass({ - mixins: [FluxibleMixin], - statics: { - storeListeners: [SearchStore] - }, - contextTypes: { - getStore: React.PropTypes.func.isRequired - }, - getDefaultProps() { - return { - placeholder: 'Search' - }; - }, - getInitialState: function() { - return this.context.getStore(SearchStore).getState(); - }, - //on Search Store Change - onChange: function() { - //When a search query has been submitted - var state = this.context.getStore(SearchStore).getState(); - this.setState(state); - }, - _handleQueryChange: function(event) { - event.preventDefault(); - //Change page to number 1 when the query is changed - this.setState({ - page: 1 - }); - this.setState({query: event.target.value}); - }, - _handleQuerySubmit: function(event) { - event.preventDefault(); - //second parameter will be empty object always since we don't have /search/{?}/ - //third param will be the query /search/?q=whatever&s=blah&f=bleh - this.props.history.pushState(null, '/search/', _getQueryParams(this.state)); - }, - render: function() { - var searchQuery = this.state.query; - var inputPlaceholder = this.props.placeholder; - return ( -
    -
    -
    - -
    - -
    -
    -
    -
    - ); - } -}); - -module.exports = SearchBar; diff --git a/app/scripts/components/search/SearchResultItem.jsx b/app/scripts/components/search/SearchResultItem.jsx deleted file mode 100644 index 579c35becf..0000000000 --- a/app/scripts/components/search/SearchResultItem.jsx +++ /dev/null @@ -1,67 +0,0 @@ -'use strict'; - -import React from 'react'; -import Badge from '../Badge.jsx'; -import StatsComponent from '../StatsComponent.jsx'; -var debug = require('debug')('COMPONENT:SearchResultItem'); - -//TODO: will go under the ul in item info, will be a bunch of key value pairs reused across -//TODO: Logged out views will have the `owner/reponame` (think about this) -//TODO: Star icon should be passed to badge as d-`iconname` where `d-` is for the docker font icons - -var SearchResultItem = React.createClass({ - render: function() { - var resultItem = this.props.resultItem; - - //Push badges based on result item - var badges = []; - var officialBadge =
  • ; - var autobuildBadge =
  • ; - - // jscs:disable requireCamelCaseOrUpperCaseIdentifiers - if (resultItem.is_official) { - badges.push(officialBadge); - } else if (resultItem.is_automated) { - badges.push(autobuildBadge); - } - - //TODO: repo_owner is null atm, since API performance degrades if we try to get it - //
  • - - return ( -
  • -
    -
    -
    - -
    -
    -
    -
    {resultItem.repo_name}
    -
    -
    -
      - {badges} -
    -
    -
    -
    -
      -
    • -
    • -
    -
    -
    -
    -
    -

    {resultItem.short_description}

    -
    -
    -
    -
  • - ); - // jscs:enable - } -}); - -module.exports = SearchResultItem; diff --git a/app/scripts/components/search/SearchResults.jsx b/app/scripts/components/search/SearchResults.jsx deleted file mode 100644 index bd56981d11..0000000000 --- a/app/scripts/components/search/SearchResults.jsx +++ /dev/null @@ -1,42 +0,0 @@ -'use strict'; -/** -TODO: UNUSED COMPONENT. SHOULD REMOVE -*/ -import React from 'react'; -import ResultItem from './SearchResultItem.jsx'; -var debug = require('debug')('COMPONENT:SearchResults'); - -var SearchResults = React.createClass({ - contextTypes: { - getStore: React.PropTypes.func.isRequired - }, - getResultItem: function(resultItem, idx) { - if (resultItem.short_description) { - if (resultItem.short_description.length > 100) { - resultItem.short_description = resultItem.short_description.substring(0, 100) + '...'; - } else if (resultItem.short_description.length === 0) { - resultItem.short_description = 'No description set'; - } - } - return ; - }, - _handleSearchResultClick: function(repoName, e) { - e.preventDefault(); - //TODO: Handle official images/repos differently - this.props.history.pushState(null, `/r/${repoName}/`); - }, - render: function() { - var results = this.props.results; - var resultItems = []; - if (results) { - resultItems = results.map(this.getResultItem); - } - return ( -
    -
      {resultItems}
    -
    - ); - } -}); - -module.exports = SearchResults; diff --git a/app/scripts/components/store-promotion.js b/app/scripts/components/store-promotion.js deleted file mode 100644 index 13645dc176..0000000000 --- a/app/scripts/components/store-promotion.js +++ /dev/null @@ -1,106 +0,0 @@ -'use strict'; - -module.exports = { - STORE_OFFICIAL_REPONAME_ID_MAP: { - busybox: '061eb9c1-aeec-4ec8-8c4b-ba30ae1d5b47', - telegraf: 'f031f47c-6f88-4c21-a31a-20be46809d37', - consul: 'fec1f6b9-0a26-49b7-990b-d001a3496cc6', - sourcemage: '983e7005-65f1-4ff0-833e-a2edce972d88', - nuxeo: '139c1693-dc39-42cd-8104-cdf838504954', - mysql: '3083290a-203f-4c04-b2de-cc057959d2c9', - piwik: '40157634-cee7-462f-9927-27d734de3a28', - ros: '4e84c2be-5bb3-40f8-8854-8901e496d576', - 'buildpack-deps': '9e56c286-5b40-4838-89fe-fd513c9c3bd6', - 'hello-world': 'f35b81c7-b96a-45d3-809d-99eef381e71f', - sonarqube: '3f8fc4ce-eb8e-40ad-88ba-69e97299c64f', - celery: '4a239159-e3cf-42b1-b16f-6a9a8555285f', - neurodebian: '63dbd2e1-f29e-498b-8b16-1477770ae733', - glassfish: '4dfbd2c4-46dd-4674-8595-433594514a69', - erlang: '06fabd5a-6420-4209-a756-3d3355b3c672', - cirros: 'e3d3b771-35d3-45fe-92af-3f8bbd56cb40', - postgres: '022689bf-dfd8-408f-9e1c-19acac32e57b', - python: '1ae86987-df14-4741-9433-d9602a4da995', - crux: '8319429c-874d-4cfa-9dde-b861f7245eab', - pypy: '91db8014-64b0-4417-9429-e8128e04191c', - alpine: 'e7e5dbc4-2103-4b7c-9409-b0ca32ce3d83', - memcached: 'deec12eb-5792-49d2-919e-0b861bb910cd', - rabbitmq: 'fa7625b4-fdca-4b48-b078-692f6451965a', - orientdb: '7a741b7c-b96a-44ce-b64d-d0b59e6a7803', - chronograf: 'c3749997-031b-4ced-9f0b-cb4d15b6a6a1', - centos: 'd5052416-4069-4619-8597-ba61df35ba6f', - hipache: '12bafabf-353e-47ad-a416-44d827874489', - kibana: '41105537-6820-4448-908b-4ac7b31be0c2', - 'websphere-liberty': 'cacdc40b-0fed-4221-952a-18b0b8a3500b', - redis: '1f6ef28b-3e48-4da1-b838-5bd8710a2053', - 'mongo-express': 'e89a86ce-9988-4ee1-ada9-228925730018', - lightstreamer: 'b0766515-2ca5-4ea2-9120-713cab78d0f7', - gazebo: 'e42e1e00-1168-4815-b951-6ee5bae86d58', - kapacitor: 'f310b81d-5c23-4936-880d-027ffe296557', - influxdb: '2053499a-fe59-495d-a024-518311223f3f', - maven: '3e44be96-02cf-427e-bdbe-f108ec3be831', - odoo: 'f351cb39-4574-44e7-afa6-b3cc87390041', - notary: '7cb50ac7-d119-4ec7-a276-cad5154fb67e', - solr: 'f4e3929d-d8bc-491e-860c-310d3f40fff2', - logstash: '6464c97c-8e9c-492c-8a35-27620300a6cc', - thrift: '579aa075-9d28-4ae5-9966-357b96f70550', - haproxy: '85c386ff-85a7-4d61-b309-5901f625c36f', - drupal: '680b2b97-bc91-44fc-9437-73748b0a8f0a', - mono: '4234a761-444b-4dea-a6b3-31bda725c427', - joomla: 'e17a7172-1f32-4191-83ba-606f354cce16', - elasticsearch: '1090e442-627e-4bf2-b29a-555f57a64ecd', - clojure: '800b3c7e-3b83-4af5-ab84-b57086887339', - 'rakudo-star': '2a6a7106-f60e-495a-b085-e0496e23b72e', - traefik: '0319de97-4b7f-4a74-a260-5d027ec8cee0', - elixir: '4e418a43-2be9-44fd-8640-9dbb82c369a2', - irssi: 'cb02bc13-349b-4aad-9b2e-6045c16d9c4c', - julia: 'b228ffc7-3d8c-46c5-9e2d-4101e2b9629a', - jruby: 'c90a0b81-88c5-437a-87b2-38c9a398451e', - haskell: '74b1a6b9-c84a-4221-891d-18d28f1798e5', - neo4j: '5f0be9a7-f5d7-4974-9c0e-78c33484e79c', - httpd: '3574ef8c-86e4-40ed-a705-3a52d9786bde', - php: '9c2c5426-0cca-4a30-a450-b2961541c6dc', - java: '199a18b1-511b-47fd-b287-a41555fafb9f', - bonita: 'c37b224a-dec9-4dbe-b18a-5f1789766409', - jetty: 'd88c12a5-0ca7-4358-aef0-c759b0e5290a', - rails: 'a3ed7866-8446-4221-b86d-67507eb6be3e', - perl: '5241d150-6793-4ca8-a392-51098722f672', - swarm: '8ea4fd22-82ac-4ec8-b89d-018cb0944d72', - redmine: 'dfd4330b-0b3a-479c-8bbc-8b4cad6235b8', - wordpress: 'c14a56d6-07e4-464b-b71c-4b24dc7f1836', - tomee: 'afc9cbe9-8325-4609-ad48-cc891f1e0002', - photon: '45053cf9-0044-46cc-9748-d6d01a548dd3', - 'r-base': 'f2e50720-cada-432f-85a5-1ade438d537b', - oraclelinux: '505eac14-101f-44de-b80f-d79743a2288d', - ruby: '0f900dcb-7e32-45e4-b095-6dfa2f5b597b', - iojs: 'c3a93fc8-ef57-47df-ad12-6e443cd93f61', - rethinkdb: '6e5e7f5d-52fa-4598-a8fc-f1911a873ac0', - mongo: '9147d1b7-a686-4e38-8ecd-94a47f5da9cf', - golang: '3e4f3e51-3930-4dd8-975c-517705d9d4e7', - mageia: '179f8859-4966-4750-a2a9-5cd203556556', - owncloud: 'a66e9029-57d7-4aef-89b0-a98987e8dbf2', - cassandra: '53ad54dd-9bd8-48cd-89b4-fc1d5fdfa6cc', - gcc: '06ad851d-f666-47d3-9ef3-e90535c141ec', - fedora: 'a5648d34-aacd-4599-ab72-79662aa09df2', - couchdb: '263ad544-d7c7-4892-8244-fe78b6231265', - arangodb: '806abe10-8cee-451b-856b-57bcf0fdf6d0', - jenkins: 'd55eda09-d7f0-47b0-8780-3407f2f9142c', - hylang: '62cb43d8-bf5b-4115-8408-ff1412ead82e', - node: 'e6658267-cc55-421e-b5be-5e69460fb0d1', - percona: '176b92e3-b122-422c-96f0-d518bffe9bd5', - registry: 'd93c7069-a612-4019-ade6-8c3b0a73acd9', - mariadb: '1712cb54-62e1-405b-a973-1492552c9bb9', - debian: '40efd176-3c0a-4460-9f94-fc98ca92362f', - ghost: '57aa97f1-9868-4936-906c-b83d78cfaf4f', - opensuse: '99f9bd45-4c65-4e45-aa36-234e9150efc6', - tomcat: '3d5f71ad-2cc0-467f-ab6a-351e7adf404e', - django: '65765d71-d893-407d-a707-486c7381dfbf', - backdrop: 'aa66b4ed-fd75-4a87-87a7-c173c740a42f', - docker: '995677a1-1f6a-4e2e-929a-fde926abbd95', - ubuntu: '414e13de-f1ba-40d0-9867-08f2e5884b3f', - nginx: '37b1dde7-a3e7-463a-a0e3-d8be2b136292', - sentry: '788f45b7-2701-4244-90e4-3f85aef116d8', - couchbase: '881296c9-606f-4861-91b6-26a31ef52618', - crate: 'dfac6fed-98d7-4c5d-b338-fb6930c62c69', - nats: '59c6aa2f-dcca-4f2c-8c30-2ea2326feab2' - } -}; diff --git a/app/scripts/components/userWrapper/UserStars.jsx b/app/scripts/components/userWrapper/UserStars.jsx deleted file mode 100644 index 1fa3055750..0000000000 --- a/app/scripts/components/userWrapper/UserStars.jsx +++ /dev/null @@ -1,67 +0,0 @@ -'use strict'; - -import React, { PropTypes, Component } from 'react'; -const { array, string, func } = PropTypes; -import connectToStores from 'fluxible-addons-react/connectToStores'; - -import UserProfileStarsStore from 'stores/UserProfileStarsStore'; -import RepositoriesList from 'common/RepositoriesList'; -import Pagination from 'common/Pagination'; -import { Module } from 'dux'; - -var debug = require('debug')('UserProfileStars'); - -var UserStars = React.createClass({ - displayName: 'UserStars', - propTypes: { - starred: array, - next: string, - prev: string - }, - _onChangePage(pageNumber) { - this.props.history.pushState(null, `/u/${this.props.user.username}/starred/`, {page: pageNumber}); - }, - render() { - - var currentPageNumber = parseInt(this.props.location.query.page, 10); - var maybePagination; - - if(this.props.starred && this.props.starred.length > 0) { - maybePagination = ( -
    -
    - -
    -
    - ); - - return ( -
    -
    - - {maybePagination} -
    -
    - ); - - } else { - - return ( - This user does not have any starred repos. - ); - - } - } -}); - -export default connectToStores(UserStars, - [ - UserProfileStarsStore - ], - function({ getStore }, props) { - return getStore(UserProfileStarsStore) - .getState(); - }); diff --git a/app/scripts/components/userprofile/Repos.jsx b/app/scripts/components/userprofile/Repos.jsx deleted file mode 100644 index 05ecd4898b..0000000000 --- a/app/scripts/components/userprofile/Repos.jsx +++ /dev/null @@ -1,79 +0,0 @@ -'use strict'; - -import React, { PropTypes, Component } from 'react'; -import { Link } from 'react-router'; -import connectToStores from 'fluxible-addons-react/connectToStores'; -import UserProfileReposStore from '../../stores/UserProfileReposStore'; -import RepositoriesList from '../common/RepositoriesList'; -import Pagination from '../common/Pagination'; -import moment from 'moment'; -import { Module } from 'dux'; - -var debug = require('debug')('UserProfileRepos'); - -class Repos extends Component { - - static propTypes = { - user: PropTypes.object.isRequired, - repos: PropTypes.array, - next: PropTypes.string, - prev: PropTypes.string - } - - _onChangePage = (pageNumber) => { - const username = this.props.params.user; - this.props.history.pushState(null, `/u/${username}/`, {page: pageNumber}); - } - - render() { - - debug(this.props); - if(this.props.repos && this.props.repos.length > 0) { - - return ( -
    -
    - - {this.renderPagination()} -
    -
    - ); - - } else { - debug(this.props); - const { username, orgname } = this.props.user; - const namespace = username || orgname; - return ( - - This user has not created any repos yet - - ); - } - } - renderPagination = (e) => { - if(this.props.repos && this.props.repos.length > 0) { - const currentPageNumber = parseInt(this.props.location.query.page, 10); - return ( -
    -
    - -
    -
    - ); - } else { - return null; - } - } -} - -export default connectToStores(Repos, - [ - UserProfileReposStore - ], - function({ getStore }, props) { - return getStore(UserProfileReposStore) - .getState(); - }); diff --git a/app/scripts/components/utils/avatar.js b/app/scripts/components/utils/avatar.js deleted file mode 100644 index 0750062fb6..0000000000 --- a/app/scripts/components/utils/avatar.js +++ /dev/null @@ -1,30 +0,0 @@ -'use strict'; - -import officialLogos from 'common/data/officialLogos.js'; -const officialImage = '/public/images/logos/mini-logo-white-inset.png'; - -const isOfficialNamespace = (namespace) => namespace === '_' || namespace === 'library'; - -// reponame is an optional param used to descriminate between official repos -// and it will be ignored unless it is an official repo -export function mkAvatarForNamespace(namespace, reponame) { - if (isOfficialNamespace(namespace) && reponame && officialLogos[reponame]) { - return `/public/images/official/${officialLogos[reponame]}`; - } - if(isOfficialNamespace(namespace) || !namespace) { - return officialImage; - } - return `${process.env.HUB_API_BASE_URL}/v2/users/${namespace}/avatar/`; -} - -/** - * This function should be treated as deprecated. We can not reliably - * detect the namespace type (User || Org) from the urls. - */ -export function mkAvatarForOrg(namespace) { - return `${process.env.HUB_API_BASE_URL}/v2/orgs/${namespace}/avatar/`; -} - -export function isOfficialAvatarURL(url) { - return url === officialImage; -} diff --git a/app/scripts/components/utils/bytesToSize.js b/app/scripts/components/utils/bytesToSize.js deleted file mode 100644 index bf0b6bebc9..0000000000 --- a/app/scripts/components/utils/bytesToSize.js +++ /dev/null @@ -1,23 +0,0 @@ -'use strict'; - -export default function bytesToSize(bytes, precision) -{ - const kilobyte = 1000; - const megabyte = kilobyte * 1000; - const gigabyte = megabyte * 1000; - const terabyte = gigabyte * 1000; - - if ((bytes >= 0) && (bytes < kilobyte)) { - return bytes + ' B'; - } else if ((bytes >= kilobyte) && (bytes < megabyte)) { - return (bytes / kilobyte).toFixed(precision) + ' KB'; - } else if ((bytes >= megabyte) && (bytes < gigabyte)) { - return (bytes / megabyte).toFixed(precision) + ' MB'; - } else if ((bytes >= gigabyte) && (bytes < terabyte)) { - return (bytes / gigabyte).toFixed(precision) + ' GB'; - } else if (bytes >= terabyte) { - return (bytes / terabyte).toFixed(precision) + ' TB'; - } else { - return 'Unknown size'; - } -} diff --git a/app/scripts/components/utils/encodeForm.js b/app/scripts/components/utils/encodeForm.js deleted file mode 100644 index 5f6b5d64d3..0000000000 --- a/app/scripts/components/utils/encodeForm.js +++ /dev/null @@ -1,17 +0,0 @@ -'use strict'; -import map from 'lodash/collection/map'; - -const _encodeForm = (obj, prefix) => { - const str = []; - map(obj, (value, key) => { - if (obj.hasOwnProperty(key)) { - const k = prefix ? `${prefix}[${key}]` : key; - str.push(typeof value === 'object' ? - _encodeForm(value, k) : - `${encodeURIComponent(k)}=${encodeURIComponent(value)}`); - } - }); - return str.join('&'); -}; - -export default _encodeForm; diff --git a/app/scripts/components/utils/validateRepositoryName.js b/app/scripts/components/utils/validateRepositoryName.js deleted file mode 100644 index 3c6167fc87..0000000000 --- a/app/scripts/components/utils/validateRepositoryName.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -export const validateRepositoryName = (name) => -{ - var repoNamePattern = /^[a-z0-9]+(?:[._-][a-z0-9]+)*$/; - return repoNamePattern.test(name); -}; diff --git a/app/scripts/components/welcome/ActivityFeedItem.jsx b/app/scripts/components/welcome/ActivityFeedItem.jsx deleted file mode 100644 index f496695aa9..0000000000 --- a/app/scripts/components/welcome/ActivityFeedItem.jsx +++ /dev/null @@ -1,41 +0,0 @@ -'use strict'; -import React from 'react'; -import moment from 'moment'; - -//TODO: remove this after a better solution is found -var _getNotificationNameForID = function(user, notificationType) { - //TODO: maybe create a link to the user's public profile page if any - if(notificationType === 'trusted_build_fail') { - return 'Automated build failure.'; - } else if (notificationType === 'new_repo_star') { - return user + ' starred a repository'; - } else if (notificationType === 'new_repo_comment') { - return user + ' added a new comment.'; - } else { - return ''; - } -}; - -var ActivityFeedItem = React.createClass({ - displayName: 'ActivityFeed', - getDefaultProps: function() { - return { - notification: 0, - /*eslint-disable camelcase */ - last_occurence: '', - /*eslint-enable camelcase */ - user: '' - }; - }, - render: function() { - return ( -
  • -
    -

    {_getNotificationNameForID(this.props.user, this.props.notification)}

    - {moment(this.props.last_occurence).fromNow()} -
    -
  • ); - } -}); - -module.exports = ActivityFeedItem; diff --git a/app/scripts/components/welcome/ChangePassSuccess.css b/app/scripts/components/welcome/ChangePassSuccess.css deleted file mode 100644 index d74134b2c6..0000000000 --- a/app/scripts/components/welcome/ChangePassSuccess.css +++ /dev/null @@ -1,9 +0,0 @@ -@import "dux/css/colors"; -@import "dux/css/box"; - -.passwordReset { - margin-top: 5rem; - border: 1px solid rgb(233, 237, 240); - border-radius: var(--global-radius); - min-height: 270px; -} diff --git a/app/scripts/components/welcome/ChangePassSuccess.jsx b/app/scripts/components/welcome/ChangePassSuccess.jsx deleted file mode 100644 index ff127d995f..0000000000 --- a/app/scripts/components/welcome/ChangePassSuccess.jsx +++ /dev/null @@ -1,30 +0,0 @@ -'use strict'; - -import React, { PropTypes } from 'react'; -import { Button } from 'dux'; -import { Link } from 'react-router'; -import ChangePasswordStore from '../../stores/ChangePasswordStore.js'; -import styles from './ChangePassSuccess.css'; - -var changePassSuccess = React.createClass({ - contextTypes: { - executeAction: PropTypes.func.isRequired - }, - PropTypes: { - changePassStore: PropTypes.shape({ - reset: PropTypes.bool.isRequired, - resetErr: PropTypes.bool.isRequired - }) - }, - render: function() { - return ( -
    -

    Your password has been reset

    -

    You may now login with your new password

    - Back to Login -
    - ); - } -}); - -module.exports = changePassSuccess; diff --git a/app/scripts/components/welcome/DashboardNewsItem.jsx b/app/scripts/components/welcome/DashboardNewsItem.jsx deleted file mode 100644 index edf3f5902f..0000000000 --- a/app/scripts/components/welcome/DashboardNewsItem.jsx +++ /dev/null @@ -1,19 +0,0 @@ -'use strict'; -const React = require('react'); - -//This is a placeholder for a news item that is shown in the dashboard. Relevant to anything that needs attention. - -var DashboardNewsItem = React.createClass({ - render: function() { - return ( -
    -
    Run Docker in your network.
    - -
    - ); - } -}); - -module.exports = DashboardNewsItem; diff --git a/app/scripts/components/welcome/DashboardTabs.jsx b/app/scripts/components/welcome/DashboardTabs.jsx deleted file mode 100644 index ed2b80b5db..0000000000 --- a/app/scripts/components/welcome/DashboardTabs.jsx +++ /dev/null @@ -1,82 +0,0 @@ -'use strict'; - -import React, { PropTypes } from 'react'; -import classnames from 'classnames'; - -/* -
    -
    -
    - NO CONTENT HERE -
    -
    -
    - */ - -export default React.createClass({ - displayName: 'DashboardTabs', - propTypes: { - myrepos: React.PropTypes.element.isRequired, - contribs: React.PropTypes.element.isRequired, - starred: React.PropTypes.element.isRequired, - activity: React.PropTypes.element.isRequired - }, - getInitialState() { - return { - tabType: 'myRepos' - }; - }, - _getActiveTab() { - switch(this.state.tabType) { - case 'myRepos': - //Show grid of my repositories - return this.props.myrepos; - case 'contrib': - //Show grid of contributed repositories - return this.props.contribs; - case 'starred': - //Show grid of my starred repositories - return this.props.starred; - case 'activity': - //Show my activity feed - return this.props.activity; - } - }, - _getTitleClassNames(type) { - return classnames({ - 'active': this.state.tabType === type, - 'tab-title': true - }); - }, - _handleTabClick(type, evt) { - evt.preventDefault(); - this.setState({ - tabType: type - }); - }, - render() { - var activeTab = this._getActiveTab(); - - return ( -
    -
    -
      -
    • My Repositories
    • -
    • Contributed
    • -
    • Starred
    • -
    • Recent Activity
    • -
    -
    -
    -
    -
    -
    - {activeTab} -
    -
    -
    -
    -
    - ); - } -}); diff --git a/app/scripts/components/welcome/ForgotPass.css b/app/scripts/components/welcome/ForgotPass.css deleted file mode 100644 index 725901d3a6..0000000000 --- a/app/scripts/components/welcome/ForgotPass.css +++ /dev/null @@ -1,42 +0,0 @@ -@import "dux/css/colors"; -@import "dux/css/box"; - -.forgotPassPage { - background: var(--docker-dark); - height: 100%; - padding-top: 100px; -} - -.forgotPassSubmit { - margin-top: var(--default-margin); - display: flex; - flex-direction: column; - justify-content: center; -} - -.header { - text-align: center; -} - -.head { - color: var(--white); - font-size: 2rem; - font-weight: 200; -} - -.subHead { - color: var(--info-color); -} - -.subHeadLight { - color: #188bb3; -} - -.logo { - width: 90px; - height: 110px; -} - -.btn { - margin-top: 1rem; -} diff --git a/app/scripts/components/welcome/ForgotPass.jsx b/app/scripts/components/welcome/ForgotPass.jsx deleted file mode 100644 index 08de9a036b..0000000000 --- a/app/scripts/components/welcome/ForgotPass.jsx +++ /dev/null @@ -1,98 +0,0 @@ -'use strict'; - -import React from 'react'; -import { Link } from 'react-router'; -import Button from '@dux/element-button'; -import FancyInput from 'common/FancyInput'; -import forgotPasswordSubmit from '../../actions/forgotPasswordSubmit.js'; -import styles from './ForgotPass.css'; -var debug = require('debug')('Password Reset'); - -module.exports = React.createClass({ - contextTypes: { - executeAction: React.PropTypes.func.isRequired - }, - getInitialState: function() { - return { - email: '', - reset: false - }; - }, - onEmailChange: function(e) { - e.preventDefault(); - this.setState({email: e.target.value}); - }, - forgotPassSubmit: function(e) { - e.preventDefault(); - debug(this.state.email); - if (this.state.email) { - this.context.executeAction(forgotPasswordSubmit, {email: this.state.email}); - this.setState({reset: true}); - } - }, - transitionHome: function(e) { - e.preventDefault(); - this.props.history.pushState(null, '/'); - }, - render: function() { - var disabledState; - if (this.state.email) { - disabledState = false; - } else { - disabledState = true; - } - - if (!this.state.reset) { - return ( -
    -
    -
    - - docker logo - -
    Reset your password
    -
    Enter an email address associated with a Docker ID.
    -
    -
    -
    -
    -
    - -
    -
    -
    - We’ll send a password reset link to the Docker ID’s primary email address. -
    -
    - If you don't have access to your primary email address, contact Docker Support. -
    -
    - -
    -
    -
    -
    -
    - ); - } else { - return ( -
    -
    -
    - - docker logo - -
    Reset request sent!
    -

    Password reset link sent. This link is valid for 24 hours. If you don't see a password reset link, check your spam folder.

    - -
    -
    -
    - ); - } - } -}); diff --git a/app/scripts/components/welcome/LoginForm.css b/app/scripts/components/welcome/LoginForm.css deleted file mode 100644 index a0ccde463f..0000000000 --- a/app/scripts/components/welcome/LoginForm.css +++ /dev/null @@ -1,13 +0,0 @@ -.formWrapper { - display: inline-block; - width: 100%; - margin: 1.5rem 0; -} - -.buttonWrapper { - display: flex; - justify-content: space-between; - .help { - margin: 0 .75rem; - } -} diff --git a/app/scripts/components/welcome/LoginForm.jsx b/app/scripts/components/welcome/LoginForm.jsx deleted file mode 100644 index e37ce5fa78..0000000000 --- a/app/scripts/components/welcome/LoginForm.jsx +++ /dev/null @@ -1,83 +0,0 @@ -'use strict'; - -import React, { createClass, PropTypes } from 'react'; -import _ from 'lodash'; -import { Link } from 'react-router'; -import connectToStores from 'fluxible-addons-react/connectToStores'; -import Button from '@dux/element-button'; -var debug = require('debug')('LoginForm'); - -import onChange from '../../actions/common/onChangeUtil'; -import FancyInput from 'common/FancyInput'; -import LoginStore from '../../stores/LoginStore'; -import loginUpdateFormField from '../../actions/loginUpdateFormField'; -import styles from './LoginForm.css'; - -var LoginForm = createClass({ - displayName: 'LoginForm', - contextTypes: { - executeAction: React.PropTypes.func.isRequired - }, - propTypes: { - loginAction: PropTypes.func.isRequired - }, - _onChange: onChange({ - storePrefix: 'LOGIN' - }), - _handleSubmit(event) { - event.preventDefault(); - var loginPayload = this.props.values; - loginPayload.username = loginPayload.username.toLowerCase(); - this.context.executeAction(this.props.loginAction, loginPayload); - }, - render() { - const { fields, values, variant, includeHelp } = this.props; - - var globalFormError = null; - if(this.props.globalFormError) { - globalFormError =

    {this.props.globalFormError}

    ; - } - - let loginButton = (); - if(this.props.STATUS === 'ATTEMPTING_LOGIN') { - loginButton = (); - } - let help; - if (includeHelp) { - help = ( - Can't Login? - ); - } - return ( -
    - {globalFormError} - - -
    -
    - {help} -
    - {loginButton} -
    - - ); - } -}); - -export default connectToStores(LoginForm, - [LoginStore], - function({ getStore }, props){ - return getStore(LoginStore).getState(); - }); diff --git a/app/scripts/components/welcome/ResetPass.css b/app/scripts/components/welcome/ResetPass.css deleted file mode 100644 index 4c5e3cc180..0000000000 --- a/app/scripts/components/welcome/ResetPass.css +++ /dev/null @@ -1,39 +0,0 @@ -@import "dux/css/colors"; -@import "dux/css/box"; - -.resetPassPage { - background: var(--docker-dark); - height: 100%; - padding-top: 100px; -} - -.resetPassSubmit { - margin-top: var(--default-margin); - display: flex; - flex-direction: column; - justify-content: center; -} - -.header { - text-align: center; -} - -.head { - color: var(--white); - font-size: 2rem; - font-weight: 200; -} - -.subHead { - color: var(--info-color); -} - -.logo { - width: 90px; - height: 110px; -} - -.back { - margin-top: var(--default-margin); - text-align: center; -} diff --git a/app/scripts/components/welcome/ResetPass.jsx b/app/scripts/components/welcome/ResetPass.jsx deleted file mode 100644 index 49a6ecac95..0000000000 --- a/app/scripts/components/welcome/ResetPass.jsx +++ /dev/null @@ -1,152 +0,0 @@ -/** -MjA2MTU is a base64 encoding of the pk for the user account in hub - -dhiltgen [11:07 AM] -41y-d0f275462b1678b1aeca is a random generated token - **/ -'use strict'; - -import React, { PropTypes } from 'react'; -import connectToStores from 'fluxible-addons-react/connectToStores'; -import Button from '@dux/element-button'; -import FancyInput from 'common/FancyInput'; -import { Link } from 'react-router'; -import resetPasswordSubmit from '../../actions/resetPasswordSubmit.js'; -import ChangePasswordStore from '../../stores/ChangePasswordStore.js'; -import clearChangePasswordStore from '../../actions/clearChangePasswordStore'; -import styles from './ResetPass.css'; -var debug = require('debug')('Password Reset Confirmation: '); - -var ResetPassword = React.createClass({ - contextTypes: { - executeAction: PropTypes.func.isRequired - }, - PropTypes: { - changePassStore: PropTypes.shape({ - reset: PropTypes.bool.isRequired, - resetErr: PropTypes.bool.isRequired - }) - }, - getInitialState: function() { - return { - pass1: '', - pass2: '', - passErr: false - }; - }, - onPassChange: function(e) { - e.preventDefault(); - this.setState({pass1: e.target.value}); - }, - onConfirmChange: function(e) { - e.preventDefault(); - var confirm = e.target.value; - this.setState({pass2: confirm, passErr: false}); - }, - onErrorRetry: function(e) { - e.preventDefault(); - this.setState({ - pass1: '', - pass2: '' - }); - this.context.executeAction(clearChangePasswordStore); - }, - transitionLogin: function(e) { - e.preventDefault(); - this.props.history.pushState('/login/'); - }, - resetPassSubmit: function(e) { - e.preventDefault(); - debug('reset pass submit'); - if (this.state.pass1 === this.state.pass2) { - var { uidb64, reset_token } = this.props.params; - this.context.executeAction(resetPasswordSubmit, - {uidb64: uidb64, - reset_token: reset_token, - password_1: this.state.pass1, - password_2: this.state.pass2}); - this.setState({reset: true}); - } else { - this.setState({ passErr: true }); - } - }, - render: function() { - var disabledState = (this.state.passErr || !this.state.pass1); - - if (!this.props.changePassStore.reset && !this.props.changePassStore.hasErr) { - let error; - if (this.state.passErr) { - error = 'Make sure passwords are identical'; - } - return ( -
    -
    -
    -
    Password Reset
    -
    Enter your new password.
    -
    -
    -
    -
    -
    - - - - -
    -
    -
    - ); - } else if (this.props.changePassStore.hasErr) { - return ( -
    -
    -
    -
    There was an error!
    -
    Your password has not been reset, please try again
    -
    -
    -
    -
    - -
    -
    -
    - ); - } else { - return ( -
    -
    -
    -
    Your password has been reset
    -
    You may now login with your new password
    -
    -
    -
    -
    - -
    -
    -
    - ); - } - } -}); - -module.exports = connectToStores(ResetPassword, - [ChangePasswordStore], - function({ getStore }, props) { - return { - changePassStore: getStore(ChangePasswordStore).getState() - }; - }); diff --git a/app/scripts/components/welcome/SignupForm.css b/app/scripts/components/welcome/SignupForm.css deleted file mode 100644 index 8b4531edb7..0000000000 --- a/app/scripts/components/welcome/SignupForm.css +++ /dev/null @@ -1,27 +0,0 @@ -@import "dux/css/colors"; -@import "dux/css/box"; - -.submit { - padding: var(--default-margin); - button { - float: right; - } -} - -.subtext { - /** new color variable **/ - color: #b9eafa; -} - -.heading { - font-weight: 200; - color: var(--smoke); -} - -.success { - text-align: center; - margin-top: 5rem; - .heading { - font-size: 1.5rem; - } -} diff --git a/app/scripts/components/welcome/SignupForm.jsx b/app/scripts/components/welcome/SignupForm.jsx deleted file mode 100644 index 544020c812..0000000000 --- a/app/scripts/components/welcome/SignupForm.jsx +++ /dev/null @@ -1,105 +0,0 @@ -'use strict'; - -var debug = require('debug')('SignupForm'); - -import React, { PropTypes } from 'react'; -import _ from 'lodash'; -import connectToStores from 'fluxible-addons-react/connectToStores'; -import Button from '@dux/element-button'; - -import FA from 'common/FontAwesome'; -import FancyInput from 'common/FancyInput'; -import SignupStore from '../../stores/SignupStore'; -import attemptSignup from '../../actions/attemptSignup'; -import onChange from '../../actions/common/onChangeUtil'; -import { STATUS } from '../../stores/signupstore/Constants'; -import { handleFormErrors } from './_utils'; -import styles from './SignupForm.css'; - -var SignupForm = React.createClass({ - displayName: 'SignupForm', - contextTypes: { - executeAction: PropTypes.func.isRequired - }, - PropTypes: { - location: PropTypes.object - }, - _onSubmit(e) { - e.preventDefault(); - const { partner_value, redirect_value } = this.props.location.query; - var payload = this.props.values; - payload.username = payload.username.toLowerCase(); - if (partner_value) { - payload.partner_value = partner_value; - } - if (redirect_value) { - payload.redirect_value = redirect_value; - } - debug(payload); - this.context.executeAction(attemptSignup, payload); - }, - onChange: onChange({ - storePrefix: 'SIGNUP' - }), - render() { - debug(this.props); - if(this.props.STATUS === STATUS.SUCCESSFUL_SIGNUP) { - return ( -
    -
    Sweet! You're almost ready to go!
    -

    Please check your email to activate your account.

    - -
    - ); - } else { - return ( -
    -
    -
    -

    New to Docker?

    -

    Create your free Docker ID to get started.

    -
    -
    -
    -
    - -
    -
    - -
    -
    - -
    -
    - -
    -
    -
    - ); - } - } -}); - -export default connectToStores(SignupForm, - [SignupStore], - function({ getStore }, props) { - return getStore(SignupStore).getState(); - }); diff --git a/app/scripts/components/welcome/_utils.js b/app/scripts/components/welcome/_utils.js deleted file mode 100644 index 9ac9e62c89..0000000000 --- a/app/scripts/components/welcome/_utils.js +++ /dev/null @@ -1,43 +0,0 @@ -'use strict'; -import _ from 'lodash'; - -export function handleFormErrors(ctx, rawValueObject) { - - /** - * This function expects a ctx that has a `fields` - * object on the state, and a `_validate` function that - * returns an object `{ hasError: bool, error: string }` - * - * A valid component looks like: - * - * var Component = React.createClasse({ - * getInitialState() { - * return { - * fields: {} - * } - * }, - * _validate(key, value) { - * return { - * hasError: true, - * error: 'It\'s always wrong!' - * } - * } - * }) - */ - - // shortcut keys for State - let fields = ctx.state.fields || {}; - - // loop through `rawValueObject`, validating values - _.forIn(rawValueObject, function(value, key) { - let { hasError, error } = ctx._validate(key, value); - fields[key] = fields[key] || {}; - fields[key].hasError = hasError; - fields[key].error = error; - }, ctx); - - // queue up the new State - ctx.setState({ - fields - }); -} diff --git a/app/scripts/fluxibleRouter.js b/app/scripts/fluxibleRouter.js deleted file mode 100644 index 27194954eb..0000000000 --- a/app/scripts/fluxibleRouter.js +++ /dev/null @@ -1,112 +0,0 @@ -'use strict'; - -import React from 'react'; -import createHashHistory from 'history/lib/createHashHistory'; -import { createRoutes, useRoutes, RoutingContext } from 'react-router'; -import { routes } from 'react-router/lib/PropTypes'; -var debug = require('debug')('FluxibleRouter'); - -const { func, object } = React.PropTypes; - -/** - * A is a high-level API for automatically setting up - * a router that renders a with all the props - * it needs each time the URL changes. - */ -const FluxibleRouter = React.createClass({ - - propTypes: { - history: object, - children: routes, - routes, // alias for children - createElement: func, - onError: func, - onUpdate: func, - parseQueryString: func, - stringifyQuery: func - }, - - getInitialState() { - return { - firstRender: true, - location: null, - routes: null, - params: null, - components: null - }; - }, - - handleError(error) { - if (this.props.onError) { - this.props.onError.call(this, error); - } else { - // Throw errors by default so we don't silently swallow them! - throw error; // This error probably occurred in getChildRoutes or getComponents. - } - }, - - //============================================================================ - //ComponentWillMount is the only addition to this Router - //Needed in order to provide location/pathname to onUpdate from client.js - /* eslint-disable */ - componentWillMount() { - let { history, children, routes, parseQueryString, stringifyQuery } = this.props; - let createHistory = history ? () => history : createHashHistory; - - this.history = useRoutes(createHistory)({ - routes: createRoutes(routes || children), - parseQueryString, - stringifyQuery - }); - - this._unlisten = this.history.listen((error, state) => { - if (error) { - this.handleError(error); - } else { - //Rendering page after setting state, here to make sure the data is loaded `onUpdate` before we show the page - if (this.state.firstRender) { - this.setState({ - firstRender: false, - ...state - }); - } else { - var _this = this; - this.props.onUpdate(state, function () { - _this.setState(state); - }); - } - //End change in `onUpdate` related change to get client side rendering to behave like now - } - }); - }, - //============================================================================ - componentWillUnmount() { - if (this._unlisten) { - this._unlisten(); - } - }, - - render() { - let { location, routes, params, components } = this.state; - let { createElement } = this.props; - - if (location == null) { - return null; // Async match - } - - const routingProps = { - history: this.history, - createElement, - location, - routes, - params, - components - }; - - return ; - } - -}); -/*eslint-enable*/ - -export default FluxibleRouter; diff --git a/app/scripts/middlewares/sdk.js b/app/scripts/middlewares/sdk.js deleted file mode 100644 index 25606daf01..0000000000 --- a/app/scripts/middlewares/sdk.js +++ /dev/null @@ -1,93 +0,0 @@ -'use strict'; - -import { ATTEMPTING, ERROR, SUCCESS } from '../reduxConsts.js'; - -/** - * SDK middleware for automatically calling SDK actions and storing request - * statuses. - * - * Example: - * - * someAction({ tagName }) => ({ - * type: 'SOME_ACTION', - * meta: { - * sdk: { - * call: SDK.func, // SDK function to call - * args: ['args', 'for', 'func'] // Args to pass in to SDK function - * callback: (err, res) => ({}) // SDK callback - * statusKey: ['SOMETHING'] // Unique identifier for saving status in status reducer - * } - * } - * }) - * - * NOTE: `statusKey` should be an array; the first item should namespace - * the action type and the second item should be unique to the particular - * record. For example, when deleting a tag: - * - * statusKey: ['deleteRepoTag', 'latest'] - * - * Status will be stored in 'state.status.deleteRepoTag.latest'. - * - * NOTE: `args` does not include the SDK callback. - * - * For an example see actions/redux/tags.js - */ - -// dispatchStatus takes the action and status of an SDK request and returns -// a new action to Redux for tracking state. -// -// The 'data' parameter may be either the error or response body from the call -const dispatchStatus = (action, status, data) => ({ - type: `${action.type}_STATUS`, - payload: { - // Add in everything from the initial action payload. This lets us pass - // things such as namespaces and repo names to reducers which handle - // success states (when deleting a tag we need the namespace/repo/tag name) - ...action.payload, - statusKey: action.meta.sdk.statusKey, - status, - data - } -}); - -const sdkMiddleware = (store) => (next) => (action) => { - // If there's no meta.sdk in our action we don't need to process it with our - // middleware - if (typeof action !== 'object' || !action.meta || !action.meta.sdk) { - return next(action); - } - - const { call, args, callback, statusKey } = action.meta.sdk; - - if (!statusKey) { - throw new Error(`action.meta.sdk.statusKey is not defined for ${action.type}`); - } - - // Wrap the callback with a function that automatically dispatches error - // states for the SDK call to Redux. - // Why: this eliminates the need to create error and success dispatches for every - // action we create, and standardizes the format of all status dispatches - const wrapped = (err, res) => { - if (err) { - next(dispatchStatus(action, ERROR, err)); - // TODO: Dispatch that there was an error with this call. - } else { - next(dispatchStatus(action, SUCCESS, res)); - } - - // Ensure we call the original callback supplied for the SDK call. - if (callback) { - callback.apply(null, [err, res]); - } - }; - - // Dispatch that we're attempting the SDK call - next(dispatchStatus(action, ATTEMPTING)); - - // Make the SDK call here. - call.apply(null, [...args, wrapped]); - - return next(action); -}; - -export default sdkMiddleware; diff --git a/app/scripts/normalizers.js b/app/scripts/normalizers.js deleted file mode 100644 index 5b7ca86f53..0000000000 --- a/app/scripts/normalizers.js +++ /dev/null @@ -1,64 +0,0 @@ -'use strict'; - -import { Schema, arrayOf } from 'normalizr'; - -// Key repositories by the 'reponame' attribute instead of the 'key' field so -// that we can look up repositories by name in our reselect queries -const repository = new Schema('repository', { idAttribute: 'reponame' }); - -// The tag ID shouldn't be via key - it should be tagname -const tag = new Schema('tag', { - idAttribute: (entity) => { - // The natuilus API uses entity.tag as the tagname whereas hub uses - // entity.name - return (entity.tag) ? entity.tag : entity.name; - } -}); -// The scan ID shouldn't use the ID attribute; we need to be able to load -// any scan by checking the repo:tag combination -// TODO: Can we use the sha256sum here instead? -const scan = new Schema('scan', { - idAttribute: (entity) => `${entity.reponame}:${entity.tag}` -}); -// AKA layer -const blob = new Schema('blob', { idAttribute: 'index' }); -// Key components by names to version numbers as they have no unique ID -const component = new Schema('component', { - idAttribute: (entity) => `${entity.component}:${entity.version}` -}); -const vulnerability = new Schema('vulnerability', { idAttribute: 'cve' }); - - -// A repository has many tags -repository.define({ - tags: arrayOf(tag) -}); - -// A tag has many blobs and many scans -tag.define({ - blobs: arrayOf(blob), - // NOTE: Right now a tag can only have the latest scan. - // In the future we'll allow tags to have many scans - scans: arrayOf(scan) -}); - -scan.define({ - blobs: arrayOf(blob) -}); - -blob.define({ - components: arrayOf(component) -}); - -component.define({ - vulnerabilities: arrayOf(vulnerability) -}); - -export { - repository, - tag, - scan, - blob, - component, - vulnerability -}; diff --git a/app/scripts/records.js b/app/scripts/records.js deleted file mode 100644 index 9a603ddf48..0000000000 --- a/app/scripts/records.js +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; - -import { Record } from 'immutable'; - -// Records are the same as Maps but with accessors -// and can only have these defined fields set. -// USE: Instead of `shape`, in propTypes, we can use -// status: instanceOf(StatusRecord) -// -// NOTE: All records should be defined in this file -export const StatusRecord = new Record({ - status: '', - error: undefined -}); diff --git a/app/scripts/reducers/_utils.js b/app/scripts/reducers/_utils.js deleted file mode 100644 index b47be097cf..0000000000 --- a/app/scripts/reducers/_utils.js +++ /dev/null @@ -1,45 +0,0 @@ -'use strict'; - -import Immutable from 'immutable'; - -/** - * mergeEntity takes an entity name and merges it into the current state - * if found. - * - * This is used when your state contains a basic map of entities. - * - * Examples: - * - * mergeEntity('repository'): - * > merge action.payload.entities.repository into the current state - * - */ -export const mergeEntity = (entityType) => (state, action) => { - //TODO: Remove promises stuff with ready / error? - const { payload, ready, error } = action; - if (!ready || error || !payload.entities[entityType]) { - return state; - } - return state.merge(new Immutable.Map(payload.entities[entityType])); -}; - -export const mapToRecord = (map, Record) => { - let records = {}; - Object.keys(map).forEach(item => { records[item] = new Record(map[item]); }); - return records; -}; - -export const mergeEntities = (...entities) => (state, action) => { - - const { payload, ready, error } = action; - if (!ready || error) { - return state; - } - - return state.withMutations( map => { - entities.forEach( item => { - return map.mergeIn([item], new Immutable.Map(payload.entities[item])); - }); - return map; - }); -}; diff --git a/app/scripts/reducers/index.js b/app/scripts/reducers/index.js deleted file mode 100644 index fd33d66740..0000000000 --- a/app/scripts/reducers/index.js +++ /dev/null @@ -1,21 +0,0 @@ -'use strict'; - -// This combines all reducers from internal and external packages to create -// a redux store. -import { combineReducers } from 'redux'; -import repos from './repos'; -import scans from './scans'; -import status from './status'; -import tags from './tags'; -import { reducer as ui } from 'redux-ui'; - -export default combineReducers({ - // external reducers - ui, - // middleware reducers - // app-specific reducers - repos, - scans, - status, - tags -}); diff --git a/app/scripts/reducers/repos.js b/app/scripts/reducers/repos.js deleted file mode 100644 index d96a1fdcd1..0000000000 --- a/app/scripts/reducers/repos.js +++ /dev/null @@ -1,24 +0,0 @@ -'use strict'; - -import immutable from 'immutable'; -import { - RECEIVE_REPO -} from 'reduxConsts.js'; - -const defaultState = immutable.fromJS( - (typeof window !== 'undefined' && window.ReduxApp.repos) || {} -); - -const reducers = { - [RECEIVE_REPO]: (state, action) => { - return state.clear().merge(action.payload); - } -}; - -export default function(state = defaultState, action) { - const { type } = action; - if (typeof reducers[type] === 'function') { - return reducers[type](state, action); - } - return state; -} diff --git a/app/scripts/reducers/scans.js b/app/scripts/reducers/scans.js deleted file mode 100644 index e3074ad4e2..0000000000 --- a/app/scripts/reducers/scans.js +++ /dev/null @@ -1,26 +0,0 @@ -'use strict'; - -//modified from nautilus-ui/src/scripts/reducers/scans.js -import immutable from 'immutable'; -import { RECEIVE_SCANNED_TAG_DATA } from 'reduxConsts.js'; - -// Map of entities within each scan -const defaultState = immutable.fromJS( - (typeof window !== 'undefined' && window.ReduxApp.scans) || {} -); - -const reducers = { - [ RECEIVE_SCANNED_TAG_DATA ]: (state, action) => { - // Here we only ever save this current scan from the repoDetailsScannedTag - // action. This means that our scans reducer only ever has one scan - for - // the current page. - return state.clear().merge(action.payload.entities); - } -}; - -export default function(state = defaultState, action) { - if (typeof reducers[action.type] === 'function') { - return reducers[action.type](state, action); - } - return state; -} diff --git a/app/scripts/reducers/status.js b/app/scripts/reducers/status.js deleted file mode 100644 index 589187b83c..0000000000 --- a/app/scripts/reducers/status.js +++ /dev/null @@ -1,40 +0,0 @@ -'use strict'; - -import immutable, { Map } from 'immutable'; -import endsWith from 'lodash/string/endsWith'; -import isArray from 'lodash/lang/isArray'; -import { ERROR } from 'reduxConsts.js'; -import { StatusRecord } from 'records'; - -const defaultState = immutable.fromJS( - (typeof window !== 'undefined' && window.ReduxApp.status) || {} -); - -// This reducer listens for status updates from the SDK middleware -// and automatically stores the status within the `statusKey`. -// -// Example: If statusKey = ['deleteRepoTag', 'latest'] and status = 'ATTEMPTING', -// then state.status.deleteRepoTag.latest would be `ATTEMPTING`. -export default function(state = defaultState, action) { - // The status reducer only acts on actions ending in _STATUS. - // Ignore anything else and return the default state. - if (!endsWith(action.type, `_STATUS`)) { - return state; - } - - const { statusKey, status, data } = action.payload; - // We're using setIn, so if the statusKey is a string it needs - // to be wrapped in an array. - const sk = isArray(statusKey) ? statusKey : [statusKey]; - - if (status === ERROR) { - // Store the status and error response from the API within - // the state. - return state.setIn(sk, new StatusRecord({ status, error: data })); - } - - // On ATTEMPTING or SUCCESS we only want to store the status; - // storing action.payload.data would store the entire API response - // which our other reducers should be handling. - return state.setIn(sk, new StatusRecord({ status })); -} diff --git a/app/scripts/reducers/tags.js b/app/scripts/reducers/tags.js deleted file mode 100644 index cb933949cb..0000000000 --- a/app/scripts/reducers/tags.js +++ /dev/null @@ -1,91 +0,0 @@ -'use strict'; - -import immutable, { Map } from 'immutable'; -import { - RECEIVE_NAUTILUS_TAGS_FOR_REPOSITORY, - RECEIVE_TAGS_FOR_REPOSITORY, - DELETE_REPO_TAG, - SUCCESS -} from 'reduxConsts.js'; - -// Use the serialized redux data from the universal app loading if it exists. -// -// Shape of state: -// { -// 'namespace': { -// 'reponame': { -// tags: { -// 'latest': { ...data }, -// '14.04': { ...data }, -// ... -// }, -// result: [1, 2, 3, ...] // Array of repo IDs as ordered by hub API -// }, -// ... -// } -// } -// -// We use a nested map of namespace:reponame keys to a list of tags to ensure -// that we can merge the nautilus and hub API responses together without -// clearing inbetween. -const defaultState = immutable.fromJS( - (typeof window !== 'undefined' && window.ReduxApp.tags) || {} -); - -// mergeTagsIntoState accepts a namespace, reponame and normalized tag -// information and merges them into the given state. -// -// This is used when tags from the hub and nautilus API are loaded. -const mergeTagsIntoState = (state, action) => { - const { namespace, reponame, tags } = action.payload; - const path = [namespace, reponame, 'tags']; - const { tag } = tags.entities; - - return state.setIn( - path, - // Get the existing tags for this namespace/repo and merge the normalized - // tags recursively. If the namespace/repo pair doesn't exist this returns - // a new map. - // - // Merge function ensures that in the event of a conflict where the new value - // is undefined or null, it does not overwrite the existing value - state.getIn(path, new Map()).mergeDeep(tag) - ); -}; - -const maybeDeleteTag = (state, action) => { - if (action.payload.status === SUCCESS) { - // Remove this tag from our reducer. - const { namespace, reponame, tagName } = action.payload; - return state.withMutations(s => { - let result = s.getIn([namespace, reponame, 'result']); - result = result.filter(tag => tag !== tagName); - s.deleteIn([namespace, reponame, 'tags', tagName]); - s.setIn([namespace, reponame, 'result'], result); - return s; - }); - } - return state; -}; - -const reducers = { - [RECEIVE_TAGS_FOR_REPOSITORY]: (state, action) => { - // Add the result array of ordered tags from the hub API response, - // then merge tags in - const { namespace, reponame, tags } = action.payload; - const path = [namespace, reponame, 'result']; - const { result } = tags; - state = state.setIn(path, result); - return mergeTagsIntoState(state, action); - }, - [RECEIVE_NAUTILUS_TAGS_FOR_REPOSITORY]: mergeTagsIntoState, - [`${DELETE_REPO_TAG}_STATUS`]: maybeDeleteTag -}; - -export default function(state = defaultState, action) { - const { type } = action; - if (typeof reducers[type] === 'function') { - return reducers[type](state, action); - } - return state; -} diff --git a/app/scripts/reduxConsts.js b/app/scripts/reduxConsts.js deleted file mode 100644 index 6ee2ee93b4..0000000000 --- a/app/scripts/reduxConsts.js +++ /dev/null @@ -1,19 +0,0 @@ -'use strict'; -//Consts used for redux actions -const keyMirror = require('keymirror'); - -export default keyMirror({ - //repos - RECEIVE_REPO: null, - - //tags - DELETE_REPO_TAG: null, - RECEIVE_NAUTILUS_TAGS_FOR_REPOSITORY: null, - RECEIVE_SCANNED_TAG_DATA: null, - RECEIVE_TAGS_FOR_REPOSITORY: null, - - // statuses - ATTEMPTING: null, - ERROR: null, - SUCCESS: null -}); diff --git a/app/scripts/reduxStore.js b/app/scripts/reduxStore.js deleted file mode 100644 index a5aaf0748f..0000000000 --- a/app/scripts/reduxStore.js +++ /dev/null @@ -1,38 +0,0 @@ -'use strict'; - -// This creates a new redux store by importing our reducers and middleware -// and combining the two. -import { applyMiddleware, compose, createStore } from 'redux'; -import { Iterable } from 'immutable'; -import reducers from './reducers'; -import sdkMiddleware from './middlewares/sdk.js'; -import createLogger from 'redux-logger'; -const debug = require('debug')('hub:redux:logger'); - - -// Logger must always be the last middleware in applyMiddleware -const logger = createLogger({ - predicate: () => process.env.ENV === `development`, - // Use the debug import as our logger - logger: {log: debug}, - // Transform any immutableJS maps and iterables into their standard JS - // counterparts. This means you can inspect state within the console. - stateTransformer: (state) => { - let newState = {}; - Object.keys(state).forEach(key => { - newState[key] = state[key]; - if (Iterable.isIterable(state[key])) { - newState[key] = state[key].toJS(); - } - }); - return newState; - } -}); - -// Compose creates a new function by taking store enhancers (such as middleware -// and any external enhancers) which modifies the createStore function. -const enhancedCreateStore = compose( - applyMiddleware(sdkMiddleware, logger) -)(createStore); - -export default enhancedCreateStore; diff --git a/app/scripts/reduxUtils.js b/app/scripts/reduxUtils.js deleted file mode 100644 index dfba193f92..0000000000 --- a/app/scripts/reduxUtils.js +++ /dev/null @@ -1,27 +0,0 @@ -'use strict'; - -import { bindActionCreators } from 'redux'; -import React from 'react'; -import consts from './reduxConsts'; -/** - * Given an object of actions, this returns a thunk which returns all actions - * bound to dispatch using the same key names. - * - * This allows us to use `this.props.actions.$actionName` within components - * after being connected to Redux. - * - * Example: - * - * @connect(mapState, mapActions(Actions)) - * class Basic extends Component { - * // this.props.actions now containers all keys in Actions bound to dispatch - * } - * - */ -export let mapActions = (actions) => { - return (dispatch) => { return { actions: bindActionCreators(actions, dispatch) }; }; -}; - -export const mapToArray = (map) => { - return Object.keys(map).map(key => map[key]); -}; diff --git a/app/scripts/selectors/status.js b/app/scripts/selectors/status.js deleted file mode 100644 index 92b5d05e21..0000000000 --- a/app/scripts/selectors/status.js +++ /dev/null @@ -1,3 +0,0 @@ -'use strict'; - -export const getStatus = (state) => state.status; diff --git a/app/scripts/server.js b/app/scripts/server.js deleted file mode 100644 index edae4a4263..0000000000 --- a/app/scripts/server.js +++ /dev/null @@ -1,342 +0,0 @@ -'use strict'; -var debug = require('debug')('hub:server'); -var path = require('path'); -if(process.env.NEW_RELIC_LICENSE_KEY && process.env.NEW_RELIC_APP_NAME) { - process.env.NEW_RELIC_NO_CONFIG_FILE = true; - require('newrelic'); -} -var request = require('superagent'); -var bugsnag = require('bugsnag'); - -import pick from 'lodash/object/pick'; -import merge from 'lodash/object/merge'; -import React from 'react'; -import { match } from 'react-router'; -import RoutingContext from 'react-router/lib/RoutingContext'; -import bootstrapCreateElement from './bootstrapCreateElement'; -import app from './app'; -import cookieParser from 'cookie-parser'; -import bodyParser from 'body-parser'; -import express from 'express'; -import favicon from 'serve-favicon'; -import navigateAction from './actions/navigate'; -import serialize from 'serialize-javascript'; -import HtmlComponent from './components/Html'; - -import { Provider } from 'react-redux'; -import reducers from './reducers'; -import enhancedCreateStore from './reduxStore'; - -const server = express(); - -// don't broadcast we are using express -server.disable('x-powered-by'); - -// add bugsnag for asynch errors -if (process.env.BUGSNAG_API_KEY) { - bugsnag.register(process.env.BUGSNAG_API_KEY); - server.use(bugsnag.requestHandler); -} - -server.use(favicon('./favicon.ico')); -server.use('/public', express.static('./public')); - -// Add a trailing '/' to the path if there is none -server.use(function(req, res, next) { - if (req.path.substr(-1) !== '/' && req.path.length > 1) { - const query = req.url.slice(req.path.length); - res.redirect(301, req.path + '/' + query); - } else { - next(); - } -}); - -// standard health check endpoint -server.get('/_health', function (req, res) { - res.send('OK'); -}); - -(function(){ - const redirectToDockerPricing = function(req, res) { - res.redirect(301, 'https://www.docker.com/pricing'); - }; - - const redirectTrialToDockerStore = function(req, res) { - res.redirect(301, 'https://store.docker.com/bundles/docker-datacenter/purchase?plan=free-trial'); - }; - - server.get('/enterprise/trial/', redirectTrialToDockerStore); // redirect DDC Trial page to new Store page - server.get('/enterprise/', redirectToDockerPricing); - server.get('/subscriptions/', redirectToDockerPricing); -})(); - -server.get('/account/signup/', function(req, res, next) { - res.redirect('/'); -}); - -server.get('/account/forgot-password/', function(req, res, next) { - res.redirect('/reset-password/'); -}); - -server.get('/account/login/', function(req, res, next) { - res.redirect('/login/'); -}); - -server.get('/_/', function(req, res, next) { - res.redirect('/explore/'); -}); - -server.get('/official/', function(req, res, next) { - res.redirect('/explore/'); -}); - -server.get('/account/accounts/', function(req, res, next) { - res.redirect('/account/authorized-services/'); -}); - -server.get('/plans/', function(req, res, next) { - res.redirect('https://www.docker.com/pricing'); -}); - -server.get('/resend-email-confirmation/', function(req, res, next) { - res.redirect('/reset-password/'); -}); - -//There are two cases now: -//Case 1: No query parameter, just the token | Default activation, with confirmation_key sent to the `activate` endpoint -//Case 2: A `ref` query parameter is sent in the email validation URL | For partners, we send both key and ref to the activation endpoint -server.get('/account/confirm-email/:token', function(req, res, next) { - if(req.params.token) { - //If on activate, we get a query parameter called `ref` back from the email link, we store it and send it with the POST - const { ref } = req.query; - const { token } = req.params; - var activateRequestBody = { confirmation_key: token }; - if (ref) { - activateRequestBody.ref = ref; - } - request.post(`${process.env.REGISTRY_API_BASE_URL}/v2/users/activate/`) - .accept('application/json') - .send(activateRequestBody) - .end((err, apiRes) => { - if (err) { - debug('sign up error', err); - //Redirect to Login page for any error. - //We do not have generic error pages for 400s or 500s. - res.redirect('/login/'); - } else if (!apiRes || !apiRes.body) { - debug('api response is empty'); - //Redirect to Login page, when there is no response - //This is a care case that needs to be handled to make sure - //that it doesn't crash. See HUB-2094 for further details. - res.redirect('/login/'); - } else { - const { redirect_url } = apiRes.body; - if (redirect_url) { - //Redirect to the redirect URL returned by the API - res.redirect(redirect_url); - } else { - //Fallback redirect to Login page, when there is no redirect URL - res.redirect('/login/'); - } - } - }); - } else { - res.redirect('/login/'); - } -}); - -server.use(cookieParser()); -// 30 days in ms: 2592000000 -const expiry = 1000 * 60 * 60 * 24 * 30; // ms * s * m * h * days -const cookieOpts = { - domain: process.env.COOKIE_DOMAIN, - httpOnly: true, - secure: true, - maxAge: expiry, - expires: new Date(Date.now() + expiry) -}; -server.post('/attempt-login/', - bodyParser.json(), - function(req, res, next) { - res.cookie('token', req.body.jwt, cookieOpts); - res.end(); -}); - -const isLoggedIn = function(req) { - return !!(req.cookies && (req.cookies.token || req.cookies.jwt)); -}; - -server.get('/account/billing-plans/', function(req, res, next) { - if (!isLoggedIn(req)) { - return res.redirect('/billing-plans/'); - } - next(); -}); - -server.use(function(req, res, next) { - if (req.method !== 'GET') { - return next(); - } - if (isLoggedIn(req) && (['/login/', '/reset-password/', '/register/'].indexOf(req.path) !== -1 || req.path.indexOf('/account/password-reset-confirm') === 0)) { - res.redirect('/'); - } else if (!isLoggedIn(req) && req.path.indexOf('password-reset-confirm') === -1 && req.path.indexOf('/account/') === 0) { - res.redirect('/login/'); - } else { - next(); - } -}); - -server.post('/attempt-logout/', function(req, res, next) { - /** - * Delete the old cookie when we see it on logout. - */ - const oldCookieOpts = merge({}, - cookieOpts, - { - domain: '.docker.com' - }); - res.clearCookie('jwt', oldCookieOpts); - res.clearCookie('token', cookieOpts); - res.end(); -}); - -server.post('/oauth/github-attempt/', - bodyParser.json(), - function(req, res, next) { - res.cookie('ghOauthKey', req.body.ghk, cookieOpts); - res.end(); -}); - -server.post('/oauth/github-done/', function(req, res, next) { - res.clearCookie('ghOauthKey', cookieOpts); - res.end(); -}); - -server.use(function(req, res, next) { - // We may need to whitelist OPTIONS - if (req.method !== 'GET') { - res.end('This server does not respond to non-GET requests'); - } else { - next(); - } -}); - -server.use(function(req, res, next) { - // Within each request create a new Redux store from all of our reducers - // so that state is unique per request. - const store = enhancedCreateStore(reducers); - const context = app.createContext({ - reduxStore: store - }); - - debug('context:', context, context.reduxStore); - - //We get the Routes that have been created in the FluxibleComponent - const routes = app.getComponent(); - - const originalURL = req.originalUrl; - //We use the 'match' API to match the created routes with the current location (req.originalURL) - debug('matching route', originalURL); - match({ routes, location: originalURL }, (routerError, redirectLocation, renderProps) => { - // match uses createRoutes for history - //TODO: handle redirect, not found and errors - //TODO: need to handle generic 404s, 500s, 301s - //if (redirectLocation) { - //TODO: redirects need to be handled here - // res.redirect(301, redirectLocation.pathname + redirectLocation.search); - //} - //else if (error) { - //TODO: Render a nice 500 page with error displayed | HOPE THIS NEVER HAPPENS - // res.send(500, error.message); - //} - //else if (renderProps == null) { - //TODO: Probably render the 404 page here - // res.send(404, 'Not found'); - //} - - //If router errors out, bail - if (routerError) { - debug('Error in the Router', routerError); - res.end(routerError); - } - // whitelist cookies from express into renderProps - if (req.cookies) { - renderProps.cookies = pick(req.cookies, ['token', 'ghOauthKey']); - // For backward compat since we changed the cookie name - renderProps.cookies.jwt = renderProps.cookies.token; - } - - // Set the props, so the server knows if the user is logged in - if (renderProps.cookies.jwt) { - renderProps.JWT = renderProps.cookies.jwt; - } - - /** - * Execute navigate action to load data (we block the render until the data is - * completely loaded) - * You can see the actual server side render happens only after the - * `navigateAction` calls `done()` somewhere - */ - context.executeAction(navigateAction, renderProps, function() { - debug('Exposing context state', context); - debug('EXPOSING RENDER PROPS', renderProps); - let serializedApp; - let reduxApp; - try { - /* - NOTE: If we have any html or request responses saved in the store - - serialize will not be able to parse this and will crash the node server - */ - serializedApp = serialize(app.dehydrate(context)); - reduxApp = serialize(store.getState()); - } catch (err) { - debug('SERIALIZATION FAILURE: ', err); - } - const exposed = `window.App=${serializedApp}; window.ReduxApp = ${reduxApp};`; - debug('Rendering Application component into html'); - - // This is the Router 1.0.0 recommended way of doing server side rendering - // Also add a Provider around the routingContext for Redux. - // NOTE: We're defining our redux store above directly within the app context - const routingContext = ( - - - - ); - - debug('rendering html'); - var html = React.renderToStaticMarkup( - - ); - - res.send(html); - }); - }); -}); - -// add bugsnag for error handling middleware -if(process.env.BUGSNAG_API_KEY) { - server.use(bugsnag.errorHandler); -} - -// add generic error catching middleware so the server doesn't crash -server.use(function catchError(err, req, res, next) { - const message = err.stack ? err.stack.replace(/\n/g, '') : ''; - const errorLog = { - time: (new Date()).toISOString(), - service: 'hub-web-v2', - message - }; - console.error(errorLog); // eslint-disable-line no-console -}); - -const port = process.env.PORT || 3000; - -// Stop the server if the process terminates -const runningServer = server.listen(port, function onListen() { - process.on('exit', runningServer.close.bind(runningServer)); - debug('Listening on port ' + port); -}); diff --git a/app/scripts/stores/AccountInfoFormStore.js b/app/scripts/stores/AccountInfoFormStore.js deleted file mode 100644 index 0102a883c1..0000000000 --- a/app/scripts/stores/AccountInfoFormStore.js +++ /dev/null @@ -1,131 +0,0 @@ -'use strict'; - -var createStore = require('fluxible/addons/createStore'); -import { STATUS } from './common/Constants'; -var debug = require('debug')('AccountInfoFormStore'); -var _ = require('lodash'); - -var noErrorObj = { - hasError: false, - error: '' -}; - -export default createStore({ - storeName: 'AccountInfoFormStore', - handlers: { - ACCOUNT_INFO_CLEAR_FORM: '_clearForm', - ACCOUNT_INFO_UPDATE_FIELD_WITH_VALUE: '_updateFieldWithValue', - ACCOUNT_INFO_ATTEMPT_START: '_attemptStart', - ACCOUNT_INFO_BAD_REQUEST: '_badRequest', - ACCOUNT_INFO_SUCCESS: '_success', - ACCOUNT_INFO_STATUS_CLEAR: '_clearStatus', - ACCOUNT_INFO_FACEPALM: '_facepalm', - RECEIVE_USER: '_receiveUser' - }, - initialize() { - this.STATUS = STATUS.DEFAULT; - - this.fields = { - full_name: {}, - company: {}, - location: {}, - profile_url: {}, - gravatar_email: {} - }; - - this.values = { - full_name: '', - company: '', - location: '', - profile_url: '', - gravatar_email: '' - }; - }, - _receiveUser(user) { - debug('receive user', user); - this.values.full_name = user.full_name; - this.values.company = user.company; - this.values.location = user.location; - this.values.profile_url = user.profile_url; - this.values.gravatar_email = user.gravatar_email; - this.emitChange(); - }, - _facepalm() { - // this happens if things are screwed and we can't recover gracefully - this.STATUS = STATUS.FACEPALM; - this.emitChange(); - }, - _clearForm() { - this.initialize(); - this.emitChange(); - }, - _updateFieldWithValue({fieldKey, fieldValue}) { - this.STATUS = STATUS.DEFAULT; - this.values[fieldKey] = fieldValue; - this.emitChange(); - }, - _attemptStart() { - this.STATUS = STATUS.ATTEMPTING; - this.fields = { - full_name: {}, - company: {}, - location: {}, - profile_url: {}, - gravatar_email: {} - }; - this.emitChange(); - }, - _success() { - this.STATUS = STATUS.SUCCESSFUL; - this.emitChange(); - }, - _clearStatus() { - this.STATUS = STATUS.DEFAULT; - this.emitChange(); - }, - _badRequest(obj) { - /** - * This function expects keys which match the `this.fields` keys - * with an array of errors: - * - * { - * orgname: ['this field is required'] - * } - */ - let shouldEmitChange = false; - this.STATUS = STATUS.ERROR; - - // cycle through the possible form fields - this.fields = _.mapValues(this.fields, function (errorObject, key) { - if(_.has(obj, key)) { - shouldEmitChange = true; - return { - hasError: !!obj[key], - error: obj[key][0] - }; - } else { - return errorObject; - } - }); - - if(shouldEmitChange) { - this.emitChange(); - } - }, - getState() { - return { - fields: this.fields, - values: this.values, - STATUS: this.STATUS - }; - }, - dehydrate() { - return this.getState(); - }, - rehydrate(state) { - debug('rehydrate', state); - this.fields = state.fields; - this.values = state.values; - this.STATUS = state.STATUS; - } -}); diff --git a/app/scripts/stores/AccountSettingsLicensesStore.js b/app/scripts/stores/AccountSettingsLicensesStore.js deleted file mode 100644 index 40274dddb7..0000000000 --- a/app/scripts/stores/AccountSettingsLicensesStore.js +++ /dev/null @@ -1,41 +0,0 @@ -'use strict'; - -import createStore from 'fluxible/addons/createStore'; -var debug = require('debug')('AccountSettingsLicenseStore'); -import _ from 'lodash'; - -export default createStore({ - storeName: 'AccountSettingsLicensesStore', - handlers: { - RECEIVE_LICENSES: '_receiveLicenses' - }, - initialize: function() { - this.licenses = []; - this.attempting = true; - }, - _receiveLicenses: function(licenses) { - this.licenses = _.flatten(licenses); - this.attempting = false; - this.emitChange(); - }, - getAttempt: function() { - return this.attempting; - }, - setAttempt: function(flag) { - this.attempting = flag; - }, - getState: function() { - return { - licenses: this.licenses, - attempting: this.attempting - }; - }, - rehydrate: function(state) { - this.licenses = state.licenses; - this.attempting = state.attempting; - }, - dehydrate: function() { - return this.getState(); - } -}); - diff --git a/app/scripts/stores/AccountSettingsTeamsStore.js b/app/scripts/stores/AccountSettingsTeamsStore.js deleted file mode 100644 index 17b7d9a462..0000000000 --- a/app/scripts/stores/AccountSettingsTeamsStore.js +++ /dev/null @@ -1,29 +0,0 @@ -'use strict'; - -import createStore from 'fluxible/addons/createStore'; - -export default createStore({ - storeName: 'AccountSettingsTeamsStore', - handlers: { - RECEIVE_LICENSES: '_receiveLicenses' - }, - initialize() { - this.licenses = []; - }, - _receiveLicenses(res) { - this.licenses = res.results; - this.emitChange(); - }, - getState() { - return { - licenses: this.licenses - }; - }, - rehydrate(state) { - this.licenses = state.licenses; - }, - dehydrate() { - return this.getState(); - } -}); - diff --git a/app/scripts/stores/AddOrganizationStore.js b/app/scripts/stores/AddOrganizationStore.js deleted file mode 100644 index 7fd9986b2d..0000000000 --- a/app/scripts/stores/AddOrganizationStore.js +++ /dev/null @@ -1,115 +0,0 @@ -'use strict'; - -var createStore = require('fluxible/addons/createStore'); -import { STATUS } from './addorganizationstore/Constants'; -var debug = require('debug')('AddOrganizationStore'); -var _ = require('lodash'); - -var noErrorObj = { - hasError: false, - error: '' -}; - -export default createStore({ - storeName: 'AddOrganizationStore', - handlers: { - ADD_ORG_CLEAR_FORM: '_clearForm', - ADD_ORG_UPDATE_FIELD_WITH_VALUE: '_updateFieldWithValue', - ADD_ORG_ATTEMPT_START: '_addOrgAttemptStart', - ADD_ORG_BAD_REQUEST: '_badRequest', - ADD_ORG_SUCCESS: '_addOrgSuccess', - ADD_ORG_FACEPALM: '_facepalm', - CREATED_ORGANIZATION: '_clearForm', - CLEAR_ERRORS: '_clearErrors' - }, - initialize() { - this.STATUS = STATUS.DEFAULT; - - this.fields = { - gravatar_email: {}, - orgname: {}, - location: {}, - company: {}, - profile_url: {} - }; - - this.values = { - gravatar_email: '', - orgname: '', - location: '', - company: '', - profile_url: '' - }; - }, - _facepalm() { - // this happens if things are screwed and we can't recover gracefully - this.STATUS = STATUS.FACEPALM; - this.emitChange(); - }, - _clearForm() { - this.initialize(); - this.emitChange(); - }, - _updateFieldWithValue({fieldKey, fieldValue}) { - this._clearErrors(fieldKey); - this.values[fieldKey] = fieldValue; - this.emitChange(); - }, - _attemptStart() { - this.STATUS = STATUS.ATTEMPTING; - this.emitChange(); - }, - _signupSuccess() { - this.STATUS = STATUS.SUCCESSFUL_SIGNUP; - this.emitChange(); - }, - _clearErrors(fieldKey) { - if (this.STATUS === STATUS.BAD_REQUEST || this.STATUS === STATUS.FACEPALM) { - this.fields[fieldKey] = noErrorObj; - this.STATUS = STATUS.DEFAULT; - this.emitChange(); - } - }, - _badRequest(obj) { - /** - * This function expects keys which match the `this.fields` keys - * with an array of errors: - * - * { - * orgname: ['this field is required'] - * } - */ - let shouldEmitChange = false; - this.STATUS = STATUS.BAD_REQUEST; - - // cycle through the possible form fields - this.fields = _.mapValues(this.fields, function (errorObject, key) { - if(_.has(obj, key)) { - shouldEmitChange = true; - return { - hasError: !!obj[key], - error: obj[key][0] - }; - } else { - return errorObject; - } - }); - - if(shouldEmitChange) { - this.emitChange(); - } - }, - getState() { - return { - fields: this.fields, - values: this.values, - STATUS: this.STATUS - }; - }, - dehydrate() { - return {}; - }, - rehydrate(state) { - this.state = state; - } -}); diff --git a/app/scripts/stores/AddTrialLicenseStore.js b/app/scripts/stores/AddTrialLicenseStore.js deleted file mode 100644 index d448f26f50..0000000000 --- a/app/scripts/stores/AddTrialLicenseStore.js +++ /dev/null @@ -1,64 +0,0 @@ -'use strict'; - -import createStore from 'fluxible/addons/createStore'; -import { ATTEMPTING_DOWNLOAD, - BAD_REQUEST, - DEFAULT, - FACEPALM, - SUCCESSFUL_DOWNLOAD } from 'stores/addtriallicensestore/Constants'; -const debug = require('debug')('AddTrialLicenseStore'); - -export default createStore({ - storeName: 'AddTrialLicenseStore', - handlers: { - ATTEMPTING_LICENSE_DOWNLOAD_START: '_attemptingLicenseDownloadStart', - DOWNLOAD_LICENSE_CONTENT_BAD_REQUEST: '_downloadLicenseContentBadRequest', - DOWNLOAD_LICENSE_CONTENT_FACEPALM: '_facepalm', - RECEIVE_LICENSE_DOWNLOAD_CONTENT: '_receiveLicenseDownloadContent' - }, - initialize: function() { - this.error = ''; - this.STATUS = DEFAULT; - }, - _attemptingLicenseDownloadStart: function() { - this.STATUS = ATTEMPTING_DOWNLOAD; - this.error = ''; - this.emitChange(); - }, - _clearFeedbackStates: function() { - this.STATUS = DEFAULT; - this.error = ''; - this.emitChange(); - }, - _downloadLicenseContentBadRequest: function(err) { - this.STATUS = BAD_REQUEST; - this.error = err; - this.emitChange(); - }, - _facepalm: function(err) { - this.STATUS = FACEPALM; - debug(err); - this.error = 'Sorry, an error occured and your license is unavailable at this time.'; - this.emitChange(); - }, - _receiveLicenseDownloadContent: function() { - this.STATUS = SUCCESSFUL_DOWNLOAD; - this.error = ''; - setTimeout(this._clearFeedbackStates.bind(this), 5000); - this.emitChange(); - }, - getState: function() { - return { - error: this.error, - STATUS: this.STATUS - }; - }, - rehydrate: function(state) { - this.error = state.error; - this.STATUS = state.STATUS; - }, - dehydrate: function() { - return this.getState(); - } -}); - diff --git a/app/scripts/stores/AddWebhookFormStore.js b/app/scripts/stores/AddWebhookFormStore.js deleted file mode 100644 index e315647c2f..0000000000 --- a/app/scripts/stores/AddWebhookFormStore.js +++ /dev/null @@ -1,86 +0,0 @@ -'use strict'; -import createStore from 'fluxible/addons/createStore'; -import last from 'lodash/array/last'; -import { - DEFAULT, - ATTEMPTING, - ERROR -} from './addwebhookformstore/Constants'; -const debug = require('debug')('AddWebhookFormStore'); - -var WebhooksSettingsStore = createStore({ - storeName: 'AddWebhookFormStore', - handlers: { - RECEIVE_WEBHOOKS: '_receiveWebhooks', - ADD_WEBHOOK_CLEAR: '_clear', - ADD_WEBHOOK_START: '_start', - ADD_WEBHOOK_RESET: '_reset', - ADD_WEBHOOK_SUCCESS: '_success', - ADD_WEBHOOK_NEW_HOOK: '_newHook', - ADD_WEBHOOK_REMOVE_HOOK: '_removeHook', - ADD_WEBHOOK_ERROR: '_error', - ADD_WEBHOOK_MISSING_ARGS: '_handleMissingArgs', - ADD_WEBHOOK_VALIDATION_ERRORS: '_handleValidationErrors' - }, - initialize() { - /** - * hookFields represent each `input` pairing that is - * rendered. They contain no data about the content of the input - */ - this.hookFields = [1]; - this.STATUS = DEFAULT; - this.serverErrors = {}; - }, - _error(args) { - // TODO: handle generic error - this.STATUS = ERROR; - this.serverErrors = args; - this.emitChange(); - }, - _handleMissingArgs(args) { - debug('missing args: ', args); - this.serverErrors = args; - }, - _handleValidationErrors(args) { - debug('validation errors: ', args); - this.serverErrors = args; - }, - _newHook() { - const { hookFields: fields } = this; - this.hookFields = fields.concat(last(fields) + 1); - this.emitChange(); - }, - _reset() { - this.initialize(); - this.emitChange(); - }, - _start() { - this.STATUS = ATTEMPTING; - this.emitChange(); - }, - _success() {}, - _receiveWebhooks(payload) { - debug(payload); - this.pipelines = payload.results; - this.emitChange(); - }, - _receiveAddWebhookErrors(error) { - }, - getState() { - return { - STATUS: this.STATUS, - pipelines: this.pipelines, - hookFields: this.hookFields, - serverErrors: this.serverErrors - }; - }, - dehydrate() { - return this.getState(); - }, - rehydrate(state) { - this.pipelines = state.pipelines; - this.hookFields = state.hookFields; - } -}); - -module.exports = WebhooksSettingsStore; diff --git a/app/scripts/stores/ApplicationStore.js b/app/scripts/stores/ApplicationStore.js deleted file mode 100644 index 6b4ea63eb6..0000000000 --- a/app/scripts/stores/ApplicationStore.js +++ /dev/null @@ -1,33 +0,0 @@ -'use strict'; -const createStore = require('fluxible/addons/createStore'); - -var ApplicationStore = createStore({ - storeName: 'ApplicationStore', - handlers: { - CHANGE_ROUTE: 'handleNavigate' - }, - initialize: function() { - this.currentRoute = null; - }, - handleNavigate: function(route) { - if (this.currentRoute && route.path === this.currentRoute.path) { - return; - } - - this.currentRoute = route; - this.emitChange(); - }, - getState: function() { - return { - route: this.currentRoute - }; - }, - dehydrate: function() { - return this.getState(); - }, - rehydrate: function(state) { - this.currentRoute = state.route; - } -}); - -module.exports = ApplicationStore; diff --git a/app/scripts/stores/AutoBuildSettingsStore.js b/app/scripts/stores/AutoBuildSettingsStore.js deleted file mode 100644 index 117c3c63e1..0000000000 --- a/app/scripts/stores/AutoBuildSettingsStore.js +++ /dev/null @@ -1,235 +0,0 @@ -'use strict'; -import createStore from 'fluxible/addons/createStore'; -import sortBy from 'lodash/collection/sortBy'; -import { STATUS } from './common/Constants'; - -var AutoBuildSettingsStore = createStore({ - storeName: 'AutoBuildSettingsStore', - handlers: { - AB_TRIGGER_BY_TAG_ERROR: '_triggerByTagError', - AB_TRIGGER_BY_TAG_SUCCESS: '_triggerByTagSuccess', - ATTEMPT_TRIGGER_BY_TAG: '_triggerByTagAttempt', - RECEIVE_AUTOBUILD_SETTINGS: '_receiveAutoBuildSettings', - UPDATE_AUTO_BUILD_SETTINGS: '_updateFields', - RECEIVE_AUTOBUILD_LINKS: '_receiveAutoBuildLinks', - LINK_AUTOBUILD_ERROR: '_linkAutoBuildError', - LINK_AUTOBUILD_SUCCESS: '_linkAutoBuildSuccess', - UPDATE_AUTOBUILD_PUSH_TRIGGER_ITEM: '_updateBuildTriggerItem', - UPDATE_AUTOBUILD_NEW_TAG_ITEM: '_updateBuildNewTagItem', - DELETE_AUTOBUILD_PUSH_TRIGGER_ITEM: '_deleteBuildTriggerItem', - DELETE_AUTOBUILD_NEW_TAG_ITEM: '_deleteBuildsNewTagItem', - ADD_AUTOBUILD_PUSH_TRIGGER_ITEM: '_addBuildTriggerItem', - SAVE_BUILD_TAGS_SUCCESS: '_saveTagsSuccess', - SAVE_BUILD_TAGS_ERROR: '_saveTagsError', - RECEIVE_TRIGGER_STATUS: '_receiveTriggerStatus', - RECEIVE_TRIGGER_LOGS: '_receiveTriggerLogs' - }, - initialize: function() { - this.autoBuildStore = { - repository: '', - build_name: '', - provider: '', - source_url: '', - docker_url: '', - repo_web_url: '', - repo_type: '', - active: false, - deleted: false, - repo_id: '', - build_tags: [], - deploykey: null, - hook_id: '' - }; - this.newTags = []; - this.validations = { - buildTags: { - hasError: false, - success: false, - errors: [] - }, - links: { - hasError: false, - success: false, - error: '' - }, - trigger: { - success: '', - error: '' - } - }; - this.autoBuildBlankSlate = {}; - this.autoBuildLinks = []; - this.triggerLinkForm = { - repoName: '' - }; - this.triggerStatus = { - token: '', - trigger_url: '', - active: false - }; - this.triggerLogs = []; - this.STATUS = STATUS.DEFAULT; - }, - _resetValidations: function(field) { - if (field === 'buildTags') { - this.validations.buildTags = { - hasError: false, - success: false, - errors: [] - }; - } else { - this.validations[field] = { - hasError: false, - success: false, - error: '' - }; - } - this.emitChange(); - }, - _receiveAutoBuildSettings: function(payload) { - this.autoBuildStore = payload; - const sorted = sortBy(payload.build_tags, 'id'); // ensure build_tags received are sorted - this.autoBuildStore.build_tags = sorted; - this.autoBuildBlankSlate = this.autoBuildStore; - this.emitChange(); - }, - _receiveAutoBuildLinks: function(payload) { - this.autoBuildLinks = payload; - this.triggerLinkForm.repoName = ''; - this.emitChange(); - }, - _linkAutoBuildError: function() { - this.validations.links = { - hasError: true, - success: false, - error: 'Failed to link this repository to your Automated Build.' - }; - this.emitChange(); - }, - _linkAutoBuildSuccess: function() { - this.validations.links = { - hasError: false, - success: true, - error: '' - }; - this.emitChange(); - }, - _addBuildTriggerItem: function() { - this.newTags.push({ - name: '', - dockerfile_location: '', - source_name: '', - source_type: 'Branch', - isNew: true - }); - this._resetValidations('buildTags'); - this.emitChange(); - }, - _deleteBuildTriggerItem: function(index) { - this.autoBuildStore.build_tags[index].toDelete = true; - this._resetValidations('buildTags'); - this.emitChange(); - }, - _deleteBuildsNewTagItem: function(index) { - this.newTags[index].toDelete = true; - this._resetValidations('buildTags'); - this.emitChange(); - }, - _updateBuildTriggerItem: function({ index, fieldkey, value}) { - this.autoBuildStore.build_tags[index][fieldkey] = value; - this._resetValidations('buildTags'); - this.emitChange(); - }, - _updateBuildNewTagItem: function({ index, fieldkey, value}) { - this.newTags[index][fieldkey] = value; - this._resetValidations('buildTags'); - this.emitChange(); - }, - _updateFields: function({ field, key, value }) { - this[field][key] = value; - if (field === 'triggerLinkForm') { - this._resetValidations('links'); - } - this.emitChange(); - }, - _saveTagsSuccess: function() { - this.validations.buildTags = { - success: true, - hasError: false, - errors: [] - }; - this.newTags = []; - setTimeout(this._resetValidations.bind(this), 3000, 'buildTags'); - this.emitChange(); - }, - _saveTagsError: function(tag) { - let currentErrors = this.validations.buildTags.errors; - if (tag.error) { - currentErrors.push(`${tag.name}: ${tag.error}`); - } - this.validations.buildTags = { - success: false, - hasError: true, - errors: currentErrors - }; - this.emitChange(); - }, - _receiveTriggerStatus: function(triggerStatus){ - this.triggerStatus = triggerStatus; - this.emitChange(); - }, - _receiveTriggerLogs: function(triggerLogs) { - this.triggerLogs = triggerLogs; - this.emitChange(); - }, - _triggerByTagAttempt: function() { - this.STATUS = STATUS.ATTEMPTING; - this.emitChange(); - }, - _triggerByTagError: function(err) { - this.validations.trigger.error = err; - setTimeout(this._clearTriggerStatus.bind(this), 5000); - this.emitChange(); - }, - _triggerByTagSuccess: function(success) { - this.validations.trigger.success = success; - setTimeout(this._clearTriggerStatus.bind(this), 5000); - this.emitChange(); - }, - _clearTriggerStatus: function() { - this.validations.trigger.success = ''; - this.validations.trigger.error = ''; - this.STATUS = STATUS.DEFAULT; - this.emitChange(); - }, - getState: function() { - return { - autoBuildStore: this.autoBuildStore, - autoBuildBlankSlate: this.autoBuildBlankSlate, - autoBuildLinks: this.autoBuildLinks, - autoTriggerForm: this.autoTriggerForm, - triggerStatus: this.triggerStatus, - triggerLinkForm: this.triggerLinkForm, - triggerLogs: this.triggerLogs, - validations: this.validations, - newTags: this.newTags, - STATUS: this.STATUS - }; - }, - dehydrate: function() { - return this.getState(); - }, - rehydrate: function(state) { - this.autoBuildStore = state.autoBuildStore; - this.autoBuildLinks = state.autoBuildLinks; - this.autoTriggerForm = state.autoTriggerForm; - this.triggerStatus = state.triggerStatus; - this.triggerLinkForm = state.triggerLinkForm; - this.triggerLogs = state.triggerLogs; - this.validations = state.validations; - this.newTags = state.newTags; - this.STATUS = state.STATUS; - } -}); - -module.exports = AutoBuildSettingsStore; diff --git a/app/scripts/stores/AutobuildConfigStore.js b/app/scripts/stores/AutobuildConfigStore.js deleted file mode 100644 index b4f8190d18..0000000000 --- a/app/scripts/stores/AutobuildConfigStore.js +++ /dev/null @@ -1,134 +0,0 @@ -'use strict'; -import createStore from 'fluxible/addons/createStore'; -import forEach from 'lodash/collection/forEach'; -import isString from 'lodash/lang/isString'; -import { STATUS } from './common/Constants'; - -var AutobuildConfigStore = createStore({ - storeName: 'AutobuildConfigStore', - handlers: { - ATTEMPTING_AUTOBUILD_CREATION: '_autobuildCreateAttempt', - AUTOBUILD_ERROR: '_autobuildConfigError', - AUTOBUILD_BAD_REQUEST: '_autobuildBadRequest', - AUTOBUILD_UNAUTHORIZED: '_autobuildUnauthorized', - AUTOBUILD_SUCCESS: '_autobuildSuccess', - AUTOBUILD_FORM_UPDATE_FIELD_WITH_VALUE: '_updateFormField', - SELECT_SOURCE_REPO: '_selectSourceRepo', - CLEAR_AUTOBUILD_FORM_ERRORS: '_clearErrorStates', - INITIALIZE_AUTOBUILD_FORM: '_initializeForm', - RECEIVE_PRIVATE_REPOSTATS: '_getPrivateDefault' - }, - initialize: function() { - this.name = ''; - this.namespace = ''; - this.description = ''; - this.isPrivate = 'public'; - this.provider = ''; - this.sourceRepoName = ''; - this.active = true; - this.error = {}; - this.success = ''; - this.STATUS = STATUS.DEFAULT; - }, - _autobuildConfigError: function(err) { - //TODO: handle config error here - this.error.general = 'An error occurred while configuring your automated build. Please try again later.'; - setTimeout(this._clearErrorStates.bind(this), 5000); - this.emitChange(); - }, - _autobuildCreateAttempt: function() { - this.error.buildTags = ''; - this.STATUS = STATUS.ATTEMPTING; - this.emitChange(); - }, - _autobuildBadRequest: function(err) { - forEach(err, (val, key) => { - this.error[key] = val.toString(); - }); - - //For build_tags, make it a global error - if (err.build_tags) { - this.error.buildTags = 'Invalid character(s) provided in build tags configuration. Please check your input.'; - } - - if (err.detail || isString(err)) { - this.error.detail = err.detail || err; - } - - this.STATUS = STATUS.DEFAULT; - this.emitChange(); - }, - _autobuildUnauthorized: function(err) { - this.error.general = 'You have no permissions to create an automated build in this namespace.'; - setTimeout(this._clearErrorStates.bind(this), 5000); - this.STATUS = STATUS.DEFAULT; - this.emitChange(); - }, - _autobuildSuccess: function(err) { - this.success = 'Successfully configured an automated build repository.'; - this.STATUS = STATUS.SUCCESSFUL; - setTimeout(this._clearErrorStates.bind(this), 5000); - this.emitChange(); - }, - _clearErrorStates: function() { - this.error = {}; - this.success = ''; - this.STATUS = STATUS.DEFAULT; - this.emitChange(); - }, - _getPrivateDefault: function(stats) { - this.isPrivate = stats.default_repo_visibility; - }, - _initializeForm: function({ name, namespace }) { - this.name = name; - this.namespace = namespace; - this.description = ''; - }, - _selectSourceRepo: function(repo) { - this.sourceRepoName = repo.full_name; - this.emitChange(); - }, - _updateFormField: function({fieldKey, fieldValue}) { - this[fieldKey] = fieldValue; - if (fieldKey === 'name' || fieldKey === 'namespace') { - delete this.error.dockerhub_repo_name; - } - if (fieldKey === 'description') { - delete this.error.description; - } - delete this.error.detail; - this.STATUS = STATUS.DEFAULT; - this.emitChange(); - }, - getState: function() { - return { - name: this.name, - namespace: this.namespace, - description: this.description, - isPrivate: this.isPrivate, - provider: this.provider, - sourceRepoName: this.sourceRepoName, - active: this.active, - error: this.error, - success: this.success, - STATUS: this.STATUS - }; - }, - dehydrate: function() { - return this.getState(); - }, - rehydrate: function(state) { - this.name = state.name; - this.namespace = state.namespace; - this.description = state.description; - this.isPrivate = state.isPrivate; - this.provider = state.provider; - this.sourceRepoName = state.sourceRepoName; - this.active = state.active; - this.error = state.error; - this.success = state.success; - this.STATUS = state.STATUS; - } -}); - -module.exports = AutobuildConfigStore; diff --git a/app/scripts/stores/AutobuildSourceRepositoriesStore.js b/app/scripts/stores/AutobuildSourceRepositoriesStore.js deleted file mode 100644 index 2b2448afb4..0000000000 --- a/app/scripts/stores/AutobuildSourceRepositoriesStore.js +++ /dev/null @@ -1,46 +0,0 @@ -'use strict'; -import createStore from 'fluxible/addons/createStore'; -import _ from 'lodash'; - -var AutobuildSourceRepositoriesStore = createStore({ - storeName: 'AutobuildSourceRepositoriesStore', - handlers: { - RECEIVE_LINKED_REPO_SOURCES: '_receiveLinkedRepos', - LINKED_REPO_SOURCES_ERROR: '_linkedReposError', - SET_LINKED_REPO_TYPE: '_setType' - }, - initialize: function() { - this.repos = []; - this.type = ''; - this.error = ''; - }, - _setType: function(type) { - this.type = type; - this.emitChange(); - }, - _receiveLinkedRepos: function(linkedRepos) { - this.repos = linkedRepos; - this.emitChange(); - }, - _linkedReposError: function(err) { - this.error = 'Please check if you have any repositories setup on ' + this.type + '.'; - this.emitChange(); - }, - getState: function() { - return { - repos: this.repos, - type: this.type, - error: this.error - }; - }, - dehydrate: function() { - return this.getState(); - }, - rehydrate: function(state) { - this.repos = state.repos; - this.type = state.type; - this.error = state.error; - } -}); - -module.exports = AutobuildSourceRepositoriesStore; diff --git a/app/scripts/stores/AutobuildStore.js b/app/scripts/stores/AutobuildStore.js deleted file mode 100644 index b012f99a60..0000000000 --- a/app/scripts/stores/AutobuildStore.js +++ /dev/null @@ -1,54 +0,0 @@ -'use strict'; -import createStore from 'fluxible/addons/createStore'; -import _ from 'lodash'; - -var AutobuildStore = createStore({ - storeName: 'AutobuildStore', - handlers: { - RECEIVE_SOURCE_REPOS: '_receiveSourceRepos', - RECEIVE_SOURCE_ACCOUNTS: '_receiveSourceAccount' - }, - initialize: function() { - this.githubAccount = null; - this.githubRepos = []; - this.bitbucketAccount = null; - this.bitbucketRepos = []; - this.gitlabAccount = null; - this.gitlabRepos = []; - }, - _receiveSourceRepos: function(res) { - this.githubRepos = res.github.detail ? [] : res.github; - this.bitbucketRepos = res.bitbucket.detail ? [] : res.bitbucket; - this.gitlabRepos = res.gitlab.detail ? [] : res.gitlab; - this.emitChange(); - }, - _receiveSourceAccount: function(res) { - this.githubAccount = res.github.detail ? null : res.github; - this.bitbucketAccount = res.bitbucket.detail ? null : res.bitbucket; - this.gitlabAccount = res.gitlab.detail ? null : res.gitlab; - this.emitChange(); - }, - getState: function() { - return { - githubAccount: this.githubAccount, - githubRepos: this.githubRepos, - bitbucketAccount: this.bitbucketAccount, - bitbucketRepos: this.bitbucketRepos, - gitlabAccount: this.gitlabAccount, - gitlabRepos: this.gitlabRepos - }; - }, - dehydrate: function() { - return this.getState(); - }, - rehydrate: function(state) { - this.githubAccount = state.githubAccount; - this.githubRepos = state.githubRepos; - this.bitbucketAccount = state.bitbucketAccount; - this.bitbucketRepos = state.bitbucketRepos; - this.gitlabAccount = state.gitlabAccount; - this.gitlabRepos = state.gitlabRepos; - } -}); - -module.exports = AutobuildStore; diff --git a/app/scripts/stores/AutobuildTagsStore.js b/app/scripts/stores/AutobuildTagsStore.js deleted file mode 100644 index 56629f1ca7..0000000000 --- a/app/scripts/stores/AutobuildTagsStore.js +++ /dev/null @@ -1,50 +0,0 @@ -'use strict'; -import createStore from 'fluxible/addons/createStore'; -import _ from 'lodash'; - -var AutobuildTagsStore = createStore({ - storeName: 'AutobuildTagsStore', - handlers: { - AUTOBUILD_TAGS_ERROR: '_autobuildTagsError' - }, - initialize: function() { - //tags is an array of tag - //{ dockerfile_location, source_type['Tag' or 'Branch'], source_name[eg. master] } - this.tags = []; - }, - addTag: function(tag) { - //tag - //{ - // id: 'row-1' - // sourceName: 'master' - // fileLocation: '/' - // buildTag: 'latest', - // sourceType: 'Branch' - //} - this.tags.push(tag); - }, - removeTag: function(id) { - _.remove(this.tags, function(tag) { - return (tag.id === id); - }); - }, - setTagState: function(id, state) { - var tagToUpdate = _.find(this.tags, function(tag) { - return tag.id === id; - }); - _.merge(tagToUpdate, state); - }, - getState: function() { - return { - tags: this.tags - }; - }, - dehydrate: function() { - return this.getState(); - }, - rehydrate: function(state) { - this.tags = state.tags; - } -}); - -module.exports = AutobuildTagsStore; diff --git a/app/scripts/stores/AutobuildTriggerByTagStore.js b/app/scripts/stores/AutobuildTriggerByTagStore.js deleted file mode 100644 index b3c16f81a1..0000000000 --- a/app/scripts/stores/AutobuildTriggerByTagStore.js +++ /dev/null @@ -1,91 +0,0 @@ -'use strict'; -import createStore from 'fluxible/addons/createStore'; -import findIndex from 'lodash/array/findIndex'; -import map from 'lodash/collection/map'; -import { STATUS } from './common/Constants'; - -var AutobuildTriggerByTagStore = createStore({ - storeName: 'AutobuildTriggerByTagStore', - handlers: { - INITIALIZE_AB_TRIGGERS: '_initTriggers', - AB_TRIGGER_BY_TAG_ERROR: '_triggerByTagError', - AB_TRIGGER_BY_TAG_SUCCESS: '_triggerByTagSuccess', - ATTEMPT_TRIGGER_BY_TAG: '_triggerByTagAttempt' - }, - initialize: function() { - this.triggers = []; - this.tagStatuses = []; - }, - _initTriggers: function(tags) { - //on load of the build settings page - this.initialize(); - - this.triggers = map(tags, (tag) => { - return { - id: tag.id, - success: '', - error: '' - }; - }); - - this.tagStatuses = map(tags, (tag) => { - return { - id: tag.id, - status: STATUS.DEFAULT - }; - }); - this.emitChange(); - }, - _findIndices: function(id) { - const statusIndex = findIndex(this.tagStatuses, (s) => { - return s.id === id; - }); - const triggerIndex = findIndex(this.triggers, (t) => { - return t.id === id; - }); - return {statusIndex, triggerIndex}; - }, - _triggerByTagAttempt: function(id) { - const {statusIndex, triggerIndex} = this._findIndices(id); - this.tagStatuses[statusIndex].status = STATUS.ATTEMPTING; - this.triggers[triggerIndex].error = ''; - this.triggers[triggerIndex].success = ''; - this.emitChange(); - }, - _triggerByTagError: function(errObj) { - const {id, error} = errObj; - const { triggerIndex } = this._findIndices(id); - this.triggers[triggerIndex].error = error; - setTimeout(this._clearTriggerStatus.bind(this, id), 3000); - this.emitChange(); - }, - _triggerByTagSuccess: function(successObj) { - const {id, success} = successObj; - const { triggerIndex } = this._findIndices(id); - this.triggers[triggerIndex].success = success; - setTimeout(this._clearTriggerStatus.bind(this, id), 3000); - this.emitChange(); - }, - _clearTriggerStatus: function(id) { - const {statusIndex, triggerIndex} = this._findIndices(id); - this.tagStatuses[statusIndex].status = STATUS.DEFAULT; - this.triggers[triggerIndex].error = ''; - this.triggers[triggerIndex].success = ''; - this.emitChange(); - }, - getState: function() { - return { - triggers: this.triggers, - tagStatuses: this.tagStatuses - }; - }, - dehydrate: function() { - return this.getState(); - }, - rehydrate: function(state) { - this.triggers = state.triggers; - this.tagStatuses = state.tagStatuses; - } -}); - -module.exports = AutobuildTriggerByTagStore; diff --git a/app/scripts/stores/BillingInfoFormStore.js b/app/scripts/stores/BillingInfoFormStore.js deleted file mode 100644 index 19473595c5..0000000000 --- a/app/scripts/stores/BillingInfoFormStore.js +++ /dev/null @@ -1,184 +0,0 @@ -'use strict'; -import createStore from 'fluxible/addons/createStore'; -import _ from 'lodash'; -import { STATUS } from './billingformstore/Constants'; -var debug = require('debug')('STORE::BillingInfoFormStore'); - -var BillingInfoFormStore = createStore({ - storeName: 'BillingInfoFormStore', - handlers: { - BILLING_ACCOUNT_EXISTS: '_accountExists', - BILLING_INFO_EXISTS: '_billingInfoExists', - BILLING_ERRORS: '_updateErrors', - BILLING_INFO_UPDATE_FIELD_WITH_VALUE: '_updateBillingInfoForm', - BILLING_SUBMIT_ERROR: '_submitErrors', - BILLING_SUBMIT_START: '_submitStart', - BILLING_SUBMIT_SUCCESS: '_submitSuccess', - CLEAR_BILLING_FORM: '_clearBillingForm', - GET_RECURLY_ERROR: '_updateRecurlyErrors', - LOGOUT: '_clearStore', - RECEIVE_BILLING_INFO: '_receiveBillingInfo', - UPDATE_COUPON_VALUE: '_updateCouponValue' - }, - initialize: function() { - var D = new Date(); - var month = 1; - var year = D.getFullYear(); - this.billforwardId = ''; - this.accountInfo = { // Billing profile account - account_code: '', - username: '', - email: '', - first_name: '', - last_name: '', - company_name: '', - hasError: false, - newBilling: true - }; - this.billingInfo = { // Billing card information - first_name: '', - last_name: '', - address1: '', - address2: '', - country: '', - state: '', - zip: '', - city: '', - last_four: '', - card_type: '', - month: '', - year: '', - newBilling: true - }; - this.card = { - number: '', - cvv: '', - month: month, - year: year, - last_four: null, - type: '', - coupon_code: '', - coupon: 0 - }; - this.errorMessage = ''; - this.fieldErrors = { - number: false, - expiry: false, - cvv: false, - coupon_code: false, - first_name: false, - last_name: false, - address1: false, - country: false, - state: false, - zip: false, - city: false, - month: false, - year: false - }; - this.STATUS = STATUS.DEFAULT; - }, - _accountExists: function() { - this.accountInfo.newBilling = false; - this.emitChange(); - }, - _billingInfoExists: function() { - this.billingInfo.newBilling = false; - this.emitChange(); - }, - _clearStore: function() { - this.initialize(); - }, - _receiveBillingInfo: function(payload) { - this.initialize(); - if (payload.billingInfo && payload.billingInfo.last_four) { - var cardInfo = { - last_four: payload.billingInfo.last_four, - type: payload.billingInfo.card_type, - month: payload.billingInfo.month, - year: payload.billingInfo.year - }; - } - _.merge(this.billingInfo, payload.billingInfo); - _.merge(this.accountInfo, payload.accountInfo); - _.merge(this.card, cardInfo); - this.billforwardId = payload.billforwardId; - this.emitChange(); - }, - _submitErrors: function(message) { - this.STATUS = STATUS.FORM_ERROR; - this.errorMessage = message; - this.emitChange(); - }, - _submitSuccess: function() { - this.STATUS = STATUS.SUCCESS; - this.errorMessage = ''; - this.emitChange(); - }, - _submitStart: function() { - this.STATUS = STATUS.ATTEMPTING; - this.errorMessage = ''; - this.emitChange(); - }, - _updateBillingInfoForm: function({ field, fieldKey, fieldValue }) { - if (field === 'billing') { - this.billingInfo[fieldKey] = fieldValue; - } else if (field === 'account') { - this.accountInfo[fieldKey] = fieldValue; - } else if (field === 'card') { - this.card[fieldKey] = fieldValue; - } - this.emitChange(); - }, - _updateErrors: function(hasError) { - this.STATUS = STATUS.FORM_ERROR; - _.merge(this.fieldErrors, hasError.fieldErrors); - _.merge(this.accountInfo, hasError.accountErr); - this.errorMessage = 'Please make sure all fields are valid.'; - this.emitChange(); - }, - _updateRecurlyErrors: function(error) { - const errorFields = error.fields; - debug('Recurly Form errors', errorFields); - const fieldErrors = { - number: _.includes(errorFields, 'number'), - expiry: _.includes(errorFields, 'month') || _.includes(errorFields, 'year'), - cvv: _.includes(errorFields, 'cvv'), - first_name: _.includes(errorFields, 'first_name'), - last_name: _.includes(errorFields, 'last_name') - }; - _.merge(this.fieldErrors, fieldErrors); - this.STATUS = STATUS.FORM_ERROR; - this.errorMessage = error.message; - this.emitChange(); - }, - _updateCouponValue: function(value) { - this.card.coupon = value; - this.emitChange(); - }, - getState: function() { - return { - billforwardId: this.billforwardId, - accountInfo: this.accountInfo, - billingInfo: this.billingInfo, - card: this.card, - errorMessage: this.errorMessage, - fieldErrors: this.fieldErrors, - STATUS: this.STATUS - }; - }, - dehydrate: function() { - return this.getState(); - }, - rehydrate: function(state) { - this.billforwardId = state.billforwardId; - this.accountInfo = state.accountInfo; - this.billingInfo = state.billingInfo; - this.card = state.card; - this.errorMessage = state.errorMessage; - this.fieldErrors = state.fieldErrors; - this.STATUS = state.STATUS; - } -}); - -module.exports = BillingInfoFormStore; diff --git a/app/scripts/stores/BillingPlansStore.js b/app/scripts/stores/BillingPlansStore.js deleted file mode 100644 index 3a25234628..0000000000 --- a/app/scripts/stores/BillingPlansStore.js +++ /dev/null @@ -1,128 +0,0 @@ -'use strict'; -import createStore from 'fluxible/addons/createStore'; -import _ from 'lodash'; - -var BillingPlansStore = createStore({ - storeName: 'BillingPlansStore', - handlers: { - RESET_BILLING_PLANS: '_clearStore', - RECEIVE_BILLING_INFO: '_receiveBillingInfo', - RECEIVE_BILLING_SUBSCRIPTION: '_receiveBillingSubscription', - RECEIVE_INVOICES: '_receiveInvoices', - RESET_CURRENT_PLAN: '_resetCurrentPlan', - UPDATE_PLAN_START: '_updatePlanStart', - UPDATE_PLAN_ERROR: '_updatePlanErr', - DELETE_SUBSCRIPTION_ERR: '_updatePlanErr', - DELETE_SUBSCRIPTION_SUCCESS: '_unsubscribeComplete', - UNSUBSCRIBE_SUBSCRIPTION: '_unsubscribe', // UNUSED - deprecated - UNSUBSCRIBE_PACKAGE: '_unsubscribePackage', // UNUSED - deprecated - UNSUBSCRIBE_PLAN: '_unsubscribePlan', // UNUSED - deprecated - LOGOUT: '_clearStore' - }, - initialize: function() { - this.currentPlan = {}; - this.accountInfo = { - account_code: '', - username: '', - email: '', - first_name: '', - last_name: '', - company_name: '', - hasError: false, - newBilling: true - }; - this.billingInfo = { - first_name: '', - last_name: '', - address1: '', - address2: '', - country: '', - state: '', - zip: '', - city: '', - last_four: '', - card_type: '', - month: '', - year: '', - newBilling: true - }; - this.invoices = []; - this.plansError = ''; - this.unsubscribing = ''; - this.updatePlan = ''; - }, - _clearStore: function() { - this.initialize(); - }, - _receiveBillingInfo: function(payload) { - this.initialize(); - _.merge(this.billingInfo, payload.billingInfo); - _.merge(this.accountInfo, payload.accountInfo); - _.merge(this.currentPlan, payload.currentPlan); - this.emitChange(); - }, - _receiveBillingSubscription: function(payload) { - _.merge(this.currentPlan, payload.currentPlan); - this.updatePlan = ''; - this.emitChange(); - }, - _receiveInvoices: function(payload) { - this.invoices = payload.invoices; - this.emitChange(); - }, - _resetCurrentPlan: function(payload) { - this.currentPlan = payload.currentPlan; - this.emitChange(); - }, - _unsubscribe: function() { // UNUSED - deprecated - this.unsubscribing = 'subscription'; - this.emitChange(); - }, - _unsubscribePackage: function() { // UNUSED - deprecated - this.unsubscribing = 'package'; - this.emitChange(); - }, - _unsubscribePlan: function() { // UNUSED - deprecated - this.unsubscribing = 'plan'; - this.emitChange(); - }, - _unsubscribeComplete: function() { // UNUSED - deprecated - this.unsubscribing = ''; - this.emitChange(); - }, - _updatePlanStart: function(payload) { - this.updatePlan = payload; - this.emitChange(); - }, - _updatePlanErr: function(payload) { - this.unsubscribing = ''; - this.updatePlan = ''; - this.plansError = payload; - this.emitChange(); - }, - getState: function() { - return { - currentPlan: this.currentPlan, - accountInfo: this.accountInfo, - billingInfo: this.billingInfo, - invoices: this.invoices, - plansError: this.plansError, - unsubscribing: this.unsubscribing, - updatePlan: this.updatePlan - }; - }, - dehydrate: function() { - return this.getState(); - }, - rehydrate: function(state) { - this.currentPlan = state.currentPlan; - this.accountInfo = state.accountInfo; - this.billingInfo = state.billingInfo; - this.invoices = state.invoices; - this.plansError = state.plansError; - this.unsubscribing = state.unsubscribing; - this.updatePlan = state.updatePlan; - } -}); - -module.exports = BillingPlansStore; diff --git a/app/scripts/stores/BitbucketLinkStore.js b/app/scripts/stores/BitbucketLinkStore.js deleted file mode 100644 index bc3c1ffb3e..0000000000 --- a/app/scripts/stores/BitbucketLinkStore.js +++ /dev/null @@ -1,60 +0,0 @@ -'use strict'; - -import _ from 'lodash'; -import createStore from 'fluxible/addons/createStore'; -var debug = require('debug')('BitbucketLinkStore'); - -var BitbucketLinkStore = createStore({ - storeName: 'BitbucketLinkStore', - handlers: { - RECEIVE_BITBUCKET_AUTH_URL: '_receiveUrl', - BITBUCKET_AUTH_URL_ERROR: '_urlError', - BITBUCKET_ASSOCIATE_ERROR: '_associateError' - }, - initialize: function() { - this.authURL = ''; - this.error = ''; - }, - _associateError: function(body) { - debug(body); - if (_.has(body, 'detail') && _.isString(body.detail)) { - this.error = body.detail; - } else { - this.error = 'Error linking your account to Bitbucket. Please check that you do not have the same Bitbucket account linked to another Docker Hub account.'; - } - this.emitChange(); - setTimeout(this._clearError.bind(this), 5000); - }, - _receiveUrl: function(res) { - this.authURL = res.bitbucket_authorization_url; - this.emitChange(); - }, - _urlError: function(err) { - debug(err); - this.error = 'Error linking your account to bitbucket.'; - this.emitChange(); - setTimeout(this._clearError.bind(this), 5000); - }, - _clearError: function() { - this.error = ''; - this.emitChange(); - }, - setURL: function(url) { - this.authURL = url; - }, - getState: function() { - return { - authURL: this.authURL, - error: this.error - }; - }, - rehydrate: function(state) { - this.authURL = state.authURL; - this.error = state.error; - }, - dehydrate: function() { - return this.getState(); - } -}); - -module.exports = BitbucketLinkStore; diff --git a/app/scripts/stores/ChangePasswordStore.js b/app/scripts/stores/ChangePasswordStore.js deleted file mode 100644 index f9c210622c..0000000000 --- a/app/scripts/stores/ChangePasswordStore.js +++ /dev/null @@ -1,64 +0,0 @@ -'use strict'; -import createStore from 'fluxible/addons/createStore'; -const debug = require('debug')('stores: ChangePasswordStore'); - -var ChangePasswordStore = createStore({ - storeName: 'ChangePasswordStore', - handlers: { - CHANGE_PASS_UPDATE: '_updateStore', - CHANGE_PASS_SUCCESS: '_changePassSuccess', - CHANGE_PASS_CLEAR: '_clearStore', - RESET_PASSWORD_SUCCESSFUL: '_changePassSuccess', - RESET_PASSWORD_ERROR: '_changePassError' - }, - initialize: function() { - this.oldpass = ''; - this.newpass = ''; - this.confpass = ''; - this.reset = false; - this.hasErr = false; - this.err = ''; - }, - _updateStore: function(payload) { - this.reset = false; - this.hasErr = false; - this.err = ''; - this.oldpass = payload.oldpass; - this.newpass = payload.newpass; - this.confpass = payload.confpass; - this.emitChange(); - }, - _changePassSuccess: function() { - this._clearStore(); - this.reset = true; - this.emitChange(); - }, - _changePassError: function(error) { - this._clearStore(); - this.hasErr = true; - this.err = error; - this.emitChange(); - }, - _clearStore: function() { - this.oldpass = ''; - this.newpass = ''; - this.confpass = ''; - this.reset = false; - this.hasErr = false; - this.err = ''; - this.emitChange(); - }, - getState: function() { - return { - oldpass: this.oldpass, - newpass: this.newpass, - confpass: this.confpass, - reset: this.reset, - hasErr: this.hasErr, - err: this.err - }; - } - -}); - -module.exports = ChangePasswordStore; diff --git a/app/scripts/stores/CloudBillingStore.js b/app/scripts/stores/CloudBillingStore.js deleted file mode 100644 index 4489827ae7..0000000000 --- a/app/scripts/stores/CloudBillingStore.js +++ /dev/null @@ -1,43 +0,0 @@ -'use strict'; -import createStore from 'fluxible/addons/createStore'; - -var BillingPlansStore = createStore({ - storeName: 'CloudBillingStore', - handlers: { - RESET_CLOUD_BILLING_PLANS: '_clearStore', - RECEIVE_CLOUD_BILLING_INFO: '_receiveBillingInfo', - LOGOUT: '_clearStore' - }, - initialize: function() { - this.currentPlan = {}; - this.billingInfo = {}; - this.accountInfo = {}; - }, - _clearStore: function() { - this.initialize(); - this.emitChange(); - }, - _receiveBillingInfo: function(payload) { - this.billingInfo = payload.billingInfo; - this.accountInfo = payload.accountInfo; - this.currentPlan = payload.currentPlan; - this.emitChange(); - }, - getState: function() { - return { - currentPlan: this.currentPlan, - accountInfo: this.accountInfo, - billingInfo: this.billingInfo - }; - }, - dehydrate: function() { - return this.getState(); - }, - rehydrate: function(state) { - this.currentPlan = state.currentPlan; - this.accountInfo = state.accountInfo; - this.billingInfo = state.billingInfo; - } -}); - -module.exports = BillingPlansStore; diff --git a/app/scripts/stores/CloudCouponStore.js b/app/scripts/stores/CloudCouponStore.js deleted file mode 100644 index c3bb7add7a..0000000000 --- a/app/scripts/stores/CloudCouponStore.js +++ /dev/null @@ -1,54 +0,0 @@ -'use strict'; -import createStore from 'fluxible/addons/createStore'; -import _ from 'lodash'; - -var CloudCouponStore = createStore({ - storeName: 'CloudCouponStore', - handlers: { - RECEIVE_BILLING_INFO: '_clearStore', - CLEAR_CLOUD_COUPON: '_clearStore', - UPDATE_COUPON_VALUE: '_updateDiscountValue', - BILLING_INFO_UPDATE_FIELD_WITH_VALUE: '_updateCouponCode', - BILLING_ERRORS: '_updateErrors' - }, - initialize: function() { - this.couponCode = ''; - this.discountValue = 0; - this.hasError = false; - }, - _clearStore: function() { - this.initialize(); - this.emitChange(); - }, - _updateCouponCode: function({field, fieldKey, fieldValue}) { - this.couponCode = fieldKey === 'coupon_code' ? fieldValue : this.couponValue; - this.emitChange(); - }, - _updateDiscountValue: function(discount) { - this.discountValue = discount; - this.emitChange(); - }, - _updateErrors: function({fieldErrors}) { - if (_.has(fieldErrors, 'coupon_code')) { - this.hasError = fieldErrors.coupon_code; - } - this.emitChange(); - }, - getState: function() { - return { - couponCode: this.couponCode, - discountValue: this.discountValue, - hasError: this.hasError - }; - }, - dehydrate: function() { - return this.getState(); - }, - rehydrate: function(state) { - this.couponCode = state.couponCode; - this.discountValue = state.discountValue; - this.hasError = state.hasError; - } -}); - -module.exports = CloudCouponStore; diff --git a/app/scripts/stores/ConvertToOrgStore.js b/app/scripts/stores/ConvertToOrgStore.js deleted file mode 100644 index f100be9945..0000000000 --- a/app/scripts/stores/ConvertToOrgStore.js +++ /dev/null @@ -1,41 +0,0 @@ -'use strict'; -import createStore from 'fluxible/addons/createStore'; -var debug = require('debug')('stores: ConvertToOrgStore'); - -export default createStore({ - storeName: 'ConvertToOrgStore', - handlers: { - CONVERT_TO_ORG_BAD_REQUEST: '_badRequest', - UPDATE_TO_ORG_OWNER: '_updateOwner' - }, - initialize: function() { - this.convertError = false; - this.error = {}; - this.newOwner = ''; - }, - _badRequest: function(error) { - this.convertError = true; - this.error = error; - this.emitChange(); - }, - _updateOwner: function(payload) { - this.newOwner = payload.newOwner; - this.convertError = false; - this.emitChange(); - }, - getState: function() { - return { - convertError: this.convertError, - error: this.error, - newOwner: this.newOwner - }; - }, - dehydrate: function() { - return this.getState(); - }, - rehydrate: function(state) { - this.convertError = state.convertError; - this.error = state.error; - this.newOwner = state.newOwner; - } -}); diff --git a/app/scripts/stores/CreateRepositoryFormStore.js b/app/scripts/stores/CreateRepositoryFormStore.js deleted file mode 100644 index e604fa6a50..0000000000 --- a/app/scripts/stores/CreateRepositoryFormStore.js +++ /dev/null @@ -1,147 +0,0 @@ -'use strict'; - -import _ from 'lodash'; -import { STATUS } from './common/Constants'; -import createStore from 'fluxible/addons/createStore'; -var debug = require('debug')('CreateRepositoryFormStore'); - -var noErrorObj = { - hasError: false, - error: '' -}; - -export default createStore({ - storeName: 'CreateRepositoryFormStore', - handlers: { - CREATE_REPO_CLEAR_FORM: 'initialize', - CREATE_REPO_UPDATE_FIELD_WITH_VALUE: '_updateFieldWithValue', - CREATE_REPO_ATTEMPT_START: '_attemptStart', - CREATE_REPO_BAD_REQUEST: '_badRequest', - CREATE_REPO_SUCCESS: '_success', - CREATE_REPO_FACEPALM: '_facepalm', - CREATE_REPO_RECEIVE_NAMESPACES: '_receiveNamespaces' - }, - initialize() { - this.STATUS = STATUS.DEFAULT; - - this.namespaces = []; - this.globalFormError = ''; - - this.fields = { - user: {}, - namespace: {}, - name: {}, - description: {}, - full_description: {}, - is_private: {} - }; - - this.values = { - user: '', - namespace: '', - name: '', - description: '', - full_description: '', - is_private: true - }; - }, - _receiveNamespaces({ - namespaces, selectedNamespace - }) { - debug('receiving namespaces', namespaces, selectedNamespace); - /** - * namespaces is equivalent to the response in the namespaces API call - */ - this.namespaces = namespaces.namespaces; - if(_.includes(namespaces.namespaces, selectedNamespace)) { - this.values.namespace = selectedNamespace; - } else { - this.values.namespace = namespaces.namespaces[0]; - } - this.emitChange(); - }, - _facepalm() { - // this happens if things are screwed and we can't recover gracefully - this.STATUS = STATUS.FACEPALM; - this.emitChange(); - }, - _clearForm() { - this.initialize(); - this.emitChange(); - }, - _updateFieldWithValue({fieldKey, fieldValue}) { - debug(fieldKey, fieldValue); - this.fields[fieldKey].hasError = false; - this.fields[fieldKey].error = ''; - this.globalFormError = ''; - this.values[fieldKey] = fieldValue; - this.emitChange(); - }, - _attemptStart() { - this.STATUS = STATUS.ATTEMPTING; - this.emitChange(); - }, - _success() { - this.STATUS = STATUS.SUCCESSFUL_SIGNUP; - this.emitChange(); - }, - _badRequest(obj) { - /** - * This function expects keys which match the `this.fields` keys - * with an array of errors: - * - * { - * orgname: ['this field is required'] - * } - */ - let shouldEmitChange = false; - // So far obj.detail is only returned when there are no more private repo's - // We really need to update the response from the api - if (obj.detail) { - obj.is_private = [obj.detail]; - } - - // cycle through the possible form fields - this.fields = _.mapValues(this.fields, function (errorObject, key) { - if(_.has(obj, key)) { - shouldEmitChange = true; - return { - hasError: !!obj[key], - error: obj[key][0] - }; - } else { - return errorObject; - } - }); - /** - * __all__ occurs when "Repository with this Name and Namespace already exists." - */ - if(obj.__all__) { - this.globalFormError = obj.__all__[0]; - shouldEmitChange = true; - } - - if(shouldEmitChange) { - this.emitChange(); - } - }, - getState() { - return { - fields: this.fields, - values: this.values, - STATUS: this.STATUS, - namespaces: this.namespaces, - globalFormError: this.globalFormError - }; - }, - dehydrate() { - return this.getState(); - }, - rehydrate(state) { - this.fields = state.fields; - this.values = state.values; - this.namespaces = state.namespaces; - this.STATUS = state.STATUS; - this.globalFormError = state.globalFormError; - } -}); diff --git a/app/scripts/stores/DashboardContribsStore.js b/app/scripts/stores/DashboardContribsStore.js deleted file mode 100644 index cbdae5356f..0000000000 --- a/app/scripts/stores/DashboardContribsStore.js +++ /dev/null @@ -1,43 +0,0 @@ -'use strict'; - -import createStore from 'fluxible/addons/createStore'; -var debug = require('debug')('DashboardContribsStore'); - -export default createStore({ - storeName: 'DashboardContribsStore', - handlers: { - RECEIVE_CONTRIB: '_receiveContribRepos', - LOGOUT: 'initialize' - }, - initialize: function() { - this.count = 0; - this.contribs = []; - this.next = null; - this.prev = null; - }, - _receiveContribRepos: function(res) { - this.count = res.count; - this.contribs = res.results; - this.next = res.next; - this.prev = res.previous; - this.emitChange(); - }, - getState: function() { - return { - count: this.count, - contribs: this.contribs, - next: this.next, - prev: this.prev - }; - }, - dehydrate: function() { - return this.getState(); - }, - rehydrate: function(state) { - this.count = state.count; - this.contribs = state.contribs; - this.next = state.next; - this.prev = state.prev; - } -}); - diff --git a/app/scripts/stores/DashboardMembersStore.js b/app/scripts/stores/DashboardMembersStore.js deleted file mode 100644 index 0b2df77622..0000000000 --- a/app/scripts/stores/DashboardMembersStore.js +++ /dev/null @@ -1,73 +0,0 @@ -'use strict'; - -import createStore from 'fluxible/addons/createStore'; -import _ from 'lodash'; -var debug = require('debug')('DashboardMembersStore'); -import { STATUS } from './orgteamstore/Constants'; - -var DashboardMembersStore = createStore({ - storeName: 'DashboardMembersStore', - handlers: { - RECEIVE_DASHBOARD_TEAM_MEMBERS: '_receiveDashboardTeamMembers', - ORG_DASHBOARD_MEMBERS_ERROR: '_errorReceivingMembers', - TEAM_MEMBER_ERROR: '_teamMemberError', - TEAM_MEMBER_BAD_REQUEST: '_teamMemberBadRequest', - TEAM_MEMBER_UNAUTHORIZED: '_teamMemberUnauthorized', - CLEAR_MEMBER_ERROR: '_clearErrorStates' - }, - initialize() { - this.members = []; - this.count = 0; - this.error = {}; - this.STATUS = STATUS.DEFAULT; - }, - _errorReceivingMembers(err) { - debug(err); - }, - _receiveDashboardTeamMembers(members) { - debug(members); - this.members = members; - this.count = members.length; - this.emitChange(); - }, - _teamMemberError: function(err) { - this.STATUS = STATUS.MEMBER_ERROR; - this.STATUS = STATUS.GENERAL_SERVER_ERROR; - this.error = err; - this.emitChange(); - }, - _teamMemberBadRequest: function(err) { - this.STATUS = STATUS.MEMBER_BAD_REQUEST; - this.error = err; - this.emitChange(); - }, - _teamMemberUnauthorized: function(err) { - this.STATUS = STATUS.MEMBER_UNAUTHORIZED; - this.error = err; - this.emitChange(); - }, - _clearErrorStates: function() { - this.error = {}; - this.STATUS = STATUS.DEFAULT; - this.emitChange(); - }, - getState() { - return { - members: this.members, - count: this.count, - error: this.error, - STATUS: this.STATUS - }; - }, - dehydrate: function() { - return this.getState(); - }, - rehydrate: function(state) { - this.members = state.members; - this.count = state.count; - this.STATUS = state.STATUS; - this.error = state.error; - } -}); - -module.exports = DashboardMembersStore; diff --git a/app/scripts/stores/DashboardNamespacesStore.js b/app/scripts/stores/DashboardNamespacesStore.js deleted file mode 100644 index 35b354f8b6..0000000000 --- a/app/scripts/stores/DashboardNamespacesStore.js +++ /dev/null @@ -1,62 +0,0 @@ -'use strict'; - -import createStore from 'fluxible/addons/createStore'; -var debug = require('debug')('DashboardNamespacesStore'); -import _ from 'lodash'; - -export default createStore({ - storeName: 'DashboardNamespacesStore', - handlers: { - RECEIVE_DASHBOARD_NAMESPACES: '_receiveOrgs', - CURRENT_USER_CONTEXT: '_setContext', - CREATE_REPO_RECEIVE_NAMESPACES: '_receiveOwnedNamespaces' - }, - initialize() { - this.namespaces = []; - this.currentUserContext = ''; - this.ownedNamespaces = []; - }, - _receiveOrgs(res) { - //There are two API calls possible to get namespaces - //`/v2/namespaces` -> returns `res.orgs.namespaces` an object with {namespaces: ['ns1', 'ns2', 'etc']} - //`/v2/orgs` -> returns `res.orgs.results` with all orgs the user has read access on. We merge the `res.user` with this list - if (res.orgs.namespaces) { - this.namespaces = res.orgs.namespaces; - } else if (res.orgs.results && _.isArray(res.orgs.results)) { - var nsArray = _.pluck(res.orgs.results, 'orgname'); - nsArray.unshift(res.user); - this.namespaces = nsArray; - } - this.emitChange(); - }, - _receiveOwnedNamespaces({ - namespaces, selectedNamespace - }) { - debug('receiving namespaces', namespaces, selectedNamespace); - /** - * namespaces is equivalent to the response in the namespaces API call - */ - this.ownedNamespaces = namespaces.namespaces; - this.emitChange(); - }, - _setContext: function({username}) { - this.currentUserContext = username; - this.emitChange(); - }, - getState() { - return { - currentUserContext: this.currentUserContext, - namespaces: this.namespaces, - ownedNamespaces: this.ownedNamespaces - }; - }, - dehydrate() { - return this.getState(); - }, - rehydrate(state) { - this.currentUserContext = state.currentUserContext; - this.namespaces = state.namespaces; - this.ownedNamespaces = state.ownedNamespaces; - } -}); - diff --git a/app/scripts/stores/DashboardReposStore.js b/app/scripts/stores/DashboardReposStore.js deleted file mode 100644 index 1501ffc8a4..0000000000 --- a/app/scripts/stores/DashboardReposStore.js +++ /dev/null @@ -1,69 +0,0 @@ -'use strict'; - -import createStore from 'fluxible/addons/createStore'; -var debug = require('debug')('DashboardReposStore'); -import { STATUS } from './common/Constants'; -const { - ATTEMPTING, - DEFAULT, - SUCCESSFUL -} = STATUS; - -var DashboardReposStore = createStore({ - storeName: 'DashboardReposStore', - handlers: { - RECEIVE_REPOS: '_receiveRepos', - LOGOUT: 'initialize', - DASHBOARD_REPOS_STORE_ATTEMPTING_GET_REPOS: '_startGetRepos', - DASHBOARD_REPOS_STORE_ATTEMPTING_GET_ALL_REPOS: '_startGetAllRepos', - DASHBOARD_REPOS_STORE_RECEIVE_ALL_REPOS_SUCCESS: '_receiveAllRepos' - }, - initialize() { - this.repos = []; - this.count = 0; - this.next = null; - this.prev = null; - this.STATUS = DEFAULT; - }, - getState() { - return { - repos: this.repos, - count: this.count, - next: this.next, - prev: this.prev, - STATUS: this.STATUS - }; - }, - _startGetRepos: function() { - this.STATUS = DEFAULT; - this.emitChange(); - }, - _startGetAllRepos: function() { - this.STATUS = ATTEMPTING; - this.emitChange(); - }, - _receiveRepos(res) { - debug(res); - this.repos = res.results; - this.count = res.count; - this.next = res.next; - this.prev = res.previous; - this.emitChange(); - }, - _receiveAllRepos(res) { - this.STATUS = SUCCESSFUL; - this._receiveRepos(res); - }, - dehydrate() { - return this.getState(); - }, - rehydrate(state) { - this.repos = state.repos; - this.count = state.count; - this.next = state.next; - this.prev = state.prev; - this.STATUS = state.STATUS; - } -}); - -module.exports = DashboardReposStore; diff --git a/app/scripts/stores/DashboardStarsStore.js b/app/scripts/stores/DashboardStarsStore.js deleted file mode 100644 index 2e8da00d21..0000000000 --- a/app/scripts/stores/DashboardStarsStore.js +++ /dev/null @@ -1,43 +0,0 @@ -'use strict'; - -import createStore from 'fluxible/addons/createStore'; -var debug = require('debug')('DashboardStarsStore'); - -export default createStore({ - storeName: 'DashboardStarsStore', - handlers: { - RECEIVE_STARRED: '_receiveStarredRepos', - LOGOUT: 'initialize' - }, - initialize: function() { - this.count = 0; - this.starred = []; - this.next = null; - this.prev = null; - }, - _receiveStarredRepos: function(res) { - this.count = res.count; - this.starred = res.results; - this.next = res.next; - this.prev = res.previous; - this.emitChange(); - }, - getState: function() { - return { - count: this.count, - starred: this.starred, - next: this.next, - prev: this.prev - }; - }, - dehydrate: function() { - return this.getState(); - }, - rehydrate: function(state) { - this.count = state.count; - this.starred = state.starred; - this.next = state.next; - this.prev = state.prev; - } -}); - diff --git a/app/scripts/stores/DashboardStore.js b/app/scripts/stores/DashboardStore.js deleted file mode 100644 index f8702ca5e7..0000000000 --- a/app/scripts/stores/DashboardStore.js +++ /dev/null @@ -1,63 +0,0 @@ -'use strict'; - -import createStore from 'fluxible/addons/createStore'; -var debug = require('debug')('DashboardStore'); - -var DashboardStore = createStore({ - storeName: 'DashboardStore', - handlers: { - RECEIVE_STARRED: '_receiveStarredRepos', - RECEIVE_CONTRIB: '_receiveContribRepos', - RECEIVE_ACTIVITY_FEED: '_receiveActivityFeed', - LOGOUT: 'initialize' - }, - initialize: function() { - this.user = {}; - this.org = ''; - this.starred = []; - this.contribs = []; - this.feed = []; - }, - getInitState: function() { - return { - starred: [], - contribs: [], - org: '', - feed: [], - user: {} - }; - }, - _receiveStarredRepos: function(repos) { - this.starred = repos.results; - this.emitChange(); - }, - _receiveContribRepos: function(repos) { - this.contribs = repos.results; - this.emitChange(); - }, - _receiveActivityFeed: function(feed) { - this.feed = feed; - this.emitChange(); - }, - getState: function() { - return { - starred: this.starred, - contribs: this.contribs, - org: this.org, - feed: this.feed, - user: this.user - }; - }, - dehydrate: function() { - return this.getState(); - }, - rehydrate: function(state) { - this.starred = state.starred; - this.contribs = state.contribs; - this.feed = state.feed; - this.org = state.org; - this.user = state.user; - } -}); - -module.exports = DashboardStore; diff --git a/app/scripts/stores/DashboardTeamsStore.js b/app/scripts/stores/DashboardTeamsStore.js deleted file mode 100644 index 74d1fb2447..0000000000 --- a/app/scripts/stores/DashboardTeamsStore.js +++ /dev/null @@ -1,100 +0,0 @@ -'use strict'; - -import createStore from 'fluxible/addons/createStore'; -import _ from 'lodash'; -import { STATUS } from './orgteamstore/Constants'; -var debug = require('debug')('DashboardTeamsStore'); - -var DashboardTeamsStore = createStore({ - storeName: 'DashboardTeamsStore', - handlers: { - RECEIVE_DASHBOARD_ORG_TEAMS: '_receiveDashboardOrgTeams', - TEAM_ERROR: '_orgTeamError', - TEAM_BAD_REQUEST: '_teamBadRequest', - TEAM_UNAUTHORIZED: '_teamUnauthorized', - UPDATE_TEAM_ERROR: '_updateTeamError', - UPDATE_TEAM_SUCCESS: '_updateTeamSuccess', - TEAM_READ_ONLY: '_isTeamReadOnly' - }, - initialize() { - this.teams = []; - this.count = 0; - this.teamReadOnly = false; - this.errorDetails = {detail: ''}; - this.success = ''; - this.STATUS = STATUS.DEFAULT; - }, - _receiveDashboardOrgTeams(orgTeams) { - debug(orgTeams); - this.teams = _.sortBy(orgTeams.results, 'name'); - this.count = orgTeams.count; - this.emitChange(); - }, - _orgTeamError: function(err) { - this.STATUS = STATUS.TEAM_ERROR; - this.STATUS = STATUS.GENERAL_SERVER_ERROR; - this.errorDetails = {detail: 'Username does not exist or it is invalid.'}; - this.emitChange(); - }, - _teamBadRequest: function(err) { - this.STATUS = STATUS.TEAM_BAD_REQUEST; - this.errorDetails = err; - this.emitChange(); - }, - _teamUnauthorized: function(err) { - this.STATUS = STATUS.TEAM_UNAUTHORIZED; - this.errorDetails = err; - this.emitChange(); - }, - _isTeamReadOnly: function(flag) { - this.teamReadOnly = flag; - this.emitChange(); - }, - _updateTeamError: function(err) { - this.STATUS = STATUS.UPDATE_TEAM_ERROR; - if (err.response) { - var errResp = err.response; - if (errResp.badRequest) { - this.errorDetails = err; - } else if (errResp.unauthorized || errResp.forbidden) { - this.errorDetails = {detail: 'You are not permitted to edit this team.'}; - } else { - this.errorDetails = {detail: 'Error updating team. Check if name is between 3 and 30 characters with no spaces.'}; - } - } - this.emitChange(); - }, - _updateTeamSuccess: function(err) { - this.STATUS = STATUS.UPDATE_TEAM_SUCCESS; - this.success = 'Team successfully updated.'; - setTimeout(this._clearErrorStates.bind(this), 5000); - this.emitChange(); - }, - _clearErrorStates: function() { - this.errorDetails = {detail: ''}; - this.success = ''; - this.STATUS = STATUS.DEFAULT; - this.emitChange(); - }, - getState() { - return { - teams: this.teams, - count: this.count, - teamReadOnly: this.teamReadOnly, - success: this.success, - errorDetails: this.errorDetails - }; - }, - dehydrate: function() { - return this.getState(); - }, - rehydrate: function(state) { - this.teams = state.teams; - this.teamReadOnly = state.teamReadOnly; - this.count = state.count; - this.success = state.success; - this.errorDetails = state.errorDetails; - } -}); - -module.exports = DashboardTeamsStore; diff --git a/app/scripts/stores/DeletePipelineStore.js b/app/scripts/stores/DeletePipelineStore.js deleted file mode 100644 index ef0681321e..0000000000 --- a/app/scripts/stores/DeletePipelineStore.js +++ /dev/null @@ -1,46 +0,0 @@ -'use strict'; - -var createStore = require('fluxible/addons/createStore'); -import { - ATTEMPTING, - DEFAULT, - FACEPALM, - SUCCESSFUL -} from './deletepipelinestore/Constants'; - -var debug = require('debug')('SignupStore'); - -export default createStore({ - storeName: 'DeletePipelineStore', - handlers: { - DELETE_PIPELINE_ATTEMPTING: '_start', - DELETE_PIPELINE_FACEPALM: '_facepalm', - DELETE_PIPELINE_SUCCESS: '_success' - }, - initialize() { - this.STATUS = DEFAULT; - }, - _start() { - this.STATUS = ATTEMPTING; - this.emitChange(); - }, - _facepalm() { - this.STATUS = FACEPALM; - this.emitChange(); - }, - _success() { - this.STATUS = SUCCESSFUL; - this.emitChange(); - }, - getState() { - return { - STATUS: this.STATUS - }; - }, - dehydrate() { - return {}; - }, - rehydrate(state) { - this.state = state; - } -}); diff --git a/app/scripts/stores/DeleteRepoFormStore.js b/app/scripts/stores/DeleteRepoFormStore.js deleted file mode 100644 index 21a60d3d33..0000000000 --- a/app/scripts/stores/DeleteRepoFormStore.js +++ /dev/null @@ -1,75 +0,0 @@ -'use strict'; - -import createStore from 'fluxible/addons/createStore'; -import { STATUS } from './deleterepostore/Constants.js'; -const debug = require('debug')('DeleteRepoFormStore'); - -var DeleteRepoFormStore = createStore({ - storeName: 'DeleteRepoFormStore', - handlers: { - DELETE_REPO_ATTEMPT_START: '_deleteRepoAttemptStart', - DELETE_REPO_BAD_REQUEST: '_deleteRepoBadRequest', - DELETE_REPO_ERROR: '_deleteRepoError', - DELETE_REPO_UPDATE_FIELD_WITH_VALUE: '_updateFieldWithValue', - RECEIVE_REPOSITORY: '_receiveRepository', - TOGGLE_DELETE_REPO_NAME_CONFIRM_BOX: '_toggleConfirmBox' - }, - initialize: function() { - this.error = ''; - this.STATUS = STATUS.DEFAULT; - this.values = { - confirmRepoName: '' - }; - }, - _deleteRepoAttemptStart: function() { - this.STATUS = STATUS.ATTEMPTING; - this.emitChange(); - }, - _deleteRepoBadRequest: function(res) { - this.STATUS = STATUS.FORM_ERROR; - this.error = res.detail ? res.detail - : 'Error deleting repository. Please verify if you have permissions.'; - this.emitChange(); - }, - _deleteRepoError: function() { - this.STATUS = STATUS.FORM_ERROR; - this.error = 'Error deleting repository. Please verify if you have permissions.'; - this.emitChange(); - }, - _receiveRepository: function() { - this.initialize(); - this.emitChange(); - }, - _toggleConfirmBox: function() { - if (this.STATUS === STATUS.DEFAULT) { - this.STATUS = STATUS.SHOWING_CONFIRM_BOX; - } else { - this.STATUS = STATUS.DEFAULT; - } - this.error = ''; - this.values.confirmRepoName = ''; - this.emitChange(); - }, - _updateFieldWithValue: function({fieldKey, fieldValue}){ - this.values[fieldKey] = fieldValue; - this.error = ''; - this.emitChange(); - }, - getState: function() { - return { - error: this.error, - STATUS: this.STATUS, - values: this.values - }; - }, - rehydrate: function(state) { - this.error = state.error; - this.STATUS = state.STATUS; - this.values = state.values; - }, - dehydrate: function() { - return this.getState(); - } -}); - -module.exports = DeleteRepoFormStore; diff --git a/app/scripts/stores/EmailNotifStore.js b/app/scripts/stores/EmailNotifStore.js deleted file mode 100644 index 4ada6a99f9..0000000000 --- a/app/scripts/stores/EmailNotifStore.js +++ /dev/null @@ -1,128 +0,0 @@ -'use strict'; - -import createStore from 'fluxible/addons/createStore'; -import _ from 'lodash'; -import { STATUS } from './common/Constants'; -var debug = require('debug')('EmailNotifStore:'); - - -export default createStore({ - storeName: 'EmailNotifStore', - handlers: { - RECEIVE_NOTIFICATIONS: '_receiveNotifications', - NOTIF_CHECKBOX_CLICK: '_updateNotifications', - RESET_EMAIL_NOTIFICATIONS_STORE: '_resetBlankSlate', - SAVE_NOTIFICATIONS_ERROR: '_saveNotifError', - SAVE_NOTIFICATIONS_SUCCESS: '_saveNotifSuccess' - }, - initialize: function() { - // initialize with data from db - this.starNotification = false; - this.imgCommentNotification = false; - this.autoBuildNotification = false; - this.starNotificationID = -1; - this.imgCommentNotificationID = -1; - this.autoBuildNotificationID = -1; - this.STATUS = STATUS.DEFAULT; - this.blankNotificationSlate = {}; - }, - _receiveNotifications: function(notifications) { - for (var i = 0; i < notifications.length; ++i) { - switch(notifications[i].notification) { - case 'new_repo_comment': - this.imgCommentNotification = true; - this.imgCommentNotificationID = notifications[i].id; - break; - case 'new_repo_star': - this.starNotification = true; - this.starNotificationID = notifications[i].id; - break; - case 'trusted_build_fail': - this.autoBuildNotification = true; - this.autoBuildNotificationID = notifications[i].id; - break; - } - } - this.blankNotificationSlate = this.getState(); - debug(this.blankNotificationSlate); - this.attempting = false; - this.emitChange(); - }, - _resetBlankSlate: function() { - var slate = this.blankNotificationSlate; - debug('RESET EMAIL NOTIF BLANK SLATE'); - this.starNotification = slate.starNotification; - this.imgCommentNotification = slate.imgCommentNotification; - this.autoBuildNotification = slate.autoBuildNotification; - this.starNotificationID = slate.starNotificationID; - this.imgCommentNotificationID = slate.imgCommentNotificationID; - this.autoBuildNotificationID = slate.autoBuildNotificationID; - this.STATUS = STATUS.DEFAULT; - this.emitChange(); - }, - _updateNotifications: function(cboxType) { - this.STATUS = STATUS.DEFAULT; - switch(cboxType) { - case 'starNotification': - this.starNotification = !this.starNotification; - break; - case 'imgCommentNotification': - this.imgCommentNotification = !this.imgCommentNotification; - break; - case 'autoBuildNotification': - this.autoBuildNotification = !this.autoBuildNotification; - break; - } - this.emitChange(); - }, - _saveNotifError: function() { - this.STATUS = 'ERROR'; - this.emitChange(); - }, - _saveNotifSuccess: function() { - this.STATUS = STATUS.SUCCESSFUL; - this.emitChange(); - }, - hasChanged: function(type) { - switch (type) { - case 'auto': - return (this.autoBuildNotification !== this.blankNotificationSlate.autoBuildNotification); - case 'star': - return (this.starNotification !== this.blankNotificationSlate.starNotificationID); - case 'comment': - return (this.imgCommentNotification !== this.blankNotificationSlate.imgCommentNotificationID); - default: - break; - } - }, - getAttempt: function() { - return this.attempting; - }, - setAttempt: function(flag) { - this.attempting = flag; - }, - getState: function() { - return { - starNotification: this.starNotification, - imgCommentNotification: this.imgCommentNotification, - autoBuildNotification: this.autoBuildNotification, - starNotificationID: this.starNotificationID, - imgCommentNotificationID: this.imgCommentNotificationID, - autoBuildNotificationID: this.autoBuildNotificationID, - STATUS: this.STATUS - }; - }, - dehydrate: function() { - return _.merge({}, this.getState(), {blankNotificationSlate: this.blankNotificationSlate}); - }, - rehydrate: function(state) { - this.starNotification = state.starNotification; - this.imgCommentNotification = state.imgCommentNotification; - this.autoBuildNotification = state.autoBuildNotification; - this.starNotificationID = state.starNotificationID; - this.imgCommentNotificationID = state.imgCommentNotificationID; - this.autoBuildNotificationID = state.autoBuildNotificationID; - this.STATUS = state.STATUS; - this.blankNotificationSlate = state.blankNotificationSlate; - } -}); diff --git a/app/scripts/stores/EmailsStore.js b/app/scripts/stores/EmailsStore.js deleted file mode 100644 index d48589a878..0000000000 --- a/app/scripts/stores/EmailsStore.js +++ /dev/null @@ -1,155 +0,0 @@ -'use strict'; - -import createStore from 'fluxible/addons/createStore'; -import merge from 'lodash/object/merge'; -import has from 'lodash/object/has'; -import find from 'lodash/collection/find'; -import cloneDeep from 'lodash/lang/cloneDeep'; -import { STATUS, EMAILSTATUS } from './emailsstore/Constants'; - -var debug = require('debug')('EmailsStore'); - -var EmailsStore = createStore({ - storeName: 'EmailsStore', - handlers: { - RECEIVE_EMAILS: '_receiveEmails', - CHANGE_ROUTE: '_resetState', - ADD_EMAIL_INVALID: '_addEmailInvalid', - ADD_EMAIL_SUCCESS: '_addEmailSuccess', - START_SAVE_ACTION: '_startSaveAction', - FINISH_SAVE_ACTION: '_finishSaveAction', - RESEND_EMAIL_CONFIRMATION_ATTEMPT_START: '_resendEmailConfirmationAttemptStart', - RESEND_EMAIL_CONFIRMATION_SENT: '_resendEmailConfirmationSent', - RESEND_EMAIL_CONFIRMATION_FAILED: '_resendEmailConfirmationFail', - RESEND_EMAIL_CONFIRMATION_CLEAR: '_resendClear', - UPDATE_ADD_EMAIL: '_updateAddEmail' - }, - initialize: function() { - this.STATUS = STATUS.DEFAULT; - - this._cleanSlate = { - emails: [] - }; - this.emails = []; - this.emailConfirmations = {}; - this.addEmail = ''; - this.addError = ''; - }, - _startSaveAction() { - this.STATUS = STATUS.SAVING; - this.emitChange(); - }, - _finishSaveAction() { - this.STATUS = STATUS.DEFAULT; - this.emitChange(); - }, - _resendEmailConfirmationAttemptStart(emailID) { - debug('RESEND CONFIRMATION START'); - this.emailConfirmations = merge(this.emailConfirmations, { - [emailID]: EMAILSTATUS.ATTEMPTING - }); - this.emitChange(); - }, - _resendEmailConfirmationSent(emailID) { - debug('RESEND CONFIRMATION SENT'); - this.emailConfirmations = merge(this.emailConfirmations, { - [emailID]: EMAILSTATUS.SUCCESS - }); - this.emitChange(); - }, - _resendEmailConfirmationFail(emailID) { - debug('RESEND CONFIRMATION FAIL'); - this.emailConfirmations = merge(this.emailConfirmations, { - [emailID]: EMAILSTATUS.FAILED - }); - this.emitChange(); - }, - _resendClear(emailID) { - debug('RESEND CONFIRMATION CLEAR'); - this.emailConfirmations = merge(this.emailConfirmations, { - [emailID]: '' - }); - this.emitChange(); - }, - _receiveEmails: function(payload) { - debug(payload); - this.initialize(); - this._cleanSlate = { - /** - * We cloneDeep here because otherwise this.emails - * and this._cleanSlate.emails will refer to the - * same array causing unintuitive behavior. - */ - emails: cloneDeep(payload.emails) - }; - this.emails = payload.emails; - this.emitChange(); - }, - _addEmailInvalid(error) { - this.addError = error[0]; - this.emitChange(); - }, - _addEmailSuccess() { - this.addEmail = ''; - this.emitChange(); - }, - _resetState() { - var {emails} = this._cleanSlate; - this.emails = emails.slice(); - this.addError = ''; - this.emitChange(); - }, - _updateAddEmail(email) { - this.addEmail = email; - this.emitChange(); - }, - isCleanSlatePrimaryEmail: function(email: string) { - debug('cleanSlate.emails', this._cleanSlate.emails, email); - /** - * A function that answers "is this email address a primary email - * address?" with respect to the database, not with respect - * to the state of the client side application - */ - var primaryEmail = find(this._cleanSlate.emails, function(obj) { - return obj.email === email && obj.primary === true; - }); - - debug('primaryEmail', !!primaryEmail); - return !!primaryEmail; - }, - getCleanSlatePrimaryEmailID() { - return find(this._cleanSlate.emails, function(obj) { - return obj.primary === true; - }).id; - }, - getEmails: function() { - return { - emails: this.emails - }; - }, - getState: function() { - return { - STATUS: this.STATUS, - emails: this.emails, - addEmail: this.addEmail, - addError: this.addError, - emailConfirmations: this.emailConfirmations - }; - }, - dehydrate() { - return merge({}, - this.getState(), - { - _cleanSlate: this._cleanSlate - }); - }, - rehydrate(state) { - this._cleanSlate = state._cleanSlate; - this.addEmail = state.addEmail; - this.emails = state.emails.slice(0); - this.emailConfirmations = state.emailConfirmations; - this.addError = state.addError; - } -}); - -module.exports = EmailsStore; diff --git a/app/scripts/stores/EnterprisePaidFormStore.js b/app/scripts/stores/EnterprisePaidFormStore.js deleted file mode 100644 index f77def90e6..0000000000 --- a/app/scripts/stores/EnterprisePaidFormStore.js +++ /dev/null @@ -1,294 +0,0 @@ -'use strict'; - -import createStore from 'fluxible/addons/createStore'; -import { STATUS } from './common/Constants'; -var debug = require('debug')('EnterprisePaidFormStore'); -import each from 'lodash/collection/each'; -import includes from 'lodash/collection/includes'; -import merge from 'lodash/object/merge'; -import keys from 'lodash/object/keys'; -import has from 'lodash/object/has'; -import mapValues from 'lodash/object/mapValues'; -import isString from 'lodash/lang/isString'; - -var noErrorObj = { - hasError: false, - error: '' -}; - -export default createStore({ - storeName: 'EnterprisePaidFormStore', - handlers: { - ENTERPRISE_PAID_RECEIVE_ORGS: '_receiveOrgs', - ENTERPRISE_PAID_CLEAR_FORM: '_clearStore', - ENTERPRISE_PAID_UPDATE_FIELD_WITH_VALUE: '_updateFieldWithValue', - - ENTERPRISE_PAID_ATTEMPT_START: '_enterprisePaidAttemptStart', - ENTERPRISE_PAID_BAD_REQUEST: '_badRequest', - ENTERPRISE_PAID_SUCCESS: '_signupSuccess', - ENTERPRISE_PAID_FACEPALM: '_facepalm', - - BILLING_SUBMIT_START: '_enterprisePaidAttemptStart', - BILLING_SUBMIT_SUCCESS: '_signupSuccess', - BILLING_SUBMIT_ERROR: '_badRequest', - - GET_RECURLY_ERROR: '_updateRecurlyErrors', - ENTERPRISE_PAID_GET_RECURLY_ERROR: 'recurlyError', - ENTERPRISE_PAID_API_ERROR: '_apiError', - ENTERPRISE_PAID_ERRORS: '_validateErrors', - ENTERPRISE_PAID_POPULATE_FORM: '_populateForm' - }, - initialize() { - this.STATUS = STATUS.DEFAULT; - - this.globalFormError = ''; - this.orgs = []; - - this.fields = { - first_name: {}, - last_name: {}, - postal_code: {}, - number: {}, - month: {}, - year: {}, - cvv: {}, - address1: {}, - city: {}, - state: {}, - country: {}, - expiry: {}, - email: {} - }; - - this.values = { - first_name: '', - last_name: '', - postal_code: '', - number: '', - month: '01', - year: '2015', - cvv: '', - address1: '', - city: '', - state: '', - country: 'US', - last_four: '', - card_type: '', - account_first: '', - account_last: '', - company_name: '', - email: '' - }; - }, - _clearStore(){ - this.initialize(); - this.emitChange(); - }, - _populateForm({ - first_name, - last_name, - zip, - month, - year, - address1, - address2, - city, - state, - country, - last_four, - card_type, - account_first, - account_last, - company_name, - email - }) { - var D = new Date(); - var defaultMonth = D.getMonth(); - var defaultYear = D.getFullYear() + 1; - var defaultCountry = 'US'; - this.fields = { - first_name: {}, - last_name: {}, - postal_code: {}, - number: {}, - month: {}, - year: {}, - cvv: {}, - address1: {}, - address2: {}, - city: {}, - state: {}, - country: {}, - expiry: {}, - email: {} - }; - this.values = { - first_name, - last_name, - postal_code: zip, - month: month || defaultMonth, - year: year || defaultYear, - address1, - address2, - city, - state, - country: country || defaultCountry, - last_four, - card_type, - account_first, - account_last, - company_name, - email - }; - this.STATUS = STATUS.DEFAULT; - this.globalFormError = ''; - this.emitChange(); - }, - _updateRecurlyErrors(error) { - const errorFields = error.fields; - debug('Recurly Form errors', errorFields); - let fieldErrors = { - number: { - hasError: includes(errorFields, 'number'), - error: 'There was an error processing your card' - }, - expiry: { - hasError: includes(errorFields, 'month') || includes(errorFields, 'year'), - error: 'This field is invalid' - }, - cvv: { - hasError: includes(errorFields, 'cvv'), - error: 'This field is invalid' - }, - first_name: { - hasError: includes(errorFields, 'first_name'), - error: 'This field is required' - }, - last_name: { - hasError: includes(errorFields, 'last_name'), - error: 'This field is required' - }, - postal_code: { - hasError: includes(errorFields, 'postal_code'), - error: 'This field is invalid' - } - }; - merge(this.fields, fieldErrors); - this.STATUS = STATUS.DEFAULT; - this.globalFormError = error.message; - this.emitChange(); - }, - _facepalm() { - // this happens if things are screwed and we can't recover gracefully - this.STATUS = STATUS.FACEPALM; - this.emitChange(); - }, - recurlyError(fields) { - this.STATUS = STATUS.DEFAULT; - var emitChange = false; - each(fields, function(val, idx) { - if(includes(keys(this.fields), val)) { - emitChange = true; - this.fields[val] = { - hasError: true, - error: 'This field is required' - }; - } - }, this); - - if(emitChange) { - this.emitChange(); - } - }, - _validateErrors(hasError) { - each(hasError, (v, k) => { - if (v) { - if (includes(['number', 'cvv', 'month', 'year', 'country'], k)) { - this.fields[k] = { - hasError: true, - error: 'Invalid ' + k - }; - } else { - this.fields[k] = { - hasError: true, - error: 'Required' - }; - } - } - }); - this.emitChange(); - }, - _updateFieldWithValue({fieldKey, fieldValue}) { - debug(fieldKey, fieldValue); - this.fields[fieldKey] = {hasError: false, error: ''}; - if (includes(['month', 'year'], fieldKey)) { - this.fields.expiry = {hasError: false, error: ''}; - } - if (fieldKey === 'number') { - let card_type = window.recurly.validate.cardType(fieldValue); - this.values.card_type = card_type; - } - this.values[fieldKey] = fieldValue; - this.emitChange(); - }, - _signupSuccess() { - this.STATUS = STATUS.SUCCESSFUL; - this.emitChange(); - }, - _receiveOrgs(namespaces) { - this.orgs = namespaces; - this.emitChange(); - }, - _apiError() { - this.STATUS = STATUS.FACEPALM; - this.emitChange(); - }, - _enterprisePaidAttemptStart() { - this.STATUS = STATUS.ATTEMPTING; - this.emitChange(); - }, - _badRequest(obj) { - this.STATUS = STATUS.ERROR; - - // cycle through the possible form fields - this.fields = mapValues(this.fields, function (errorObject, key) { - if(has(obj, key)) { - return { - hasError: !!obj[key], - error: obj[key][0] - }; - } else { - return errorObject; - } - }); - - if(has(obj, 'non_field_errors')) { - this.globalFormError = obj.non_field_errors[0]; - } else if (has(obj, 'detail')) { - this.globalFormError = obj.detail; - } else if (isString(obj)) { - this.globalFormError = obj; - } - - this.emitChange(); - }, - getState() { - return { - fields: this.fields, - values: this.values, - STATUS: this.STATUS, - orgs: this.orgs, - globalFormError: this.globalFormError - }; - }, - dehydrate() { - return this.getState(); - }, - rehydrate(state) { - this.orgs = state.orgs; - this.values = state.values; - this.fields = state.fields; - this.STATUS = state.STATUS; - this.globalFormError = this.globalFormError; - } -}); diff --git a/app/scripts/stores/EnterprisePartnerTrackingStore.js b/app/scripts/stores/EnterprisePartnerTrackingStore.js deleted file mode 100644 index 6c5afaea8b..0000000000 --- a/app/scripts/stores/EnterprisePartnerTrackingStore.js +++ /dev/null @@ -1,29 +0,0 @@ -'use strict'; - -import createStore from 'fluxible/addons/createStore'; -var debug = require('debug')('EnterprisePartnerTrackingStore'); - -export default createStore({ - storeName: 'EnterprisePartnerTrackingStore', - handlers: { - ENTERPRISE_PARTNER_RECEIVE_CODE: '_receivePartnerTrackingCode' - }, - initialize() { - this.partnervalue = ''; - }, - _receivePartnerTrackingCode({ code }) { - this.partnervalue = code; - this.emitChange(); - }, - getState() { - return { - partnervalue: this.partnervalue - }; - }, - dehydrate() { - return this.getState(); - }, - rehydrate(state) { - this.partnervalue = state.partnervalue; - } -}); diff --git a/app/scripts/stores/EnterpriseTrialFormStore.js b/app/scripts/stores/EnterpriseTrialFormStore.js deleted file mode 100644 index e967f84876..0000000000 --- a/app/scripts/stores/EnterpriseTrialFormStore.js +++ /dev/null @@ -1,140 +0,0 @@ -'use strict'; - -import createStore from 'fluxible/addons/createStore'; -import { ATTEMPTING, DEFAULT, FACEPALM, SUCCESSFUL_SIGNUP } from 'stores/enterprisetrialstore/Constants'; -var debug = require('debug')('EnterpriseTrialFormStore'); -var _ = require('lodash'); - -var noErrorObj = { - hasError: false, - error: '' -}; - -export default createStore({ - storeName: 'EnterpriseTrialFormStore', - handlers: { - ENTERPRISE_TRIAL_RECEIVE_ORGS: '_receiveOrgs', - ENTERPRISE_TRIAL_CLEAR_FORM: '_clearForm', - ENTERPRISE_TRIAL_UPDATE_FIELD_WITH_VALUE: '_updateFieldWithValue', - ENTERPRISE_TRIAL_ATTEMPT_START: '_attemptStart', - ENTERPRISE_TRIAL_BAD_REQUEST: '_badRequest', - ENTERPRISE_TRIAL_SUCCESS: '_signupSuccess', - ENTERPRISE_TRIAL_FACEPALM: '_facepalm', - CREATED_ORGANIZATION: '_clearForm' - }, - initialize() { - this.STATUS = DEFAULT; - this.orgs = []; - this.globalFormError = ''; - - this.fields = { - firstName: {}, - lastName: {}, - companyName: {}, - jobFunction: {}, - email: {}, - phoneNumber: {}, - country: {}, - state: {}, - namespace: {} - }; - - this.values = { - namespace: '', - firstName: '', - lastName: '', - jobFunction: '', - companyName: '', - email: '', - phoneNumber: '', - country: 'US', - state: '' - }; - }, - _facepalm() { - // this happens if things are screwed and we can't recover gracefully - this.STATUS = FACEPALM; - this.globalFormError = 'Something went wrong on the server. We have been alerted to this issue'; - this.emitChange(); - }, - _clearForm() { - this.initialize(); - this.emitChange(); - }, - _clearErrors() { - this.fields = { - firstName: {}, - lastName: {}, - jobFunction: {}, - companyName: {}, - email: {}, - phoneNumber: {}, - country: {}, - state: {}, - namespace: {} - }; - this.globalFormError = ''; - }, - _updateFieldWithValue({fieldKey, fieldValue}) { - this.STATUS = DEFAULT; - this.globalFormError = ''; - this.values[fieldKey] = fieldValue; - this.emitChange(); - }, - _attemptStart() { - this.STATUS = ATTEMPTING; - this.emitChange(); - }, - _signupSuccess() { - this.STATUS = SUCCESSFUL_SIGNUP; - this._clearErrors(); - this.emitChange(); - }, - _receiveOrgs(namespaces) { - this.orgs = namespaces; - //will always have at least current logged in namespace - this.values.namespace = namespaces[0]; - this.emitChange(); - }, - _badRequest(obj) { - this._clearErrors(); - this.STATUS = DEFAULT; - - // cycle through the possible form fields - this.fields = _.mapValues(this.fields, (errorObject, key) => { - if(_.has(obj, key)) { - return { - hasError: !!obj[key], - error: obj[key][0] - }; - } else { - return errorObject; - } - }); - - if(obj && obj.non_field_errors) { - this.globalFormError = obj.non_field_errors[0]; - } - this.emitChange(); - }, - getState() { - return { - fields: this.fields, - values: this.values, - STATUS: this.STATUS, - orgs: this.orgs, - globalFormError: this.globalFormError - }; - }, - dehydrate() { - return this.getState(); - }, - rehydrate(state) { - this.orgs = state.orgs; - this.fields = state.fields; - this.values = state.values; - this.STATUS = state.STATUS; - this.globalFormError = state.globalFormError; - - } -}); diff --git a/app/scripts/stores/EnterpriseTrialSuccessStore.js b/app/scripts/stores/EnterpriseTrialSuccessStore.js deleted file mode 100644 index b68cf015af..0000000000 --- a/app/scripts/stores/EnterpriseTrialSuccessStore.js +++ /dev/null @@ -1,47 +0,0 @@ -'use strict'; - -import createStore from 'fluxible/addons/createStore'; -import { DEFAULT, - ERROR } from 'stores/enterprisetrialsuccessstore/Constants'; -const debug = require('debug')('EnterpriseTrialSuccessStore'); - -export default createStore({ - storeName: 'EnterpriseTrialSuccessStore', - handlers: { - RECEIVE_TRIAL_LICENSE_FACEPALM: '_facepalm', - RECEIVE_TRIAL_LICENSE: '_receiveTrialLicense', - RECEIVE_TRIAL_LICENSE_BAD_REQUEST: '_receiveTrialLicenseBadRequest' - }, - initialize: function() { - this.license = {}; - this.STATUS = DEFAULT; - }, - _facepalm: function(err) { - this.STATUS = ERROR; - debug(err); - this.emitChange(); - }, - _receiveTrialLicense: function(license) { - this.license = license; - this.emitChange(); - }, - _receiveTrialLicenseBadRequest: function(err) { - this.STATUS = ERROR; - debug(err); - this.emitChange(); - }, - getState: function() { - return { - license: this.license, - STATUS: this.STATUS - }; - }, - rehydrate: function(state) { - this.license = state.license; - this.STATUS = state.STATUS; - }, - dehydrate: function() { - return this.getState(); - } -}); - diff --git a/app/scripts/stores/GithubLinkStore.js b/app/scripts/stores/GithubLinkStore.js deleted file mode 100644 index 212e90a594..0000000000 --- a/app/scripts/stores/GithubLinkStore.js +++ /dev/null @@ -1,61 +0,0 @@ -'use strict'; - -import _ from 'lodash'; -import createStore from 'fluxible/addons/createStore'; -var debug = require('debug')('GithubLinkStore'); - -var GithubLinkStore = createStore({ - storeName: 'GithubLinkStore', - handlers: { - RECEIVE_GITHUB_ID: '_receiveID', - GITHUB_ID_ERROR: '_idError', - GITHUB_SECURITY_ERROR: '_githubSecurityError', - GITHUB_ASSOCIATE_ERROR: '_githubAssociateError' - }, - initialize: function() { - this.githubClientID = ''; - this.error = ''; - }, - _receiveID: function(res) { - this.githubClientID = res.client_id; - this.emitChange(); - }, - _idError: function(err) { - debug(err); - }, - _githubAssociateError: function(body) { - debug(body); - if (_.has(body, 'detail') && _.isString(body.detail)) { - this.error = body.detail; - } else { - this.error = 'There was an error during the Github account link. Please check that you do not have the same Github account linked to another Docker Hub account.'; - } - this.emitChange(); - setTimeout(this._clearError.bind(this), 5000); - }, - _githubSecurityError: function(errorState) { - debug(errorState); - this.error = 'There was a security error during the github account linking process.'; - this.emitChange(); - setTimeout(this._clearError.bind(this), 5000); - }, - _clearError: function() { - this.error = ''; - this.emitChange(); - }, - getState: function() { - return { - githubClientID: this.githubClientID, - error: this.error - }; - }, - rehydrate: function(state) { - this.githubClientID = state.githubClientID; - this.error = state.error; - }, - dehydrate: function() { - return this.getState(); - } -}); - -module.exports = GithubLinkStore; diff --git a/app/scripts/stores/JWTStore.js b/app/scripts/stores/JWTStore.js deleted file mode 100644 index d7fcd3b368..0000000000 --- a/app/scripts/stores/JWTStore.js +++ /dev/null @@ -1,73 +0,0 @@ -'use strict'; -import createStore from 'fluxible/addons/createStore'; -var debug = require('debug')('stores: JWTStore'); -import cookie from 'cookie'; - -export default createStore({ - storeName: 'JWTStore', - handlers: { - RECEIVE_JWT: '_receiveJWT', - LOGOUT: '_logout', - LOGOUT_ERROR: '_logoutError', - EXPIRED_SIGNATURE: '_setExpiredSignature' - }, - _receiveJWT(jwt) { - this.jwt = jwt; - this.signatureIsExpired = false; - this.emitChange(); - }, - _logoutError(err) { - debug(err + ' Logout did not complete cleanly on the server'); - this._logout(); //we logout on the client side anyway - }, - _logout() { - this.jwt = null; - this.emitChange(); - }, - _logoutWithNotification(){ - debug('Logging out due to invalid Signature'); - this._logout(); - }, - _setExpiredSignature(){ - this.signatureIsExpired = true; - this.jwt = null; - this.emitChange(); - }, - getJWT() { - return this.jwt; - }, - getState() { - return { - jwt: this.jwt, - signatureIsExpired: this.signatureIsExpired - }; - }, - isLoggedIn() { - //Return true if user is logged in - return !!this.jwt; - }, - dehydrate() { - if(this.signatureIsExpired) { - return { - jwt: null, - signatureIsExpired: true - }; - } else { - return { - jwt: this.jwt, - signatureIsExpired: false - }; - } - }, - rehydrate(state) { - debug('rehydrate', state); - if(state.signatureIsExpired) { - debug('signatureIsExpired'); - this._logoutWithNotification(); - } else { - debug('signatureIsValid'); - this.signatureIsExpired = state.signatureIsExpired; - this._receiveJWT(state.jwt); - } - } -}); diff --git a/app/scripts/stores/LoginStore.js b/app/scripts/stores/LoginStore.js deleted file mode 100644 index a074541f06..0000000000 --- a/app/scripts/stores/LoginStore.js +++ /dev/null @@ -1,108 +0,0 @@ -'use strict'; - -import _ from 'lodash'; -import { STATUS } from './loginstore/Constants'; -import createStore from 'fluxible/addons/createStore'; -var debug = require('debug')('LoginStore'); - -export default createStore({ - storeName: 'LoginStore', - handlers: { - LOGIN_ATTEMPT_START: '_loginAttemptStart', - LOGIN_UNAUTHORIZED: '_loginUnauthorized', - LOGIN_UNAUTHORIZED_DETAIL: '_loginUnauthorizedDetail', - LOGIN_BAD_REQUEST: '_badRequest', - LOGIN_ERROR: '_loginError', - LOGIN_UPDATE_FIELD_WITH_VALUE: '_updateFieldWithValue', - LOGIN_CLEAR: '_clearLoginForm' - }, - initialize() { - this.STATUS = STATUS.DEFAULT; - this.globalFormError = ''; - - this.fields = { - username: {}, - password: {} - }; - - this.values = { - username: '', - password: '' - }; - }, - _clearLoginForm() { - debug('Clearing'); - this.initialize(); - this.emitChange(); - }, - _loginAttemptStart() { - this.STATUS = STATUS.ATTEMPTING_LOGIN; - this.emitChange(); - }, - _loginError(err){ - this.STATUS = STATUS.GENERIC_ERROR; - this.globalFormError = 'There was an error contacting the server. Please try again later.'; - this.emitChange(); - }, - _badRequest(obj) { - this.STATUS = STATUS.DEFAULT; - /** - * This function expects keys which match the `this.fields` keys - * with an array of errors: - * - * { - * username: ['this field is required'] - * } - */ - let shouldEmitChange = false; - - // cycle through the possible form fields - this.fields = _.mapValues(this.fields, function (errorObject, key) { - if(_.has(obj, key)) { - shouldEmitChange = true; - return { - hasError: !!obj[key], - error: obj[key][0] - }; - } else { - return errorObject; - } - }); - - if(shouldEmitChange) { - this.emitChange(); - } - }, - _loginUnauthorized() { - this.STATUS = STATUS.ERROR_UNAUTHORIZED; - this.globalFormError = 'Login Failed. The username or password may be incorrect.'; - this.emitChange(); - }, - _loginUnauthorizedDetail({detail}) { - this.STATUS = STATUS.ERROR_UNAUTHORIZED; - this.globalFormError = detail; - this.emitChange(); - }, - getState() { - return { - fields: this.fields, - values: this.values, - STATUS: this.STATUS, - globalFormError: this.globalFormError - }; - }, - _updateFieldWithValue: function({fieldKey, fieldValue}){ - this.fields[fieldKey] = { - hasError: false, - error: '' - }; - this.values[fieldKey] = fieldValue; - this.emitChange(); - }, - dehydrate: function() { - return {}; - }, - rehydrate: function(state) { - this.state = state; - } -}); diff --git a/app/scripts/stores/NotifyStore.js b/app/scripts/stores/NotifyStore.js deleted file mode 100644 index 57c2cc30b5..0000000000 --- a/app/scripts/stores/NotifyStore.js +++ /dev/null @@ -1,44 +0,0 @@ -'use strict'; - -/** - * displays alert-style dismissable notifications to the user - */ - -const createStore = require('fluxible/addons/createStore'); -const debug = require('debug')('NotifyStore'); - -var NotifyStore = createStore({ - storeName: 'NotifyStore', - handlers: { - NEW_ALERT: '_newAlert', - EXPIRE_ALERT: '_expireAlert', - EXPIRED_SIGNATURE: '_newDetailAlert' - }, - initialize: function() { - // alerts have a timestamp-based key - this.alerts = {}; - }, - _newAlert: function(obj) { - this.alerts[+new Date()] = obj.msg; - debug(this.alerts); - this.emitChange(); - }, - _newDetailAlert: function(msg) { - debug(msg); - this._newAlert({ - msg: 'You have been logged out because your token has expired or was invalid' - }); - }, - getState: function() { - return this.state; - }, - dehydrate: function() { - return this.getState(); - }, - rehydrate: function(state) { - debug(state); - this.alerts = state.alerts; - } -}); - -module.exports = NotifyStore; diff --git a/app/scripts/stores/OrgTeamStore.js b/app/scripts/stores/OrgTeamStore.js deleted file mode 100644 index cc8b54ed7f..0000000000 --- a/app/scripts/stores/OrgTeamStore.js +++ /dev/null @@ -1,90 +0,0 @@ -'use strict'; - -import createStore from 'fluxible/addons/createStore'; -import { STATUS } from './orgteamstore/Constants'; - -var OrgTeamStore = createStore({ - storeName: 'OrgTeamStore', - handlers: { - CREATE_ORG_TEAM: '_createOrgTeam', - RECEIVE_ORG_TEAM: '_receiveOrgTeam', - RECEIVE_TEAM_MEMBERS: '_receiveOrgMembers', - TEAM_ERROR: '_orgTeamError', - TEAM_BAD_REQUEST: '_teamBadRequest', - TEAM_UNAUTHORIZED: '_teamUnauthorized', - ORG_TEAM_CLEAR_ERROR_STATES: '_clearErrorStates' - }, - initialize: function() { - // initialize - this.name = ''; - this.description = ''; - this.members = []; - this.errorDetails = {}; - this.success = ''; - this.STATUS = STATUS.DEFAULT; - }, - //TODO: this will be removed once we have API - _createOrgTeam: function(payload) { - this.name = payload.name; - this.description = payload.description; - this.STATUS = STATUS.CREATE_TEAM_SUCCESS; - this.emitChange(); - }, - _receiveOrgTeam: function(orgTeam) { - this.name = orgTeam.name; - this.description = orgTeam.description; - this.emitChange(); - }, - _receiveOrgMembers: function(members) { - this.members = members; - this.emitChange(); - }, - _orgTeamError: function(err) { - this.STATUS = STATUS.TEAM_ERROR; - this.STATUS = STATUS.GENERAL_SERVER_ERROR; - this.errorDetails = {detail: 'Error updating team. Check if name is between 3 and 30 characters with no spaces.'}; - this.emitChange(); - }, - _teamBadRequest: function(err) { - this.STATUS = STATUS.TEAM_BAD_REQUEST; - this.errorDetails = {detail: 'Please check your input values. The team name may already exist or the characters may be invalid.'}; - this.emitChange(); - }, - _teamUnauthorized: function(err) { - this.STATUS = STATUS.TEAM_UNAUTHORIZED; - this.errorDetails = {detail: 'You have no permission to edit this team.'}; - this.emitChange(); - }, - _clearErrorStates: function() { - this.errorDetails = {}; - this.success = ''; - this.STATUS = STATUS.DEFAULT; - this.emitChange(); - }, - getState: function() { - return { - name: this.name, - description: this.description, - members: this.members, - errorDetails: this.errorDetails, - success: this.success, - STATUS: this.STATUS - }; - }, - getMembers: function() { - return this.members; - }, - dehydrate: function() { - return this.getState(); - }, - rehydrate: function(state) { - this.name = state.name; - this.description = state.description; - this.members = state.members; - this.errorDetails = state.errorDetails; - this.success = state.success; - this.STATUS = state.STATUS; - } -}); - -module.exports = OrgTeamStore; diff --git a/app/scripts/stores/OrganizationStore.js b/app/scripts/stores/OrganizationStore.js deleted file mode 100644 index 9b12f12b70..0000000000 --- a/app/scripts/stores/OrganizationStore.js +++ /dev/null @@ -1,130 +0,0 @@ -'use strict'; - -import createStore from 'fluxible/addons/createStore'; -import _ from 'lodash'; - -var OrganizationStore = createStore({ - storeName: 'OrganizationStore', - handlers: { - RECEIVE_ORGANIZATION: '_updateOrg', - CREATED_ORGANIZATION: '_onCreateOrg', - SELECT_ORGANIZATION: '_onCurrentOrgChange', - RECEIVE_ORG_TEAMS: '_receiveOrgTeams', - CURRENT_USER_ORGS: '_onGetCurrentOrgs', - UPDATE_ORG_SUCCESS: '_updateOrgSuccess', - UPDATE_ORG_ERROR: '_updateOrgError' - }, - initialize: function() { - // initialize - this.name = ''; - this.gravatarURL = 'https://secure.gravatar.com/avatar/00000000000000000000000000000000?d=retro&f=y'; - this.currentOrg = {}; - this.orgs = []; - this.currentOrgTeams = []; - this.success = ''; - this.error = ''; - }, - _onCreateOrg: function(payload) { - this.receiveState({ - currentOrg: payload.newOrg, - orgs: payload.userOrgs - }); - this.emitChange(); - }, - _updateOrg: function(payload) { - this.receiveState({ - currentOrg: payload - }); - this.emitChange(); - }, - _onGetCurrentOrgs: function(payload) { - this.receiveState({ - orgs: payload.results - }); - this.emitChange(); - }, - _onCurrentOrgChange: function(payload) { - this.receiveState({ - currentOrg: this.getOrg(payload) - }); - this.emitChange(); - }, - _receiveOrgTeams: function(orgTeams) { - this.receiveState({ - currentOrgTeams: orgTeams.results - }); - this.emitChange(); - }, - _updateOrgSuccess: function() { - this.success = 'Updated Organization Details Successfully!'; - setTimeout(this._clearOrgErrorStates.bind(this), 5000); - this.emitChange(); - }, - _updateOrgError: function(err) { - var errResponse = err.response; - if (errResponse.badRequest) { - _.forIn(errResponse.body, function(v, k) { - this.error += k + ': ' + v.join(',') + '\n'; - }.bind(this)); - } else if(errResponse.unauthorized || errResponse.forbidden) { - this.error = 'You have no permission to edit this organization.'; - } else { - this.error = 'An error occurred during the organization update. Please try again later'; - } - setTimeout(this._clearOrgErrorStates.bind(this), 5000); - this.emitChange(); - }, - _clearOrgErrorStates: function() { - this.success = ''; - this.error = ''; - this.emitChange(); - }, - receiveState: function(payload) { - this.name = payload.orgname || this.name; - this.gravatarURL = payload.gravatar_url || this.gravatarURL; - this.currentOrg = payload.currentOrg || this.currentOrg; - this.currentOrgTeams = payload.currentOrgTeams || this.currentOrgTeams; - this.orgs = payload.orgs || this.orgs; - }, - getState: function() { - return { - name: this.name, - gravatarURL: this.gravatarURL, - currentOrg: this.currentOrg, - currentOrgTeams: this.currentOrgTeams, - orgs: this.orgs, - error: this.error, - success: this.success - }; - }, - getOrgs: function() { - return this.orgs; - }, - getCurrentOrg: function() { - //returns currently selected org - return this.currentOrg; - }, - getOrg: function(name) { - //Assuming org names are unique and expecting filter to return an array of exactly 1 item - return _.filter(this.orgs, function(org) { - return org.orgname === name; - })[0]; - }, - getOrgTeams: function() { - return this.currentOrgTeams; - }, - dehydrate: function() { - return this.getState(); - }, - rehydrate: function(state) { - this.name = state.name; - this.gravatarURL = state.gravatarURL; - this.currentOrg = state.currentOrg; - this.currentOrgTeams = state.currentOrgTeams; - this.orgs = state.orgs; - this.error = state.error; - this.success = state.success; - } -}); - -module.exports = OrganizationStore; diff --git a/app/scripts/stores/OutboundCommunicationStore.js b/app/scripts/stores/OutboundCommunicationStore.js deleted file mode 100644 index 6aa321d62c..0000000000 --- a/app/scripts/stores/OutboundCommunicationStore.js +++ /dev/null @@ -1,90 +0,0 @@ -'use strict'; - -import createStore from 'fluxible/addons/createStore'; -import _ from 'lodash'; -import { STATUS } from './common/Constants'; -var debug = require('debug')('AccountNotifStore:'); - -export default createStore({ - storeName: 'OutboundCommunicationStore', - handlers: { - RECEIVE_EMAIL_SUBSCRIPTIONS: '_receiveEmailSubscriptions', - RESET_OUTBOUND_EMAILS_STORE: '_resetBlankSlate', - SAVE_OUTBOUND_ERROR: '_saveOutboundError', - SAVE_OUTBOUND_SUCCESS: '_saveOutboundSuccess', - UPDATE_OUTBOUND: '_updateOutbound', - UPDATE_BETA_GROUP: '_updateBetaGroup' - }, - initialize: function() { - // initialize with data from db - /*eslint-disable camelcase */ - this.weeklyDigest = { - subscribed_emails: [], - unsubscribed_emails: [] - }; - this.digestEmails = []; - this.betaGroup = { - subscribed_emails: [], - unsubscribed_emails: [] - }; - /*eslint-enable camelcase */ - this.betaEmails = []; - this.STATUS = STATUS.DEFAULT; - this.blankOutboundSlate = {}; - }, - _receiveEmailSubscriptions: function(payload) { - this.weeklyDigest = payload.weeklyDigest; - this.digestEmails = payload.weeklyDigest.subscribed_emails.concat(payload.weeklyDigest.unsubscribed_emails); - this.betaGroup = payload.betaGroup; - this.betaEmails = payload.betaGroup.subscribed_emails.concat(payload.betaGroup.unsubscribed_emails); - this.blankOutboundSlate = this.getState(); - this.emitChange(); - }, - _resetBlankSlate: function() { - var slate = this.blankOutboundSlate; - debug('RESET OUTBOUND BLANK SLATE'); - this.weeklyDigest = slate.weeklyDigest; - this.digestEmails = slate.digestEmails; - this.betaGroup = slate.betaGroup; - this.betaEmails = slate.betaEmails; - this.STATUS = STATUS.DEFAULT; - this.emitChange(); - }, - _updateOutbound: function(newList) { - this.STATUS = STATUS.DEFAULT; - if (newList.list === 'weekly') { - this.weeklyDigest = newList.data; - } else if (newList.list === 'beta') { - this.betaGroup = newList.data; - } - this.emitChange(); - }, - _saveOutboundError: function() { - this.STATUS = 'ERROR'; - this.emitChange(); - }, - _saveOutboundSuccess: function() { - this.STATUS = STATUS.SUCCESSFUL; - this.emitChange(); - }, - getState: function() { - return { - weeklyDigest: this.weeklyDigest, - digestEmails: this.digestEmails, - betaGroup: this.betaGroup, - betaEmails: this.betaEmails, - STATUS: this.STATUS - }; - }, - dehydrate: function() { - return _.merge({}, this.getState(), {blankOutboundSlate: this.blankOutboundSlate}); - }, - rehydrate: function(state) { - this.weeklyDigest = state.weeklyDigest; - this.digestEmails = state.digestEmails; - this.betaGroup = state.betaGroup; - this.betaEmails = state.betaEmails; - this.STATUS = state.STATUS; - this.blankOutboundSlate = state.blankOutboundSlate; - } -}); diff --git a/app/scripts/stores/PipelineHistoryStore.js b/app/scripts/stores/PipelineHistoryStore.js deleted file mode 100644 index 59b9494f2d..0000000000 --- a/app/scripts/stores/PipelineHistoryStore.js +++ /dev/null @@ -1,31 +0,0 @@ -'use strict'; - -import createStore from 'fluxible/addons/createStore'; -const debug = require('debug')('PipelineHistory'); - -export default createStore({ - storeName: 'PipelineHistoryStore', - handlers: { - RECEIVE_PIPELINE_HISTORY: '_receivePipelineHistory' - }, - initialize() { - this.results = {}; - }, - _receivePipelineHistory(data) { - this.results[data.slug] = {}; - this.results[data.slug].results = data.payload.results; - this.results[data.slug].count = data.payload.count; - this.emitChange(); - }, - getState() { - return { - results: this.results - }; - }, - dehydrate() { - return this.getState(); - }, - rehydrate(state) { - this.results = state.results; - } -}); diff --git a/app/scripts/stores/PlansStore.js b/app/scripts/stores/PlansStore.js deleted file mode 100644 index 8ac12e6c89..0000000000 --- a/app/scripts/stores/PlansStore.js +++ /dev/null @@ -1,74 +0,0 @@ -'use strict'; -import createStore from 'fluxible/addons/createStore'; -var debug = require('debug')('PlansStore'); - -var PlansStore = createStore({ - storeName: 'PlansStore', - handlers: { - RECEIVE_BILLING_PLANS: '_receivePlans', - RECEIVE_BILLING_INFO: '_receiveBilling', - RECEIVE_BILLING_SUBSCRIPTION: '_receiveBillingSubscription', - RESET_CURRENT_PLAN: '_resetCurrentPlan' - }, - initialize: function() { - this.plansList = []; - this.currentPlan = { - plan: '', - package: '', - subscription_uuid: '', - state: '', - add_ons: [] - }; - }, - _clearPlan: function() { - this.currentPlan = { - plan: '', - package: '', - subscription_uuid: '', - state: '', - add_ons: [] - }; - }, - _receiveBilling: function(payload){ - debug('RECEIVE BILLING: ', payload); - this._clearPlan(); - if (payload.currentPlan) { - this.currentPlan = payload.currentPlan; - } - this.emitChange(); - }, - _receiveBillingSubscription: function(payload) { - this._clearPlan(); - if (payload.currentPlan) { - this.currentPlan = payload.currentPlan; - } - this.emitChange(); - }, - _resetCurrentPlan: function(payload) { - this._clearPlan(); - if (payload.currentPlan) { - this.currentPlan = payload.currentPlan; - } - this.emitChange(); - }, - _receivePlans: function(payload) { - debug(payload); - this.plansList = payload.plansList; - this.emitChange(); - }, - getState() { - return { - plansList: this.plansList, - currentPlan: this.currentPlan - }; - }, - dehydrate() { - return this.getState(); - }, - rehydrate(state) { - this.plansList = state.plansList; - this.currentPlan = state.currentPlan; - } -}); - -module.exports = PlansStore; diff --git a/app/scripts/stores/PrivateRepoUsageStore.js b/app/scripts/stores/PrivateRepoUsageStore.js deleted file mode 100644 index ab21e79cc1..0000000000 --- a/app/scripts/stores/PrivateRepoUsageStore.js +++ /dev/null @@ -1,63 +0,0 @@ -'use strict'; - -import createStore from 'fluxible/addons/createStore'; -var debug = require('debug')('PrivateReposUsageStore'); - -var PrivateRepoUsageStore = createStore({ - storeName: 'PrivateRepoUsageStore', - handlers: { - RECEIVE_PRIVATE_REPOSTATS: '_receivePrivateRepoStats', - PRIVATE_REPOSTATS_NO_PERMISSIONS: '_notAvailable' - }, - initialize: function() { - this.privateRepoUsed = 0; - this.numFreePrivateRepos = 0; - this.defaultRepoVisibility = 'public'; - this.privateRepoAvailable = 0; - this.privateRepoPercentUsed = 0; - this.privateRepoLimit = 0; - this.notAvailable = false; - }, - _receivePrivateRepoStats: function(stats) { - this.notAvailable = false; - /*eslint-disable camelcase */ - this.privateRepoUsed = stats.private_repo_used; - this.numFreePrivateRepos = stats.num_free_private_repos; - this.defaultRepoVisibility = stats.default_repo_visibility; - this.privateRepoAvailable = stats.private_repo_available; - this.privateRepoPercentUsed = stats.private_repo_percent_used; - this.privateRepoLimit = stats.private_repo_limit; - /*eslint-enable camelcase */ - this.emitChange(); - }, - _notAvailable: function(err) { - //No permissions to see the private repo stats for this org - this.notAvailable = true; - this.emitChange(); - }, - getState: function() { - return { - privateRepoUsed: this.privateRepoUsed, - numFreePrivateRepos: this.numFreePrivateRepos, - defaultRepoVisibility: this.defaultRepoVisibility, - privateRepoAvailable: this.privateRepoAvailable, - privateRepoPercentUsed: this.privateRepoPercentUsed, - privateRepoLimit: this.privateRepoLimit, - notAvailable: this.notAvailable - }; - }, - dehydrate: function() { - return this.getState(); - }, - rehydrate: function(state) { - this.privateRepoUsed = state.privateRepoUsed; - this.numFreePrivateRepos = state.numFreePrivateRepos; - this.defaultRepoVisibility = state.defaultRepoVisibility; - this.privateRepoAvailable = state.privateRepoAvailable; - this.privateRepoPercentUsed = state.privateRepoPercentUsed; - this.privateRepoLimit = state.privateRepoLimit; - this.notAvailable = state.notAvailable; - } -}); - -module.exports = PrivateRepoUsageStore; diff --git a/app/scripts/stores/RepoDetailsBuildLogs.js b/app/scripts/stores/RepoDetailsBuildLogs.js deleted file mode 100644 index 9d263b87b7..0000000000 --- a/app/scripts/stores/RepoDetailsBuildLogs.js +++ /dev/null @@ -1,29 +0,0 @@ -'use strict'; - -import createStore from 'fluxible/addons/createStore'; -var debug = require('debug')('RepoDetailsBuildLogsStore'); - -export default createStore({ - storeName: 'RepoDetailsBuildLogsStore', - handlers: { - BUILD_LOGS_RECEIVE: '_receiveBuildLogs' - }, - initialize() { - this.build_results = {}; - }, - _receiveBuildLogs(res) { - this.build_results = res.build_results; - this.emitChange(); - }, - getState() { - return { - build_results: this.build_results - }; - }, - rehydrate(state) { - this.build_results = state.build_results; - }, - dehydrate() { - return this.getState(); - } -}); diff --git a/app/scripts/stores/RepoDetailsBuildsStore.js b/app/scripts/stores/RepoDetailsBuildsStore.js deleted file mode 100644 index 793feeddad..0000000000 --- a/app/scripts/stores/RepoDetailsBuildsStore.js +++ /dev/null @@ -1,79 +0,0 @@ -'use strict'; - -import createStore from 'fluxible/addons/createStore'; -import find from 'lodash/collection/find'; -import map from 'lodash/collection/map'; -import assign from 'lodash/object/assign'; - -const debug = require('debug')('RepoDetailsBuildsStore'); - -const RepoDetailsBuildsStore = createStore({ - storeName: 'RepoDetailsBuildsStore', - handlers: { - RECEIVE_BUILD_HISTORY_FOR_REPOSITORY: '_receiveBuilds', - CANCEL_BUILD_START: '_cancelBuildStart', - CANCEL_BUILD_SUCCESS: '_cancelBuildSuccess', - CANCEL_BUILD_ERROR: '_cancelBuildError' - } - , - initialize() { - this.results = []; - this.canceling = {}; - this.count = 0; - }, - - _cancelBuildStart(id) { - this.canceling = { - ...this.canceling, - [id]: 'queued' - }; - this.emitChange(); - }, - - _cancelBuildSuccess(id) { - this.canceling = { - ...this.canceling, - [id]: 'success' - }; - this.emitChange(); - }, - - _cancelBuildError({ id, detail }) { - this.canceling = { - ...this.canceling, - [id]: 'failed' - }; - this.emitChange(); - }, - - _receiveBuilds(res) { - debug('receiving builds', res); - this.results = res.results; - this.count = res.count; - this.emitChange(); - }, - - getState: function() { - let results = this.results; - if (this.canceling !== undefined) { - results = map(this.results, (v) => assign(v, { canceling: this.canceling[v.id] })); - } - return { - count: this.count, - canceling: this.canceling, - results - }; - }, - - rehydrate(state) { - this.results = state.results; - this.count = state.count; - this.canceling = state.canceling || {}; - }, - - dehydrate() { - return this.getState(); - } -}); - -export default RepoDetailsBuildsStore; diff --git a/app/scripts/stores/RepoDetailsDockerfileStore.js b/app/scripts/stores/RepoDetailsDockerfileStore.js deleted file mode 100644 index ed1a1aee22..0000000000 --- a/app/scripts/stores/RepoDetailsDockerfileStore.js +++ /dev/null @@ -1,32 +0,0 @@ -'use strict'; - -import createStore from 'fluxible/addons/createStore'; -var debug = require('debug')('RepoDetailsDockerfileStore'); - -var RepoDetailsDockerfileStore = createStore({ - storeName: 'RepoDetailsDockerfileStore', - handlers: { - RECEIVE_DOCKERFILE_FOR_REPOSITORY: '_receiveDockerfile' - }, - initialize: function() { - this.dockerfile = ''; - }, - _receiveDockerfile: function(res) { - debug('dockerfile', res); - this.dockerfile = res.contents; - this.emitChange(); - }, - getState: function() { - return { - dockerfile: this.dockerfile - }; - }, - rehydrate: function(state) { - this.dockerfile = state.dockerfile; - }, - dehydrate: function() { - return this.getState(); - } -}); - -module.exports = RepoDetailsDockerfileStore; diff --git a/app/scripts/stores/RepoDetailsLongDescriptionFormStore.js b/app/scripts/stores/RepoDetailsLongDescriptionFormStore.js deleted file mode 100644 index d9ce6e5b60..0000000000 --- a/app/scripts/stores/RepoDetailsLongDescriptionFormStore.js +++ /dev/null @@ -1,116 +0,0 @@ -'use strict'; - -import _ from 'lodash'; -import createStore from 'fluxible/addons/createStore'; -var debug = require('debug')('RepoDetailsLongDescriptionFormStore'); - -export default createStore({ - storeName: 'RepoDetailsLongDescriptionFormStore', - handlers: { - RECEIVE_REPOSITORY: '_receiveRepository', - LONG_DESCRIPTION_ATTEMPT_START: '_longDescriptionAttemptStart', - LONG_DESCRIPTION_SUCCESS: '_longDescriptionSuccess', - DETAILS_UNAUTHORIZED: '_detailsUnauthorized', - DETAILS_UNAUTHORIZED_DETAIL: '_detailsUnauthorizedDetail', - LONG_BAD_REQUEST: '_badRequest', - DETAILS_ERROR: '_detailsError', - LONG_DESCRIPTION_UPDATE_FIELD_WITH_VALUE: '_updateFieldWithValue', - DETAILS_RESET_FORMS: '_detailsResetForms', - TOGGLE_LONG_DESCRIPTION_EDIT: '_toggleEditMode' - }, - initialize: function() { - this.isEditing = false; - this.successfulSave = false; - this.fields = { - longDescription: {} - }; - - this._defaultValues = { - longDescription: '' - }; - - this.values = { - longDescription: '' - }; - }, - _longDescriptionAttemptStart() { - debug('starting long description update'); - }, - _longDescriptionSuccess() { - this.fields.longDescription.success = 'Successfully updated full description.'; - //switch back to viewing mode with green outline - this.successfulSave = true; - this.isEditing = false; - this._defaultValues.longDescription = this.values.longDescription; - //clear the green outline and text on successful save - setTimeout(this._clearFeedbackStates.bind(this), 5000); - setTimeout(this._clearSuccessfulSave.bind(this), 5000); - this.emitChange(); - }, - _receiveRepository(repo) { - this.isEditing = false; - this.values.longDescription = repo.full_description || ''; - this._defaultValues.longDescription = repo.full_description || ''; - this.emitChange(); - }, - _detailsResetForms() { - // reset form value to repo longdescription - this.values.longDescription = this._defaultValues.longDescription; - // reset errors - this.fields.longDescription = {}; - this.emitChange(); - }, - _badRequest(obj) { - this.fields.longDescription.hasError = !!obj.full_description; - this.fields.longDescription.error = obj.full_description[0]; - setTimeout(this._clearFeedbackStates.bind(this), 5000); - this.emitChange(); - }, - _detailsError() { - this.fields.longDescription.hasError = true; - this.fields.longDescription.error = 'Sorry, your long description could not be saved.'; - setTimeout(this._clearFeedbackStates.bind(this), 5000); - this.emitChange(); - }, - _clearFeedbackStates() { - this.fields.longDescription.error = ''; - this.fields.longDescription.hasError = false; - this.fields.longDescription.success = ''; - this.emitChange(); - }, - _clearSuccessfulSave() { - this.successfulSave = false; - this.emitChange(); - }, - _updateFieldWithValue: function({fieldKey, fieldValue}){ - this.values[fieldKey] = fieldValue; - this.emitChange(); - }, - _toggleEditMode( { isEditing }) { - this.isEditing = isEditing; - //if you cancel, clear the old input - this.values.longDescription = this._defaultValues.longDescription; - //in case you recently saved and you now cancel - this._clearSuccessfulSave(); - this.emitChange(); - }, - getState() { - return { - _defaultValues: this._defaultValues, - fields: this.fields, - values: this.values, - isEditing: this.isEditing, - successfulSave: this.successfulSave - }; - }, - dehydrate: function() { - return this.getState(); - }, - rehydrate: function(state) { - this._defaultValues = state._defaultValues; - this.fields = state.fields; - this.values = state.values; - this.isEditing = state.isEditing; - this.successfulSave = state.successfulSave; - } -}); diff --git a/app/scripts/stores/RepoDetailsShortDescriptionFormStore.js b/app/scripts/stores/RepoDetailsShortDescriptionFormStore.js deleted file mode 100644 index 1f573f12cb..0000000000 --- a/app/scripts/stores/RepoDetailsShortDescriptionFormStore.js +++ /dev/null @@ -1,116 +0,0 @@ -'use strict'; - -import _ from 'lodash'; -import createStore from 'fluxible/addons/createStore'; -var debug = require('debug')('RepoDetailsShortDescriptionFormStore'); - -export default createStore({ - storeName: 'RepoDetailsShortDescriptionFormStore', - handlers: { - RECEIVE_REPOSITORY: '_receiveRepository', - SHORT_DESCRIPTION_ATTEMPT_START: '_shortDescriptionAttemptStart', - SHORT_DESCRIPTION_SUCCESS: '_shortDescriptionSuccess', - DETAILS_UNAUTHORIZED: '_detailsUnauthorized', - DETAILS_UNAUTHORIZED_DETAIL: '_detailsUnauthorizedDetail', - SHORT_BAD_REQUEST: '_badRequest', - DETAILS_ERROR: '_detailsError', - SHORT_DESCRIPTION_UPDATE_FIELD_WITH_VALUE: '_updateFieldWithValue', - DETAILS_RESET_FORMS: '_detailsResetForms', - TOGGLE_SHORT_DESCRIPTION_EDIT: '_toggleEditMode' - }, - initialize: function() { - this.isEditing = false; - this.successfulSave = false; - this.fields = { - shortDescription: {} - }; - - this._defaultValues = { - shortDescription: '' - }; - - this.values = { - shortDescription: '' - }; - }, - _shortDescriptionAttemptStart() { - debug('starting short description update'); - }, - _shortDescriptionSuccess() { - this.fields.shortDescription.success = 'Successfully updated short description.'; - //switch back to viewing mode with green outline - this.successfulSave = true; - this.isEditing = false; - this._defaultValues.shortDescription = this.values.shortDescription; - //clear the green outline and text on successful save - setTimeout(this._clearFeedbackStates.bind(this), 5000); - setTimeout(this._clearSuccessfulSave.bind(this), 5000); - this.emitChange(); - }, - _receiveRepository(repo) { - this.isEditing = false; - this.values.shortDescription = repo.description; - this._defaultValues.shortDescription = repo.description; - this.emitChange(); - }, - _detailsResetForms() { - // reset form value to repo shortdescription - this.values.shortDescription = this._defaultValues.shortDescription; - // reset errors - this.fields.shortDescription = {}; - this.emitChange(); - }, - _detailsError() { - this.fields.longDescription.hasError = true; - this.fields.longDescription.error = 'Sorry, your long description could not be saved.'; - setTimeout(this._clearFeedbackStates.bind(this), 5000); - this.emitChange(); - }, - _badRequest(obj) { - this.fields.shortDescription.hasError = true; - this.fields.shortDescription.error = obj.description[0]; - setTimeout(this._clearFeedbackStates.bind(this), 5000); - this.emitChange(); - }, - _clearFeedbackStates() { - this.fields.shortDescription.error = ''; - this.fields.shortDescription.hasError = false; - this.fields.shortDescription.success = ''; - this.emitChange(); - }, - _clearSuccessfulSave() { - this.successfulSave = false; - this.emitChange(); - }, - _updateFieldWithValue: function({fieldKey, fieldValue}){ - this.values[fieldKey] = fieldValue; - this.emitChange(); - }, - _toggleEditMode( { isEditing }) { - this.isEditing = isEditing; - //if you cancel, clear the old input - this.values.shortDescription = this._defaultValues.shortDescription; - //in case you recently saved and you now cancel - this._clearSuccessfulSave(); - this.emitChange(); - }, - getState() { - return { - _defaultValues: this._defaultValues, - fields: this.fields, - values: this.values, - isEditing: this.isEditing, - successfulSave: this.successfulSave - }; - }, - dehydrate: function() { - return this.getState(); - }, - rehydrate: function(state) { - this._defaultValues = state._defaultValues; - this.fields = state.fields; - this.values = state.values; - this.isEditing = state.isEditing; - this.successfulSave = state.successfulSave; - } -}); diff --git a/app/scripts/stores/RepoDetailsVisibilityFormStore.js b/app/scripts/stores/RepoDetailsVisibilityFormStore.js deleted file mode 100644 index 1ef9872139..0000000000 --- a/app/scripts/stores/RepoDetailsVisibilityFormStore.js +++ /dev/null @@ -1,113 +0,0 @@ -'use strict'; - -import createStore from 'fluxible/addons/createStore'; -import { STATUS } from './repovisibilitystore/Constants.js'; -const debug = require('debug')('RepoDetailsVisibilityFormStore'); - -var RepoDetailsVisibilityFormStore = createStore({ - storeName: 'RepoDetailsVisibilityFormStore', - handlers: { - VISIBILITY_BAD_REQUEST: '_badRequest', - VISIBILITY_ERROR: '_visibilityError', - TOGGLE_VISIBILITY_ATTEMPT_START: '_toggleVisibilityAttemptStart', - TOGGLE_VISIBILITY_SUCCESS: '_toggleSuccess', - RECEIVE_PRIVATE_REPOSTATS: '_receivePrivateRepoStats', - RECEIVE_REPOSITORY: '_receiveRepository', - REPO_DETAILS_VISIBILITY_UPDATE_FIELD_WITH_VALUE: '_updateFieldWithValue', - TOGGLE_VISIBILITY_REPO_NAME_CONFIRM_BOX: '_toggleConfirmBox' - }, - initialize: function() { - this.badRequest = ''; - this.error = ''; - this.success = ''; - this.isPrivate = false; - this.privateRepoLimit = null; - this.numPrivateReposAvailable = null; - this.STATUS = STATUS.DEFAULT; - this.values = { - confirmRepoName: '' - }; - }, - _badRequest: function(res) { - this.initialize(); - this.badRequest = res.detail; - this.STATUS = STATUS.FORM_ERROR; - this.emitChange(); - }, - _clearErrors: function () { - this.error = ''; - this.badRequest = ''; - }, - _toggleVisibilityAttemptStart: function() { - this.STATUS = STATUS.ATTEMPTING; - this.emitChange(); - }, - _visibilityError: function(maybeError) { - this.STATUS = STATUS.FORM_ERROR; - if (maybeError) { - this.error = maybeError.detail; - } else { - this.error = 'No private repositories available'; - } - this.emitChange(); - }, - _toggleSuccess: function(isPrivate) { - this.initialize(); - this.isPrivate = isPrivate; - this.emitChange(); - }, - _toggleConfirmBox: function() { - if (this.STATUS === STATUS.DEFAULT) { - this.STATUS = STATUS.SHOWING_CONFIRM_BOX; - } else { - this.STATUS = STATUS.DEFAULT; - } - this._clearErrors(); - this.values.confirmRepoName = ''; - this.emitChange(); - }, - _receivePrivateRepoStats: function(stats) { - /*eslint-disable camelcase */ - this.numPrivateReposAvailable = stats.private_repo_available; - this.privateRepoLimit = stats.private_repo_limit; - /*eslint-enable camelcase */ - this.emitChange(); - }, - _receiveRepository: function(res) { - this.initialize(); - this.isPrivate = res.is_private; - this.emitChange(); - }, - _updateFieldWithValue: function({fieldKey, fieldValue}){ - this.values[fieldKey] = fieldValue; - this._clearErrors(); - this.emitChange(); - }, - getState: function() { - return { - badRequest: this.badRequest, - error: this.error, - success: this.success, - isPrivate: this.isPrivate, - privateRepoLimit: this.privateRepoLimit, - numPrivateReposAvailable: this.numPrivateReposAvailable, - values: this.values, - STATUS: this.STATUS - }; - }, - dehydrate: function() { - return this.getState(); - }, - rehydrate: function(state) { - this.badRequest = state.badRequest; - this.error = state.error; - this.success = state.success; - this.isPrivate = state.isPrivate; - this.numPrivateReposAvailable = state.numPrivateReposAvailable; - this.privateRepoLimit = state.privateRepoLimit; - this.values = state.values; - this.STATUS = state.STATUS; - } -}); - -module.exports = RepoDetailsVisibilityFormStore; diff --git a/app/scripts/stores/RepoSettingsCollaborators.jsx b/app/scripts/stores/RepoSettingsCollaborators.jsx deleted file mode 100644 index 20705e93ea..0000000000 --- a/app/scripts/stores/RepoSettingsCollaborators.jsx +++ /dev/null @@ -1,104 +0,0 @@ -'use strict'; - -import createStore from 'fluxible/addons/createStore'; -import { STATUS } from './collaborators/Constants.js'; -var debug = require('debug')('RepoSettingsCollaborators'); - -export default createStore({ - storeName: 'RepoSettingsCollaborators', - handlers: { - ADD_COLLAB_START: '_addCollabStart', - ADD_COLLAB_ERROR: '_addCollabError', - ADD_COLLAB_SUCCESS: '_addCollabSuccess', - COLLAB_RECEIVE_COLLABORATORS: '_receiveCollaborators', - COLLAB_RECEIVE_TEAMS: '_receiveTeams', - COLLAB_RECEIVE_ALL_TEAMS: '_receiveAllTeams', - DEL_COLLABORATORS_SET_LOADING: 'setLoadingFor', - DEL_COLLABORATORS_SET_ERROR: 'setErrorFor', - DEL_COLLABORATORS_SET_SUCCESS: 'setSuccessFor', - LOGOUT: 'initialize', - ON_ADD_COLLAB_CHANGE: 'onAddCollabChange' - }, - initialize() { - // these are full request objects. Only one will succeed and have a `count` key - this.collaborators = {}; - this.teams = {}; - this.allTeams = {results: []}; - this.newCollaborator = ''; - this.error = ''; - this.requests = {}; - this.STATUS = STATUS.DEFAULT; - }, - getState() { - return { - collaborators: this.collaborators, - teams: this.teams, - allTeams: this.allTeams, - newCollaborator: this.newCollaborator, - error: this.error, - requests: this.requests, - STATUS: this.STATUS - }; - }, - - setLoadingFor(username) { - this.requests[username] = STATUS.ATTEMPTING; - this.emitChange(); - }, - setErrorFor(username) { - this.requests[username] = STATUS.ERROR; - this.emitChange(); - }, - setSuccessFor(username) { - this.requests[username] = STATUS.DEFAULT; - this.newCollaborator = ''; - this.emitChange(); - }, - onAddCollabChange(collaborator) { - this.newCollaborator = collaborator; - this.error = ''; - this.emitChange(); - }, - _addCollabSuccess() { - this.STATUS = STATUS.SUCCESS; - this.newCollaborator = ''; - this.error = ''; - this.emitChange(); - }, - _addCollabError(message) { - this.STATUS = STATUS.ERROR; - this.error = message; - this.emitChange(); - }, - _addCollabStart() { - this.STATUS = STATUS.ATTEMPTING; - this.emitChange(); - }, - _receiveCollaborators(collaborators) { - debug(collaborators); - this.newCollaborator = ''; - this.collaborators = collaborators; - this.emitChange(); - }, - _receiveTeams(teams) { - debug(teams); - this.teams = teams; - this.emitChange(); - }, - _receiveAllTeams(teams) { - this.allTeams = teams; - this.emitChange(); - }, - dehydrate() { - return this.getState(); - }, - rehydrate(state) { - this.collaborators = state.collaborators; - this.teams = state.teams; - this.allTeams = state.allTeams; - this.newCollaborator = state.newCollaborator; - this.error = state.error; - this.requests = state.requests; - this.STATUS = state.STATUS; - } -}); diff --git a/app/scripts/stores/RepositoriesPageStore.js b/app/scripts/stores/RepositoriesPageStore.js deleted file mode 100644 index 9e82aa2480..0000000000 --- a/app/scripts/stores/RepositoriesPageStore.js +++ /dev/null @@ -1,42 +0,0 @@ -'use strict'; - -import createStore from'fluxible/addons/createStore'; - -var ReposStore = createStore({ - storeName: 'RepositoriesPageStore', - handlers: { - RECEIVE_REPOS: '_receiveRepos' - }, - initialize: function() { - this.repos = []; - this.previous = null; - this.next = null; - this.count = null; - }, - _receiveRepos: function(res) { - this.repos = res.results; - this.previous = res.previous; - this.next = res.next; - this.count = res.count; - this.emitChange(); - }, - getState: function() { - return { - repos: this.repos, - previous: this.previous, - next: this.next, - count: this.count - }; - }, - rehydrate: function(state) { - this.repos = state.repos; - this.previous = state.previous; - this.next = state.next; - this.count = state.count; - }, - dehydrate: function() { - return this.getState(); - } -}); - -module.exports = ReposStore; diff --git a/app/scripts/stores/RepositoryCommentsStore.js b/app/scripts/stores/RepositoryCommentsStore.js deleted file mode 100644 index f31d5af4e4..0000000000 --- a/app/scripts/stores/RepositoryCommentsStore.js +++ /dev/null @@ -1,42 +0,0 @@ -'use strict'; -import createStore from 'fluxible/addons/createStore'; -var debug = require('debug')('RepositoryCommentsStore'); - -var RepoCommentsStore = createStore({ - storeName: 'RepositoryCommentsStore', - handlers: { - RECEIVE_REPO_COMMENTS: '_receiveRepoComments' - }, - initialize: function() { - this.results = []; - this.prev = null; - this.next = null; - this.count = 0; - }, - _receiveRepoComments: function(res) { - this.results = res.results; - this.prev = res.previous; - this.next = res.next; - this.count = res.count; - this.emitChange(); - }, - getState: function() { - return { - results: this.results, - prev: this.prev, - next: this.next, - count: this.count - }; - }, - rehydrate: function(state) { - this.results = state.results; - this.prev = state.prev; - this.next = state.next; - this.count = state.count; - }, - dehydrate: function() { - return this.getState(); - } -}); - -module.exports = RepoCommentsStore; diff --git a/app/scripts/stores/RepositoryPageStore.js b/app/scripts/stores/RepositoryPageStore.js deleted file mode 100644 index 64a6866b84..0000000000 --- a/app/scripts/stores/RepositoryPageStore.js +++ /dev/null @@ -1,118 +0,0 @@ -'use strict'; -import createStore from 'fluxible/addons/createStore'; -import _ from 'lodash'; -const STATUS = require('./repostore/Constants').STATUS; -var debug = require('debug')('RepositoryPageStore'); - -var RepoStore = createStore({ - storeName: 'RepositoryPageStore', - handlers: { - RECEIVE_REPOSITORY: '_receiveRepository', - CREATE_REPO_ERROR: '_createRepoError', - TOGGLE_STARRED_STATE: '_toggleStarred', - TOGGLE_VISIBILITY_SUCCESS: '_toggleVisibility', - REPO_NOT_FOUND: '_repoNotFound' - }, - initialize: function() { - this.canEdit = false; - this.description = ''; - this.fullDescription = ''; - this.hasStarred = false; - this.isPrivate = true; - this.isAutomated = false; - this.name = ''; - this.namespace = ''; - this.status = 0; - this.lastUpdated = ''; - this.globalFormError = ''; - this.STATUS = STATUS.DEFAULT; - }, - _createRepoError: function(err) { - if (err) { - var errResponse = err.response.body; - this.globalFormError = ''; - if (!_.isEmpty(errResponse)) { - if (err.response.badRequest) { - this.STATUS = STATUS.BAD_REQUEST; - if (_.has(errResponse, '__all__')) { - this.globalFormError = errResponse.__all__.toString(); - } else if (_.has(errResponse, 'detail')) { - this.globalFormError = errResponse.detail.toString(); - } else { - _.forIn(errResponse, function(v, k) { - this.globalFormError += k + ': ' + v.join(',') + '\n'; - }.bind(this)); - } - } - } else { - this.STATUS = STATUS.GENERAL_SERVER_ERROR; - this.globalFormError = 'An error occurred while creating your repository. Please try again later.'; - } - } - this.emitChange(); - }, - _receiveRepository: function(res) { - debug('receive repo', res); - this.STATUS = STATUS.DEFAULT; - this.canEdit = res.can_edit; - this.description = res.description; - // full_description can come in as null; Default to string - this.fullDescription = res.full_description || ''; - this.hasStarred = res.has_starred; - this.isPrivate = res.is_private; - this.isAutomated = res.is_automated; - this.lastUpdated = res.last_updated; - this.name = res.name; - this.namespace = res.namespace; - this.status = res.status; - - this.emitChange(); - }, - _toggleStarred: function(status) { - this.hasStarred = status; - this.emitChange(); - }, - _toggleVisibility: function(vis) { - this.isPrivate = vis; - this.emitChange(); - }, - _repoNotFound: function(err) { - this.STATUS = STATUS.REPO_NOT_FOUND; - this.emitChange(); - }, - getState: function() { - return { - canEdit: this.canEdit, - description: this.description, - fullDescription: this.fullDescription, - hasStarred: this.hasStarred, - isPrivate: this.isPrivate, - isAutomated: this.isAutomated, - lastUpdated: this.lastUpdated, - name: this.name, - namespace: this.namespace, - status: this.status, - globalFormError: this.globalFormError, - STATUS: this.STATUS - }; - }, - rehydrate: function(state) { - this.canEdit = state.canEdit; - this.description = state.description; - this.fullDescription = state.fullDescription; - this.hasStarred = state.hasStarred; - this.isPrivate = state.isPrivate; - this.isAutomated = state.isAutomated; - this.name = state.name; - this.lastUpdated = state.lastUpdated; - this.namespace = state.namespace; - this.status = state.status; - this.globalFormError = state.globalFormError; - this.STATUS = state.STATUS; - }, - dehydrate: function() { - return this.getState(); - } -}); - -module.exports = RepoStore; diff --git a/app/scripts/stores/SearchStore.js b/app/scripts/stores/SearchStore.js deleted file mode 100644 index 0884946f82..0000000000 --- a/app/scripts/stores/SearchStore.js +++ /dev/null @@ -1,104 +0,0 @@ -'use strict'; -const createStore = require('fluxible/addons/createStore'); -const _ = require('lodash'); -const debug = require('debug')('STORE:SearchStore'); - -//Store to keep track of searches -//TODO: Autocomplete support? -//Query API on general search and return results in a Search Results Component -var SearchStore = createStore({ - storeName: 'SearchStore', - handlers: { - SUBMIT_SEARCH_QUERY: '_submitSearchQuery', - UPDATE_SEARCH_FILTER: '_updateSearchFilter', - UPDATE_SEARCH_SORT: '_updateSearchSort', - UPDATE_SEARCH_PAGE: '_updateSearchPage', - UPDATE_SEARCH_OTHERFILTERS: '_updateSearchFilters', - PROCESS_SEARCH_RESULTS: '_processSearchResults', - SEARCH_ERROR: '_handleSearchError' - }, - initialize: function() { - this.results = ''; - this.queryResult = {}; - this.page = 1; - this.count = 0; - this.next = false; - this.prev = false; - }, - getQueryParams: function() { - //transition to will always have `q` appended as query param at the very least - //Other query params like: `s` -> sort by | `t=User` -> user | `t=Organization` -> Org | `f=official` - // `f=automated_builds` | `s=date_created`, `s=last_updated`, `s=alphabetical`, `s=stars`, `s=downloads` - // `s=pushes` - var queryParams = { - q: this.query || '', - page: this.page || 1, - isOfficial: this.isOfficial || 0, - isAutomated: this.isAutomated || 0, - pullCount: this.pullCount || 0, - starCount: this.starCount || 0 - }; - return queryParams; - }, - _submitSearchQuery: function(payload: string) { - this.query = payload; - this.results = null; - this.emitChange(); - }, - _processSearchResults: function(searchResult) { - this.queryResult = searchResult; - this.count = searchResult.count; - this.results = searchResult.results; - this.next = searchResult.next; - this.prev = searchResult.previous; - this.emitChange(); - }, - _handleSearchError: function(searchError) { - //TODO: Some form of common error handling across all components - debug(searchError); - }, - _updateSearchPage: function(page) { - this.page = page; - this.emitChange(); - }, - _updateSearchFilters: function(params) { - this.isAutomated = params.isAutomated; - this.isOfficial = params.isOfficial; - this.pullCount = params.pullCount; - this.starCount = params.starCount; - this.emitChange(); - }, - getState: function() { - return { - query: this.query, - page: this.page, - queryResult: this.queryResult, - results: this.results, - isOfficial: this.isOfficial, - isAutomated: this.isAutomated, - pullCount: this.pullCount, - starCount: this.starCount, - count: this.count, - next: this.next, - prev: this.prev - }; - }, - dehydrate: function() { - return this.getState(); - }, - rehydrate: function(state) { - this.query = state.query; - this.page = state.page; - this.queryResult = state.queryResult; - this.results = state.results; - this.isOfficial = state.isOfficial; - this.isAutomated = state.isAutomated; - this.pullCount = state.pullCount; - this.starCount = state.starCount; - this.count = state.count; - this.next = state.next; - this.prev = state.prev; - } -}); - -module.exports = SearchStore; diff --git a/app/scripts/stores/SignupStore.js b/app/scripts/stores/SignupStore.js deleted file mode 100644 index bedf00db7f..0000000000 --- a/app/scripts/stores/SignupStore.js +++ /dev/null @@ -1,117 +0,0 @@ -'use strict'; - -var createStore = require('fluxible/addons/createStore'); -import { STATUS } from './signupstore/Constants'; -var debug = require('debug')('SignupStore'); -var _ = require('lodash'); - -var noErrorObj = { - hasError: false, - error: '' -}; - -export default createStore({ - storeName: 'SignupStore', - handlers: { - SIGNUP_CLEAR_FORM: '_signupClearForm', - SIGNUP_CLEAR_PASSWORD: '_signupClearPassword', - SIGNUP_UPDATE_FIELD_WITH_VALUE: '_updateFieldWithValue', - SIGNUP_ATTEMPT_START: '_signupAttemptStart', - SIGNUP_BAD_REQUEST: '_badRequest', - SIGNUP_SUCCESS: '_signupSuccess' - }, - initialize() { - this.STATUS = STATUS.DEFAULT; - - this.fields = { - username: {}, - email: {}, - password: {} - }; - - this.values = { - username: '', - email: '', - password: '' - }; - }, - _signupClearForm() { - this.initialize(); - this.emitChange(); - }, - _signupClearPassword() { - this.values.password = ''; - this.emitChange(); - }, - _updateFieldWithValue({fieldKey, fieldValue}){ - this.values[fieldKey] = fieldValue; - if (fieldValue) { - this.fields[fieldKey] = this._validate({fieldKey, fieldValue}); - } - this.emitChange(); - }, - _signupAttemptStart() { - debug('attempting Signup'); - this.STATUS = STATUS.ATTEMPTING_SIGNUP; - this.emitChange(); - }, - _signupSuccess() { - this.STATUS = STATUS.SUCCESSFUL_SIGNUP; - this.emitChange(); - }, - _badRequest(obj) { - let shouldEmitChange = false; - - // cycle through the possible form fields - _.forEach(_.keys(this.fields), - (key) => { - if(_.has(obj, key)) { - shouldEmitChange = true; - var newField = {}; - newField.hasError = !!obj[key]; - newField.error = obj[key][0]; - this.fields[key] = newField; - } - }); - if(shouldEmitChange) { - this.emitChange(); - } - }, - validations: { - username(value) { - if (value.length < 4){ - return { - hasError: true, - error: 'Username must be at least four characters long' - }; - } else if (!/^[A-Za-z0-9]+$/.test(value)) { - return { - hasError: true, - error: 'Username must contain only letters and digits' - }; - } else { - return noErrorObj; - } - } - }, - _validate({fieldKey, fieldValue}) { - if(_.isFunction(this.validations[fieldKey])) { - return this.validations[fieldKey](fieldValue); - } else { - return noErrorObj; - } - }, - getState() { - return { - fields: this.fields, - values: this.values, - STATUS: this.STATUS - }; - }, - dehydrate() { - return {}; - }, - rehydrate(state) { - this.state = state; - } -}); diff --git a/app/scripts/stores/TriggerBuildStore.js b/app/scripts/stores/TriggerBuildStore.js deleted file mode 100644 index dab896a28a..0000000000 --- a/app/scripts/stores/TriggerBuildStore.js +++ /dev/null @@ -1,50 +0,0 @@ -'use strict'; - -const createStore = require('fluxible/addons/createStore'); -const debug = require('debug')('TriggerBuildStore'); - -var TriggerBuildStore = createStore({ - storeName: 'TriggerBuildStore', - handlers: { - AB_TRIGGER_SUCCESS: '_abTriggerSuccess', - AB_TRIGGER_ERROR: '_abTriggerError' - }, - initialize: function() { - this.abtrigger = { - hasError: false, - success: false - }; - }, - _abTriggerClear: function() { - this.abtrigger = { - hasError: false, - success: false - }; - this.emitChange(); - }, - _abTriggerError: function() { - this.abtrigger.success = false; - this.abtrigger.hasError = true; - setTimeout(this._abTriggerClear.bind(this), 3000); - this.emitChange(); - }, - _abTriggerSuccess: function() { - this.abtrigger.success = true; - this.abtrigger.hasError = false; - setTimeout(this._abTriggerClear.bind(this), 3000); - this.emitChange(); - }, - getState: function() { - return { - abtrigger: this.abtrigger - }; - }, - dehydrate: function() { - return this.getState(); - }, - rehydrate: function(state) { - this.abtrigger = state.abtrigger; - } -}); - -module.exports = TriggerBuildStore; diff --git a/app/scripts/stores/UnlinkAccountsStore.js b/app/scripts/stores/UnlinkAccountsStore.js deleted file mode 100644 index 22f7b2ad35..0000000000 --- a/app/scripts/stores/UnlinkAccountsStore.js +++ /dev/null @@ -1,36 +0,0 @@ -'use strict'; - -import createStore from 'fluxible/addons/createStore'; -var debug = require('debug')('UnlinkAccountsStore'); - -var BitbucketLinkStore = createStore({ - storeName: 'UnlinkAccountsStore', - handlers: { - GITHUB_UNLINK_ERROR: _unlinkGithubError, - BITBUCKET_UNLINK_ERROR: _unlinkBitbucketError - }, - initialize: function() { - this.error = ''; - }, - _unlinkGithubError: function() { - this.error = 'Error unlinking Github Account. Please try again later'; - this.emitChange(); - }, - _unlinkBitbucketError: function() { - this.error = 'Error unlinking Bitbucket Account. Please try again later'; - this.emitChange(); - }, - getState: function() { - return { - error: this.error - }; - }, - rehydrate: function(state) { - this.error = state.error; - }, - dehydrate: function() { - return this.getState(); - } -}); - -module.exports = UnlinkAccountsStore; diff --git a/app/scripts/stores/UserProfileReposStore.js b/app/scripts/stores/UserProfileReposStore.js deleted file mode 100644 index 397a727c14..0000000000 --- a/app/scripts/stores/UserProfileReposStore.js +++ /dev/null @@ -1,46 +0,0 @@ -'use strict'; - -import createStore from 'fluxible/addons/createStore'; -import filter from 'lodash/collection/filter'; -import { PENDING_DELETE } from 'common/enums/RepoStatus'; -var debug = require('debug')('stores: UserProfileStore'); - -export default createStore({ - storeName: 'UserProfileReposStore', - handlers: { - RECEIVE_PROFILE_REPOS: 'receiveRepos' - }, - initialize() { - this.repos = []; - this.next = null; - this.prev = null; - }, - removePendingDeleteRepos(repos) { - //Remove repos that are in pending delete state from user profile repos - return filter(repos, (repo) => { - const { status } = repo; - return status !== PENDING_DELETE; - }); - }, - receiveRepos(res) { - this.repos = this.removePendingDeleteRepos(res.results); - this.next = res.next; - this.prev = res.previous; - this.emitChange(); - }, - getState() { - return { - repos: this.repos, - next: this.next, - prev: this.prev - }; - }, - dehydrate() { - return this.getState(); - }, - rehydrate(state) { - this.repos = state.repos; - this.next = state.next; - this.prev = state.prev; - } -}); diff --git a/app/scripts/stores/UserProfileStarsStore.js b/app/scripts/stores/UserProfileStarsStore.js deleted file mode 100644 index 1a70b56588..0000000000 --- a/app/scripts/stores/UserProfileStarsStore.js +++ /dev/null @@ -1,37 +0,0 @@ -'use strict'; - -import createStore from 'fluxible/addons/createStore'; -var debug = require('debug')('stores: UserProfileStarsStore'); - -export default createStore({ - storeName: 'UserProfileStarsStore', - handlers: { - RECEIVE_PROFILE_STARRED_REPOS: '_receiveStarredRepos' - }, - initialize() { - this.repos = []; - this.next = null; - this.prev = null; - }, - _receiveStarredRepos(res) { - this.starred = res.results; - this.next = res.next; - this.prev = res.previous; - this.emitChange(); - }, - getState() { - return { - starred: this.starred, - next: this.next, - prev: this.prev - }; - }, - dehydrate() { - return this.getState(); - }, - rehydrate(state) { - this.starred = state.starred; - this.next = state.next; - this.prev = state.prev; - } -}); diff --git a/app/scripts/stores/UserProfileStore.js b/app/scripts/stores/UserProfileStore.js deleted file mode 100644 index a4c44484e7..0000000000 --- a/app/scripts/stores/UserProfileStore.js +++ /dev/null @@ -1,38 +0,0 @@ -'use strict'; - -import createStore from 'fluxible/addons/createStore'; -var debug = require('debug')('UserProfileStore'); - -export default createStore({ - storeName: 'UserProfileStore', - handlers: { - RECEIVE_PROFILE_USER: '_receiveUser', - USER_PROFILE_404: '_fourOHfour' - }, - initialize() { - this.STATUS = 'DEFAULT'; - this.user = {}; - }, - _fourOHfour() { - this.STATUS = '404'; - this.emitChange(); - }, - _receiveUser(user) { - this.STATUS = 'DEFAULT'; - this.user = user; - this.emitChange(); - }, - getState() { - return { - user: this.user, - STATUS: this.STATUS - }; - }, - dehydrate() { - return this.getState(); - }, - rehydrate(state) { - this.user = state.user; - this.STATUS = state.STATUS; - } -}); diff --git a/app/scripts/stores/UserStore.js b/app/scripts/stores/UserStore.js deleted file mode 100644 index ff68d1cfac..0000000000 --- a/app/scripts/stores/UserStore.js +++ /dev/null @@ -1,137 +0,0 @@ -'use strict'; - -import createStore from 'fluxible/addons/createStore'; -import md5 from 'md5'; -var debug = require('debug')('stores: UserStore'); - -var UserStore = createStore({ - storeName: 'UserStore', - handlers: { - RECEIVE_USER: '_receiveUserFromHub', - RECEIVE_NAMESPACES: '_receiveNamespaces', - LOGOUT: '_logout', - EXPIRED_SIGNATURE: '_logout' - }, - initialize: function() { - this.dateJoined = ''; - this.fullName = ''; - this.gravatarEmail = ''; - this.gravatarUrl = ''; - this.isActive = false; - this.isAdmin = false; - this.isStaff = false; - this.profileUrl = ''; - this.company = ''; - this.id = ''; - this.location = ''; - this.userType = 'User'; - this.username = ''; - this.namespaces = []; - }, - _getGravatarUrl: function(email) { - return 'https://secure.gravatar.com/avatar/' + md5( email.trim().toLowerCase() ); - }, - _receiveUserFromHub: function(user) { - - // jscs:disable requireCamelCaseOrUpperCaseIdentifiers - this.dateJoined = user.date_joined; - this.fullName = user.full_name; - this.gravatarEmail = user.gravatar_email; - //TODO: the url has to be handed off from the backend - //This fix should be temporary - this.gravatarUrl = (user.gravatar_url === user.gravatar_email) ? - this._getGravatarUrl(user.gravatar_email) : user.gravatar_url; - this.isActive = user.is_active; - this.isAdmin = user.is_admin; - this.isStaff = user.is_staff; - this.profileUrl = user.profile_url; - // jscs:enable - - this.company = user.company; - this.id = user.id; - this.location = user.location; - this.userType = user.type; - this.username = user.username; - - this.emitChange(); - }, - _receiveNamespaces: function(receivedNamespaces) { - //This is required for creating a repository - //Namespaces are attached to a user, due to permissions/access restrictions - //Eg. { - // "namespaces": [ - // "user", - // "org1", - // "org2" - // ] - //} - this.namespaces = receivedNamespaces.namespaces; - - this.emitChange(); - }, - _logout: function() { - - this.company = ''; - this.dateJoined = ''; - this.fullName = ''; - this.gravatarEmail = ''; - this.gravatarUrl = ''; - this.id = ''; - this.isActive = false; - this.isAdmin = false; - this.isStaff = false; - this.location = ''; - this.profileUrl = ''; - this.userType = 'User'; - this.username = ''; - this.namespaces = []; - - this.emitChange(); - }, - getState: function() { - return { - company: this.company, - dateJoined: this.dateJoined, - fullName: this.fullName, - gravatarEmail: this.gravatarEmail, - gravatarUrl: this.gravatarUrl, - id: this.id, - isActive: this.isActive, - isAdmin: this.isAdmin, - isStaff: this.isStaff, - location: this.location, - profileUrl: this.profileUrl, - userType: this.userType, - username: this.username, - namespaces: this.namespaces - }; - }, - getUsername: function() { - return this.username; - }, - getNamespaces: function() { - return this.namespaces; - }, - dehydrate: function() { - return this.getState(); - }, - rehydrate: function(state) { - debug('rehydrate', state); - this.dateJoined = state.dateJoined; - this.fullName = state.fullName; - this.gravatarEmail = state.gravatarEmail; - this.gravatarUrl = state.gravatarUrl; - this.isActive = state.isActive; - this.isAdmin = state.isAdmin; - this.isStaff = state.isStaff; - this.profileUrl = state.profileUrl; - this.company = state.company; - this.id = state.id; - this.location = state.location; - this.userType = state.userType; - this.username = state.username; - this.namespaces = state.namespaces; - } -}); - -module.exports = UserStore; diff --git a/app/scripts/stores/WebhooksSettingsStore.js b/app/scripts/stores/WebhooksSettingsStore.js deleted file mode 100644 index 8c27103a95..0000000000 --- a/app/scripts/stores/WebhooksSettingsStore.js +++ /dev/null @@ -1,31 +0,0 @@ -'use strict'; -import createStore from 'fluxible/addons/createStore'; -const debug = require('debug')('WebhooksSettingsStore'); - -var WebhooksSettingsStore = createStore({ - storeName: 'WebhooksSettingsStore', - handlers: { - RECEIVE_WEBHOOKS: '_receiveWebhooks' - }, - initialize() { - this.pipelines = []; - }, - _receiveWebhooks(payload) { - debug(payload); - this.pipelines = payload.results; - this.emitChange(); - }, - getState() { - return { - pipelines: this.pipelines - }; - }, - dehydrate() { - return this.getState(); - }, - rehydrate(state) { - this.pipelines = state.pipelines; - } -}); - -module.exports = WebhooksSettingsStore; diff --git a/app/scripts/stores/addorganizationstore/Constants.js b/app/scripts/stores/addorganizationstore/Constants.js deleted file mode 100644 index 2da1465eb6..0000000000 --- a/app/scripts/stores/addorganizationstore/Constants.js +++ /dev/null @@ -1,15 +0,0 @@ -'use strict'; -var keyMirror = require('keymirror'); - -// Component-Global form states -var STATUS = keyMirror({ - ATTEMPTING: null, - DEFAULT: null, - FACEPALM: null, - BAD_REQUEST: null, - SUCCESSFUL: null -}); - -module.exports = { - STATUS -}; diff --git a/app/scripts/stores/addtriallicensestore/Constants.js b/app/scripts/stores/addtriallicensestore/Constants.js deleted file mode 100644 index 08e9dfd0ff..0000000000 --- a/app/scripts/stores/addtriallicensestore/Constants.js +++ /dev/null @@ -1,11 +0,0 @@ -'use strict'; -import keyMirror from 'keymirror'; - -const STATUS = keyMirror({ - ATTEMPTING_DOWNLOAD: null, - DEFAULT: null, - FACEPALM: null, - SUCCESSFUL_DOWNLOAD: null -}); - -export default STATUS; diff --git a/app/scripts/stores/addwebhookformstore/Constants.js b/app/scripts/stores/addwebhookformstore/Constants.js deleted file mode 100644 index d2ed2ffbf4..0000000000 --- a/app/scripts/stores/addwebhookformstore/Constants.js +++ /dev/null @@ -1,10 +0,0 @@ -'use strict'; -var keyMirror = require('keymirror'); - -export default keyMirror({ - ATTEMPTING: null, - DEFAULT: null, - FACEPALM: null, - SUCCESSFUL: null, - ERROR: null -}); diff --git a/app/scripts/stores/billingformstore/Constants.js b/app/scripts/stores/billingformstore/Constants.js deleted file mode 100644 index 42bb512ddf..0000000000 --- a/app/scripts/stores/billingformstore/Constants.js +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; -var keyMirror = require('keymirror'); - -// Component-Global form states -var STATUS = keyMirror({ - DEFAULT: null, - ATTEMPTING: null, - SUCCESS: null, - FORM_ERROR: null -}); - -module.exports = { - STATUS -}; diff --git a/app/scripts/stores/collaborators/Constants.js b/app/scripts/stores/collaborators/Constants.js deleted file mode 100644 index 0092c8068c..0000000000 --- a/app/scripts/stores/collaborators/Constants.js +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; -var keyMirror = require('keymirror'); - -// Component-Global form states -var STATUS = keyMirror({ - DEFAULT: null, - ATTEMPTING: null, - SUCCESS: null, - ERROR: null -}); - -module.exports = { - STATUS -}; diff --git a/app/scripts/stores/common/Constants.js b/app/scripts/stores/common/Constants.js deleted file mode 100644 index 63b6ce6890..0000000000 --- a/app/scripts/stores/common/Constants.js +++ /dev/null @@ -1,25 +0,0 @@ -'use strict'; -var keyMirror = require('keymirror'); - -// Component-Global form states -export const STATUS = keyMirror({ - ATTEMPTING: null, - DEFAULT: null, - FACEPALM: null, - SUCCESSFUL: null, - ERROR: null -}); - -export const ACCOUNT = 'account'; -export const BILLING = 'billing'; -export const STRIPE_URL = 'https://api.stripe.com/v1/tokens'; -export const STRIPE_STAGE_TOKEN = 'pk_test_mNouiY3uYoBAfQYyTurrxf0Q'; -export const STRIPE_PROD_TOKEN = 'pk_live_89IjovLdwh2MTzV7JsGJK3qk'; -export const BF_STAGE_URL = 'https://api-sandbox.billforward.net:443/v1/tokenization/auth-capture'; -export const BF_PROD_URL = 'https://api.billforward.net/v1/tokenization/auth-capture'; -export const BF_STAGE_TOKEN = 'ec687f76-c1b6-4d71-b919-4fe99202ca13'; -export const BF_PROD_TOKEN = '650cbe35-4aca-4820-a7d1-accec8a7083a'; -export const BILLFORWARD_ACCOUNT_ID = 'billforward-account-id'; -export const v4BillingProfile = (docker_id) => { - return `/api/billing/v4/accounts/${docker_id}/profile`; -}; diff --git a/app/scripts/stores/deletepipelinestore/Constants.js b/app/scripts/stores/deletepipelinestore/Constants.js deleted file mode 100644 index c619b4befb..0000000000 --- a/app/scripts/stores/deletepipelinestore/Constants.js +++ /dev/null @@ -1,9 +0,0 @@ -'use strict'; -var keyMirror = require('keymirror'); - -export default keyMirror({ - ATTEMPTING: null, - DEFAULT: null, - FACEPALM: null, - SUCCESSFUL: null -}); diff --git a/app/scripts/stores/deleterepostore/Constants.js b/app/scripts/stores/deleterepostore/Constants.js deleted file mode 100644 index 2282e4de76..0000000000 --- a/app/scripts/stores/deleterepostore/Constants.js +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; -var keyMirror = require('keymirror'); - -// Component-Global form states -var STATUS = keyMirror({ - ATTEMPTING: null, - DEFAULT: null, - FORM_ERROR: null, - SHOWING_CONFIRM_BOX: null -}); - -module.exports = { - STATUS -}; diff --git a/app/scripts/stores/emailsstore/Constants.js b/app/scripts/stores/emailsstore/Constants.js deleted file mode 100644 index 262d6665c5..0000000000 --- a/app/scripts/stores/emailsstore/Constants.js +++ /dev/null @@ -1,19 +0,0 @@ -'use strict'; -var keyMirror = require('keymirror'); - -// Component-Global form states -var STATUS = keyMirror({ - DEFAULT: null, - SAVING: null -}); - -var EMAILSTATUS = keyMirror({ - SUCCESS: null, - ATTEMPTING: null, - FAILED: null -}); - -module.exports = { - STATUS, - EMAILSTATUS -}; diff --git a/app/scripts/stores/enterprisetrialstore/Constants.js b/app/scripts/stores/enterprisetrialstore/Constants.js deleted file mode 100644 index c1c53dce9c..0000000000 --- a/app/scripts/stores/enterprisetrialstore/Constants.js +++ /dev/null @@ -1,11 +0,0 @@ -'use strict'; -import keyMirror from 'keymirror'; - -const STATUS = keyMirror({ - ATTEMPTING: null, - DEFAULT: null, - FACEPALM: null, - SUCCESSFUL_SIGNUP: null -}); - -export default STATUS; diff --git a/app/scripts/stores/enterprisetrialsuccessstore/Constants.js b/app/scripts/stores/enterprisetrialsuccessstore/Constants.js deleted file mode 100644 index 061a46f844..0000000000 --- a/app/scripts/stores/enterprisetrialsuccessstore/Constants.js +++ /dev/null @@ -1,9 +0,0 @@ -'use strict'; -import keyMirror from 'keymirror'; - -const STATUS = keyMirror({ - DEFAULT: null, - ERROR: null -}); - -export default STATUS; diff --git a/app/scripts/stores/loginstore/Constants.js b/app/scripts/stores/loginstore/Constants.js deleted file mode 100644 index d8cc11d128..0000000000 --- a/app/scripts/stores/loginstore/Constants.js +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; -var keyMirror = require('keymirror'); - -// Component-Global form states -var STATUS = keyMirror({ - DEFAULT: null, - ATTEMPTING_LOGIN: null, - ERROR_UNAUTHORIZED: null, - GENERIC_ERROR: null -}); - -module.exports = { - STATUS -}; diff --git a/app/scripts/stores/loginstore/createFormStore.js b/app/scripts/stores/loginstore/createFormStore.js deleted file mode 100644 index cf17dd0cbe..0000000000 --- a/app/scripts/stores/loginstore/createFormStore.js +++ /dev/null @@ -1,88 +0,0 @@ -'use strict'; - -import createStore from 'fluxible/addons/createStore'; -import _ from 'lodash'; -var debug = require('debug')('createFormStore'); -/** - * @param {Array} fields - array of objects with field names - * as keys and inital values as values - * @param {Function} init - old initialize function - */ - -export default function createFormStore(fields, oldSpec) { - - var spec = {}; - - spec.initialize = function() { - this.globalFormError = ''; - _.forOwn(fields, function(key, val){ - this.fields[key] = {}; - this.values[key] = val; - }); - spec.initialize(); - }.bind(spec); - - spec._badRequest = function(obj) { - /** - * obj is an Object with keys that are field names - * and values that are arrays of errors - * - * This function should be used as the handler for - * an HTTP 400 BadRequest - * - * obj = { - * username: ["cannot be empty"] - * } - */ - // did we update state? - var dirty = false; - - _.forOwn(obj, function(key, val) { - if(_.includes(fields, key)) { - this.fields[key].hasError = !!val; - this.fields[key].error = val[0]; - dirty = true; - } - }, this); - - if(dirty) { - this.emitChange(); - } - }; - - spec._getState = function() { - return { - fields: this.fields, - values: this.values, - globalFormError: this.globalFormError - }; - }; - - - spec._updateFieldWithValue = function({fieldKey, fieldValue}){ - this.values[fieldKey] = fieldValue; - this.emitChange(); - }; - - - spec.dehydrate = function() { - return {}; - }, - spec.rehydrate = function(state) { - this.state = state; - }; - - _.merge(spec, oldSpec, function(objectValue, sourceValue, key) { - if(key === 'initializer') { - return sourceValue; - } else if(key === 'getState') { - return function() { - debug('state', this.state); - return _.merge({}, - objectValue.getState(), - sourceValue._getState()); - }; - } - }); - return createStore(spec); -} diff --git a/app/scripts/stores/orgteamstore/Constants.js b/app/scripts/stores/orgteamstore/Constants.js deleted file mode 100644 index 0731e53f0e..0000000000 --- a/app/scripts/stores/orgteamstore/Constants.js +++ /dev/null @@ -1,22 +0,0 @@ -'use strict'; -var keyMirror = require('keymirror'); - -// Component-Global form states -var STATUS = keyMirror({ - DEFAULT: null, - MEMBER_UNAUTHORIZED: null, - TEAM_UNAUTHORIZED: null, - MEMBER_ERROR: null, - TEAM_ERROR: null, - MEMBER_BAD_REQUEST: null, - TEAM_BAD_REQUEST: null, - GENERAL_SERVER_ERROR: null, - CREATE_TEAM_SUCCESS: null, - CREATE_MEMBER_SUCCESS: null, - UPDATE_TEAM_ERROR: null, - UPDATE_TEAM_SUCCESS: null -}); - -module.exports = { - STATUS -}; diff --git a/app/scripts/stores/repodetailstags/Constants.js b/app/scripts/stores/repodetailstags/Constants.js deleted file mode 100644 index 42faf1dbcc..0000000000 --- a/app/scripts/stores/repodetailstags/Constants.js +++ /dev/null @@ -1,12 +0,0 @@ -'use strict'; -var keyMirror = require('keymirror'); - -// Component-Global form states -var STATUS = keyMirror({ - DEFAULT: null, - ERROR: null, - DELETING: null, - CONFIRMING: null -}); - -module.exports = STATUS; diff --git a/app/scripts/stores/repostore/Constants.js b/app/scripts/stores/repostore/Constants.js deleted file mode 100644 index f3faaad35f..0000000000 --- a/app/scripts/stores/repostore/Constants.js +++ /dev/null @@ -1,15 +0,0 @@ -'use strict'; -var keyMirror = require('keymirror'); - -// Component-Global form states -var STATUS = keyMirror({ - DEFAULT: null, - REPO_ALREADY_EXISTS: null, - PRIVATE_REPO_QUOTA_EXCEEDED: null, - BAD_REQUEST: null, - REPO_NOT_FOUND: null -}); - -module.exports = { - STATUS -}; diff --git a/app/scripts/stores/repovisibilitystore/Constants.js b/app/scripts/stores/repovisibilitystore/Constants.js deleted file mode 100644 index 2282e4de76..0000000000 --- a/app/scripts/stores/repovisibilitystore/Constants.js +++ /dev/null @@ -1,14 +0,0 @@ -'use strict'; -var keyMirror = require('keymirror'); - -// Component-Global form states -var STATUS = keyMirror({ - ATTEMPTING: null, - DEFAULT: null, - FORM_ERROR: null, - SHOWING_CONFIRM_BOX: null -}); - -module.exports = { - STATUS -}; diff --git a/app/scripts/stores/signupstore/Constants.js b/app/scripts/stores/signupstore/Constants.js deleted file mode 100644 index 030ee671ac..0000000000 --- a/app/scripts/stores/signupstore/Constants.js +++ /dev/null @@ -1,13 +0,0 @@ -'use strict'; -var keyMirror = require('keymirror'); - -// Component-Global form states -var STATUS = keyMirror({ - DEFAULT: null, - ATTEMPTING_SIGNUP: null, - SUCCESSFUL_SIGNUP: null -}); - -module.exports = { - STATUS -}; diff --git a/app/scripts/vendor/Blob.js b/app/scripts/vendor/Blob.js deleted file mode 100644 index 294debb35f..0000000000 --- a/app/scripts/vendor/Blob.js +++ /dev/null @@ -1,215 +0,0 @@ -/* eslint-disable */ -/* Blob.js - * A Blob implementation. - * 2014-07-24 - * - * By Eli Grey, http://eligrey.com - * By Devin Samarin, https://github.com/dsamarin - * License: X11/MIT - * See https://github.com/eligrey/Blob.js/blob/master/LICENSE.md - */ - -/*global self, unescape */ -/*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true, - plusplus: true */ - -/*! @source http://purl.eligrey.com/github/Blob.js/blob/master/Blob.js */ - -if(typeof window !== "undefined") { -(function (view) { - "use strict"; - - view.URL = view.URL || view.webkitURL; - - if (view.Blob && view.URL) { - try { - new Blob; - return; - } catch (e) {} - } - - // Internally we use a BlobBuilder implementation to base Blob off of - // in order to support older browsers that only have BlobBuilder - var BlobBuilder = view.BlobBuilder || view.WebKitBlobBuilder || view.MozBlobBuilder || (function(view) { - var - get_class = function(object) { - return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1]; - } - , FakeBlobBuilder = function BlobBuilder() { - this.data = []; - } - , FakeBlob = function Blob(data, type, encoding) { - this.data = data; - this.size = data.length; - this.type = type; - this.encoding = encoding; - } - , FBB_proto = FakeBlobBuilder.prototype - , FB_proto = FakeBlob.prototype - , FileReaderSync = view.FileReaderSync - , FileException = function(type) { - this.code = this[this.name = type]; - } - , file_ex_codes = ( - "NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR " - + "NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR" - ).split(" ") - , file_ex_code = file_ex_codes.length - , real_URL = view.URL || view.webkitURL || view - , real_create_object_URL = real_URL.createObjectURL - , real_revoke_object_URL = real_URL.revokeObjectURL - , URL = real_URL - , btoa = view.btoa - , atob = view.atob - - , ArrayBuffer = view.ArrayBuffer - , Uint8Array = view.Uint8Array - - , origin = /^[\w-]+:\/*\[?[\w\.:-]+\]?(?::[0-9]+)?/ - ; - FakeBlob.fake = FB_proto.fake = true; - while (file_ex_code--) { - FileException.prototype[file_ex_codes[file_ex_code]] = file_ex_code + 1; - } - // Polyfill URL - if (!real_URL.createObjectURL) { - URL = view.URL = function(uri) { - var - uri_info = document.createElementNS("http://www.w3.org/1999/xhtml", "a") - , uri_origin - ; - uri_info.href = uri; - if (!("origin" in uri_info)) { - if (uri_info.protocol.toLowerCase() === "data:") { - uri_info.origin = null; - } else { - uri_origin = uri.match(origin); - uri_info.origin = uri_origin && uri_origin[1]; - } - } - return uri_info; - }; - } - URL.createObjectURL = function(blob) { - var - type = blob.type - , data_URI_header - ; - if (type === null) { - type = "application/octet-stream"; - } - if (blob instanceof FakeBlob) { - data_URI_header = "data:" + type; - if (blob.encoding === "base64") { - return data_URI_header + ";base64," + blob.data; - } else if (blob.encoding === "URI") { - return data_URI_header + "," + decodeURIComponent(blob.data); - } if (btoa) { - return data_URI_header + ";base64," + btoa(blob.data); - } else { - return data_URI_header + "," + encodeURIComponent(blob.data); - } - } else if (real_create_object_URL) { - return real_create_object_URL.call(real_URL, blob); - } - }; - URL.revokeObjectURL = function(object_URL) { - if (object_URL.substring(0, 5) !== "data:" && real_revoke_object_URL) { - real_revoke_object_URL.call(real_URL, object_URL); - } - }; - FBB_proto.append = function(data/*, endings*/) { - var bb = this.data; - // decode data to a binary string - if (Uint8Array && (data instanceof ArrayBuffer || data instanceof Uint8Array)) { - var - str = "" - , buf = new Uint8Array(data) - , i = 0 - , buf_len = buf.length - ; - for (; i < buf_len; i++) { - str += String.fromCharCode(buf[i]); - } - bb.push(str); - } else if (get_class(data) === "Blob" || get_class(data) === "File") { - if (FileReaderSync) { - var fr = new FileReaderSync; - bb.push(fr.readAsBinaryString(data)); - } else { - // async FileReader won't work as BlobBuilder is sync - throw new FileException("NOT_READABLE_ERR"); - } - } else if (data instanceof FakeBlob) { - if (data.encoding === "base64" && atob) { - bb.push(atob(data.data)); - } else if (data.encoding === "URI") { - bb.push(decodeURIComponent(data.data)); - } else if (data.encoding === "raw") { - bb.push(data.data); - } - } else { - if (typeof data !== "string") { - data += ""; // convert unsupported types to strings - } - // decode UTF-16 to binary string - bb.push(unescape(encodeURIComponent(data))); - } - }; - FBB_proto.getBlob = function(type) { - if (!arguments.length) { - type = null; - } - return new FakeBlob(this.data.join(""), type, "raw"); - }; - FBB_proto.toString = function() { - return "[object BlobBuilder]"; - }; - FB_proto.slice = function(start, end, type) { - var args = arguments.length; - if (args < 3) { - type = null; - } - return new FakeBlob( - this.data.slice(start, args > 1 ? end : this.data.length) - , type - , this.encoding - ); - }; - FB_proto.toString = function() { - return "[object Blob]"; - }; - FB_proto.close = function() { - this.size = 0; - delete this.data; - }; - return FakeBlobBuilder; - }(view)); - - view.Blob = function(blobParts, options) { - var type = options ? (options.type || "") : ""; - var builder = new BlobBuilder(); - if (blobParts) { - for (var i = 0, len = blobParts.length; i < len; i++) { - if (Uint8Array && blobParts[i] instanceof Uint8Array) { - builder.append(blobParts[i].buffer); - } - else { - builder.append(blobParts[i]); - } - } - } - var blob = builder.getBlob(type); - if (!blob.slice && blob.webkitSlice) { - blob.slice = blob.webkitSlice; - } - return blob; - }; - - var getPrototypeOf = Object.getPrototypeOf || function(object) { - return object.__proto__; - }; - view.Blob.prototype = getPrototypeOf(new view.Blob()); -}(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this.content || this)); -} - /* eslint-enable */ diff --git a/app/scripts/vendor/FileSaver.js b/app/scripts/vendor/FileSaver.js deleted file mode 100644 index 910a217e1e..0000000000 --- a/app/scripts/vendor/FileSaver.js +++ /dev/null @@ -1,260 +0,0 @@ -/* eslint-disable */ -/* FileSaver.js - * A saveAs() FileSaver implementation. - * 2015-05-07.2 - * - * By Eli Grey, http://eligrey.com - * License: X11/MIT - * See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md - */ - -/*global self */ -/*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */ - -/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */ - -if(typeof window !== "undefined") { - -var saveAs = saveAs || (function(view) { - "use strict"; - // IE <10 is explicitly unsupported - if (typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) { - return; - } - var - doc = view.document - // only get URL when necessary in case Blob.js hasn't overridden it yet - , get_URL = function() { - return view.URL || view.webkitURL || view; - } - , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a") - , can_use_save_link = "download" in save_link - , click = function(node) { - var event = doc.createEvent("MouseEvents"); - event.initMouseEvent( - "click", true, false, view, 0, 0, 0, 0, 0 - , false, false, false, false, 0, null - ); - node.dispatchEvent(event); - } - , webkit_req_fs = view.webkitRequestFileSystem - , req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem - , throw_outside = function(ex) { - (view.setImmediate || view.setTimeout)(function() { - throw ex; - }, 0); - } - , force_saveable_type = "application/octet-stream" - , fs_min_size = 0 - // See https://code.google.com/p/chromium/issues/detail?id=375297#c7 and - // https://github.com/eligrey/FileSaver.js/commit/485930a#commitcomment-8768047 - // for the reasoning behind the timeout and revocation flow - , arbitrary_revoke_timeout = 500 // in ms - , revoke = function(file) { - var revoker = function() { - if (typeof file === "string") { // file is an object URL - get_URL().revokeObjectURL(file); - } else { // file is a File - file.remove(); - } - }; - if (view.chrome) { - revoker(); - } else { - setTimeout(revoker, arbitrary_revoke_timeout); - } - } - , dispatch = function(filesaver, event_types, event) { - event_types = [].concat(event_types); - var i = event_types.length; - while (i--) { - var listener = filesaver["on" + event_types[i]]; - if (typeof listener === "function") { - try { - listener.call(filesaver, event || filesaver); - } catch (ex) { - throw_outside(ex); - } - } - } - } - , auto_bom = function(blob) { - // prepend BOM for UTF-8 XML and text/* types (including HTML) - if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) { - return new Blob(["\ufeff", blob], {type: blob.type}); - } - return blob; - } - , FileSaver = function(blob, name) { - blob = auto_bom(blob); - // First try a.download, then web filesystem, then object URLs - var - filesaver = this - , type = blob.type - , blob_changed = false - , object_url - , target_view - , dispatch_all = function() { - dispatch(filesaver, "writestart progress write writeend".split(" ")); - } - // on any filesys errors revert to saving with object URLs - , fs_error = function() { - // don't create more object URLs than needed - if (blob_changed || !object_url) { - object_url = get_URL().createObjectURL(blob); - } - if (target_view) { - target_view.location.href = object_url; - } else { - var new_tab = view.open(object_url, "_blank"); - if (new_tab == undefined && typeof safari !== "undefined") { - //Apple do not allow window.open, see http://bit.ly/1kZffRI - view.location.href = object_url - } - } - filesaver.readyState = filesaver.DONE; - dispatch_all(); - revoke(object_url); - } - , abortable = function(func) { - return function() { - if (filesaver.readyState !== filesaver.DONE) { - return func.apply(this, arguments); - } - }; - } - , create_if_not_found = {create: true, exclusive: false} - , slice - ; - filesaver.readyState = filesaver.INIT; - if (!name) { - name = "download"; - } - if (can_use_save_link) { - object_url = get_URL().createObjectURL(blob); - save_link.href = object_url; - save_link.download = name; - click(save_link); - filesaver.readyState = filesaver.DONE; - dispatch_all(); - revoke(object_url); - return; - } - // Object and web filesystem URLs have a problem saving in Google Chrome when - // viewed in a tab, so I force save with application/octet-stream - // http://code.google.com/p/chromium/issues/detail?id=91158 - // Update: Google errantly closed 91158, I submitted it again: - // https://code.google.com/p/chromium/issues/detail?id=389642 - if (view.chrome && type && type !== force_saveable_type) { - slice = blob.slice || blob.webkitSlice; - blob = slice.call(blob, 0, blob.size, force_saveable_type); - blob_changed = true; - } - // Since I can't be sure that the guessed media type will trigger a download - // in WebKit, I append .download to the filename. - // https://bugs.webkit.org/show_bug.cgi?id=65440 - if (webkit_req_fs && name !== "download") { - name += ".download"; - } - if (type === force_saveable_type || webkit_req_fs) { - target_view = view; - } - if (!req_fs) { - fs_error(); - return; - } - fs_min_size += blob.size; - req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) { - fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) { - var save = function() { - dir.getFile(name, create_if_not_found, abortable(function(file) { - file.createWriter(abortable(function(writer) { - writer.onwriteend = function(event) { - target_view.location.href = file.toURL(); - filesaver.readyState = filesaver.DONE; - dispatch(filesaver, "writeend", event); - revoke(file); - }; - writer.onerror = function() { - var error = writer.error; - if (error.code !== error.ABORT_ERR) { - fs_error(); - } - }; - "writestart progress write abort".split(" ").forEach(function(event) { - writer["on" + event] = filesaver["on" + event]; - }); - writer.write(blob); - filesaver.abort = function() { - writer.abort(); - filesaver.readyState = filesaver.DONE; - }; - filesaver.readyState = filesaver.WRITING; - }), fs_error); - }), fs_error); - }; - dir.getFile(name, {create: false}, abortable(function(file) { - // delete file if it already exists - file.remove(); - save(); - }), abortable(function(ex) { - if (ex.code === ex.NOT_FOUND_ERR) { - save(); - } else { - fs_error(); - } - })); - }), fs_error); - }), fs_error); - } - , FS_proto = FileSaver.prototype - , saveAs = function(blob, name) { - return new FileSaver(blob, name); - } - ; - // IE 10+ (native saveAs) - if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) { - return function(blob, name) { - return navigator.msSaveOrOpenBlob(auto_bom(blob), name); - }; - } - - FS_proto.abort = function() { - var filesaver = this; - filesaver.readyState = filesaver.DONE; - dispatch(filesaver, "abort"); - }; - FS_proto.readyState = FS_proto.INIT = 0; - FS_proto.WRITING = 1; - FS_proto.DONE = 2; - - FS_proto.error = - FS_proto.onwritestart = - FS_proto.onprogress = - FS_proto.onwrite = - FS_proto.onabort = - FS_proto.onerror = - FS_proto.onwriteend = - null; - - return saveAs; -}( - typeof self !== "undefined" && self - || typeof window !== "undefined" && window - || this && this.content -)); -// `self` is undefined in Firefox for Android content script context -// while `this` is nsIContentFrameMessageManager -// with an attribute `content` that corresponds to the window - -if (typeof module !== "undefined" && module.exports) { - module.exports.saveAs = saveAs; -} else if ((typeof define !== "undefined" && define !== null) && (define.amd != null)) { - define([], function() { - return saveAs; - }); -} -} else { - // nope -} -/* eslint-enable */ diff --git a/app/styles/common/_repository-list-item.scss b/app/styles/common/_repository-list-item.scss deleted file mode 100644 index 1cd1411c48..0000000000 --- a/app/styles/common/_repository-list-item.scss +++ /dev/null @@ -1,98 +0,0 @@ -.repository-list-item { - display: flex; - flex-flow: row; - border: 1px solid $secondary-5; - border-radius: $global-radius; - margin: 1rem; - font-weight: $font-weight-bold; - color: $secondary-2; - background: $white; - &:hover { - border-color: $primary-1; - .section { - &.action { - background-color: $primary-1; - color: white; - border-color: $primary-1; - } - } - } - > a { - display: flex; - flex: 1; - } - .avatar { - background: $primary-color; - width: 50px; - height: 50px; - border-radius: $global-radius; - } - .section { - display: flex; - border-left: 1px solid $secondary-5; - padding: 1rem; - flex-flow: row; - &.head { - flex-grow: 1; - } - &:first-child { - border-left: 0; - } - &.stats { - min-width: 100px; - text-align: center; - } - &.action { - background-color: $secondary-5;; - color: $secondary-4; - flex-flow: column; - i { - position: relative; - top: 0.5rem; - left: 1.2rem; - } - .text { - margin-top: 1.2rem; - margin-left: 0.4rem; - font-size: 0.7rem; - } - } - .title { - padding-left: 1rem; - padding-right: 1rem; - padding-top: 0.25rem; - } - .labels { - font-size: rem-calc(12px); - color: $secondary-4; - .official { - color: $primary-1; - } - .public { - color: darken($primary-1, 30%); - } - .private { - color: darken($primary-6, 35%); - } - .automated { - color: $secondary-4; - } - } - .label-value { - padding-top: 0.25rem; - margin: 0 auto; - .value { - font-size: rem-calc(14px); - margin-bottom: 0.25rem; - color: $secondary-3; - } - .sub-label { - font-size: rem-calc(10px); - color: $secondary-3; - } - } - .repo-name { - font-size: rem-calc(18px); - } - } -} diff --git a/app/styles/font-awesome.min.css b/app/styles/font-awesome.min.css deleted file mode 100644 index 9c24364d62..0000000000 --- a/app/styles/font-awesome.min.css +++ /dev/null @@ -1,4 +0,0 @@ -/*! - * Font Awesome 4.4.0 by @davegandy - http://fontawesome.io - @fontawesome - * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) - */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.4.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.4.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.4.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.4.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.4.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.4.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"} \ No newline at end of file diff --git a/app/styles/hub.scss b/app/styles/hub.scss deleted file mode 100644 index 3ec7183cf9..0000000000 --- a/app/styles/hub.scss +++ /dev/null @@ -1,18 +0,0 @@ -@import 'hub/account'; -@import 'hub/autobuilds'; -@import 'hub/badge'; -@import 'hub/blankslate'; -@import 'hub/flyout-menu'; -@import 'hub/react-tagsinput'; -@import 'hub/main-nav'; -@import 'hub/profile'; -@import 'hub/repositories'; -@import 'hub/repository-settings'; -@import 'hub/reset-password'; -@import 'hub/search'; -@import 'hub/tabs'; -@import 'hub/type'; -@import 'hub/usericons'; -@import 'hub/welcome'; -@import 'hub/forms'; -@import 'hub/docker-trusted-registry'; diff --git a/app/styles/hub/_blankslate.scss b/app/styles/hub/_blankslate.scss deleted file mode 100644 index 7fb8a37d73..0000000000 --- a/app/styles/hub/_blankslate.scss +++ /dev/null @@ -1,84 +0,0 @@ -/* - * For pages without content - * - */ - -.blankslate { - text-align: center; - background: #fff; - border-bottom: 1px solid #cbd1d7; - padding: 2.4rem; - h1 { - font-size: 2.5em; - } - .fa { - color: #566471; - font-size: 4em; - margin-bottom: 15px; - } -} - -.blankslate-alt { - text-align: center; - padding: 5rem; -} - -/* - * - * buttons : TODO: MOVE TO FOUNDATION OVERRIDES & SPLIT OUT THESE RANDOM BUTTONS - * - */ - -button, -.button, -.profile-settings .change-pass-form .change-pass-save .button, -.settings-wrapper input[type='submit'] { - -moz-appearance: none; - border-radius: $global-radius; - border-color: #1298c6; - border-style: solid; - border-width: 0; - color: #ffffff; - cursor: pointer; - display: inline-block; - font-size: 1rem; - font-weight: normal; - margin: 0 0 1.25rem; - padding: 0.7rem 1rem 0.7rem 0.9rem; - text-align: center; - transition: background-color 300ms ease-out 0s; - box-shadow: none; - &.default { - background-color: #fff; - border: 1px solid #dfe4ea; - color: #000; - } - &.primary { - background: $primary-1; - border-radius: $global-radius; - color: #fff; - &:hover { - background: $primary-2; - } - } - // &.secondary {/** will switch this with .default **/} - &.dashed { - background-color: transparent; - border: 1px dashed #c3ccd9; - color: #2f4559;/** need variable **/ - border-radius: $global-radius; - &:hover { - opacity: .8; - } - } - &.button.disabled { - cursor: not-allowed; - } - &.small { - padding: 0.7rem 1rem 0.7rem 0.9rem; - } - &.xl { - padding: 1rem 2rem 1rem 2rem; - margin-right: 1rem; - } -} diff --git a/app/styles/hub/_profile.scss b/app/styles/hub/_profile.scss deleted file mode 100644 index cca73f4675..0000000000 --- a/app/styles/hub/_profile.scss +++ /dev/null @@ -1,30 +0,0 @@ -.gravatar { - margin: 1.5rem 0; - img { - border: 1px solid $secondary-5; - border-radius: $global-radius; - } -} - -.profile-info { - padding: .5rem 1rem 0 1rem; - ul { - padding: .6rem 0; - li { - padding: .2rem 0; - color: $secondary-4; - .fa { - margin: 0 .5rem 0 0; - min-width: .8rem; - text-align: center; - } - } - } -} - -.profile-repos { - padding: 1rem 0; - h4 { - padding-left: 2rem; - } -} diff --git a/app/styles/hub/_type.scss b/app/styles/hub/_type.scss deleted file mode 100644 index 683ab8a3cd..0000000000 --- a/app/styles/hub/_type.scss +++ /dev/null @@ -1,19 +0,0 @@ -/* - * This file is in progress - will contain global typography styles - * - */ -h1, -h2, -h3, -h4, -h5, -h6 { - color: $primary-1; - font-weight: 200; -} -h1 { - font-size: 1.8875rem; -} -h2 { - font-size: 1.3875rem; -} \ No newline at end of file diff --git a/app/styles/hub/account.scss b/app/styles/hub/account.scss deleted file mode 100644 index 5d577764e4..0000000000 --- a/app/styles/hub/account.scss +++ /dev/null @@ -1,518 +0,0 @@ -.settings-wrapper { - width: 100%; - input { - &[type='text'],&[type='email'],&[type='password'] { - color: $secondary-1; - } - &[type='submit'] { - padding: .5rem; - } - } - .settings-body { - padding: 25px 0px; - .account-section-text { - float: left; - display:inline-block; - } - .account-section-header { - padding-left: 0; - .account-section-title{ - color: $secondary-1; - font-weight: $font-weight-bold; - } - .account-section-subtitle{ - color: $primary-2; - margin-bottom: .5rem; - } - } - .account-section { - margin-bottom: 2rem; - .columns:last-child { - float: left; - } - } - } -} - -.profile-settings { - .default-repo-visibility { - padding: 1rem; - .visibility-toggle { - &:hover { - cursor: pointer; - cursor: hand; - } - input { - margin-right: .5rem; - } - } - } - .email-wrapper { - border: 1px solid $border-input; - background: white; - form { - .add-email { - padding: 2rem 1rem 0; - .email-title { - font-weight: $font-weight-bold; - } - } - .email-element { - height: 4rem; - padding: 0 1rem; - margin: .5rem .5rem; - display: flex; - align-items: left; - .emphasis {/** TODO: Scope to .email-element for the moment, however will mostly be global **/ - color: $secondary-3; - font-weight: 800; - } - .fa-times {/** TODO: Scope to .email-element for the moment, however will mostly be global **/ - color: $primary-5; - font-size: 1.3rem; - &:hover { - color: $secondary-1; - } - } - .close-button {/** TODO: Let's verify we still need this **/ - color: white; - display: inline-block; - background: $docker-dark--placeholders; - border-radius: 100%; - width: 1.5rem; - height: 1.5rem; - text-align: center; - margin-right: .5rem; - float: right; - &:hover { - background: darken($docker-dark--placeholders, 10%); - } - } - .email-action { - text-align: center; - border-radius: 1rem; - &.status-sent { - border: 1px solid $primary-2; - color: $primary-2; - } - &.status-sending { - border: 1px solid $primary-1; - color: $primary-1; - } - &.status-failed { - border: 1px solid $primary-5; - color: $primary-5; - } - } - .email-address { - word-wrap: break-word; - } - } - } - } - .change-pass-form { - border: 1px solid $border-input; - background: white; - padding: 3rem 3rem 1rem 3rem; - .change-pass-save { - height: 250px; - display: flex; - align-items: flex-end; - .button { - padding:.5rem; - } - } - &.success { - border: 1px solid $primary-2; - } - &.form-error { - border: 1px solid $primary-5; - } - } - .account-info-wrapper { - border: 1px solid $border-input; - background: white; - padding: 3rem 3rem 1rem; - .button { - float: right; - } - &.success { - border: 1px solid $primary-2; - } - &.form-error { - border: 1px solid $primary-5; - } - } - .toOrgButton { - padding: .5rem 0; - } -} -.convert-to-org{ - .toOrg-title { - font-weight: $font-weight-bold; - } - .toOrg-body { - margin-bottom: 1rem; - } - .warning { - text-align: center; - color: $primary-5; - } - .convert-org-form { - padding: 3rem 2rem .5rem; - background: white; - border: 1px solid $border-input; - .button { - padding:.5rem; - &:disabled { - background: $secondary-5; - } - } - } -} - -.accounts-services { - .linked-accounts { - margin-bottom: 5rem; - .link-service { - padding: 1.25rem; - margin: 0 1rem; - height: 13rem; - border: 1px solid $border-input; - background: white; - float: left; - .service-title { - display:flex; - align-items: center; - .linked-icon { - width: 100%; - height: auto; - } - .service-name { - font-weight: $font-weight-bold; - margin: 0 1rem; - } - } - .user-access { - margin: .5rem 0 0; - } - .button { - margin: 1rem 0 0; - float: right; - } - } - } -} - -.account-notifications { - form { - background: white; - border: 1px solid $border-input; - padding: 2rem 2rem 1rem; - .button { - margin-right: 1rem; - // padding: .5rem; - float: right; - } - &.success { - border: 1px solid $primary-2; - } - &.form-error { - border: 1px solid $primary-5; - } - } - .event-notifs { - margin-bottom: 5rem; - } - .notification { - margin-bottom: 1rem; - &:hover { - cursor: pointer; - cursor: hand; - } - &.unverified { - color: $secondary-4; - cursor: default; - } - } -} - -.billing-plans { - .columns:last-child { - float: left; - } - .account-billing-info { - margin-left: .5rem; - } - .plans-error-message { - background: $alert-color; - color:white; - } - .plans-q { - .q-title { - font-weight: 500; - color: $primary-2; - } - .q-answer { - padding-left: 1rem; - } - margin-bottom: 2rem; - } - .billing-info { - background: white; - border: 1px solid $border-input; - padding: 2rem 0rem 2rem 2rem; - margin: .5rem; - .row { - margin-bottom: 1rem; - .info-content { - border-left: 1px solid $border-input; - padding: .5rem 3rem; - } - .no-account { - text-align: center; - } - } - } - .billing-form-wrapper { - border: 1px solid $border-input; - background: white; - padding: 3rem 3rem 1rem; - .billing-form-header { - text-align: center; - } - .billing-info-form { - .billing-form-section { - margin-bottom: 1.5rem; - } - .billing-field * { - width: 100%; - } - .billing-dropdown { - width: 100%; - &.error { - border: 1px solid $alert-color; - } - } - .accepted-cards { - margin-bottom: 35px; - .card-icon { - font-size: 1.5rem; - margin-left: .5rem; - } - } - .above-selects .group { - margin-bottom: 15px; - } - .selects { - .date-text { - text-align: center; - height: 2rem; - display: flex; - align-items: center; - } - .columns { - margin-bottom: 20px; - } - } - .back { - margin-left: 2rem; - } - } - } - .preview-box { - border: 1px solid $border-input; - background: white; - padding: 2rem 2rem 0; - margin-left: 1rem; - .total { - margin-bottom: 35px; - } - .coupon_code * { - width: 100%; - } - .price { - text-align: right; - } - } - .invoice-table { - a.not-active { - pointer-events: none; - cursor: default; - color: $secondary-5; - } - } -} -.orgs-body { - padding-top: rem-calc(15px); - padding-bottom: rem-calc(20px); -} - -.orgs-grid { - margin-left: 1.6rem; -} - -.orgs-settings { - h5 { - font-weight: 400; - color: #22b8eb;/** find varible and update */ - float: left; - margin: 0 0 0.8rem 1rem; - // color: $docker-dark; - } - .page-header-buttons { - float: left; - padding-left: 20px; - button { - margin-right: rem-calc(10px); - } - } - .new-org-form { - width: 100%; - } - .org-details { - ul { - list-style: none; - margin-left: 0; - li { - background-color: $panel-bg; - padding: rem-calc(10px); - margin-bottom: rem-calc(5px); - border-radius: rem-calc(2px); - margin: 0 .2rem 0 0; - } - } - .org-team-md { - margin-left: rem-calc(-15px); - .inline-list { - margin: 0; - } - h5 { - margin-left: rem-calc(10px); - font-weight: 300; - font-color: #22b8eb; - } - h6 { - background-color: lighten($panel-bg, 8%); - border-radius: $global-radius; - padding: 10px; - .action-icon { - background-color: lighten($panel-bg, 8%); - } - } - .org-members { - li { - img { - margin-right: rem-calc(10px); - border-radius: 100%; - } - width: rem-calc(200px); - padding: rem-calc(12px); - margin-right: rem-calc(20px); - } - } - // .org-teams {} - } - /** hide border when dux-form is in tabs **/ - .dux-form { - border: 0; - } - } - .tab-title { - border: 1px solid #c4cdda; - border-bottom: none; - border-top-left-radius: $global-radius; - border-top-right-radius: $global-radius; - background-color: #e6edf4; - padding: 0.5rem; - &:hover { - cursor: pointer; - color: #23b8eb; - } - } - .tab-title.active { - background-color: white; - } - .tabs-content { - border-bottom-left-radius: $global-radius; - border-bottom-right-radius: $global-radius; - border-top-right-radius: $global-radius; - border: 1px solid #c4cdda; - background-color: white; - padding: rem-calc(20px); - } -} - -//Teams -.team-item { - a { - margin-left: rem-calc(15px); - } -} - -.add-team-container { - form { - margin-top: 1.6rem; - .alert-box { - margin-left: 0.5rem !important; - margin-right: 0.5rem !important; - } - } -} - -.add-team-button-group { - input[type="submit"], input[type="reset"] { - border-radius: $global-radius; - margin-left: 1rem; - } -} - -//global -li.li-no-hover { - &:hover { - background-color: transparent !important; - } -} - -.delete-member-item { - height: rem-calc(25px); - cursor: default; - a { - float: left; - margin-left: 0.7rem; - } - i { - margin-top: 0.3rem; - margin-right: 1.4rem; - cursor: pointer; - color: #FF5151; - } -} -.add-member-item { - height: rem-calc(25px); - cursor: text; - input[type="text"] { - font-size: rem-calc(16px); - margin-left: 0.5rem; - float: left; - border: 0; - height: 2rem; - line-height: 2rem; - color: $gray-2; - width: rem-calc(500px); - &:hover { - color: $gray-2; - } - &:active { - color: $gray-2; - } - &:focus { - color: $gray-2; - } - } - i { - margin-top: 0.3rem; - margin-right: -1.5rem; - cursor: pointer; - } -} diff --git a/app/styles/hub/autobuilds.scss b/app/styles/hub/autobuilds.scss deleted file mode 100644 index f95ba83e46..0000000000 --- a/app/styles/hub/autobuilds.scss +++ /dev/null @@ -1,108 +0,0 @@ -.ol-decimal { - list-style-type: decimal; -} - -.auto-build-tags-table { - input[type="text"] { - max-width:180px; - } -} - -.autobuild-checkbox { - font-size: 14px; - font-weight: 300; - cursor: pointer; - * { - cursor: pointer; - } - .checkbox-text { - margin-left: 5px; - } -} - -//GLOBAL? -.two-level-selector { - margin-top: 1.0rem; - .dux-form { - padding: 0; - margin: 0; - } - .row { - padding: 0; - margin: 0; - .columns { - padding: 0; - } - } - //this is actually a lighter filter bar - .searchbar input[type=text] { - background-color: $secondary-4; - width: 100%; - } - .filterbar-container { - margin-left: rem-calc(24px); - } -} - -//Strip out the module class -ul.stripped-module { - background: #fff; - list-style: none; - padding: 0 !important; - margin: 0 !important; - li { - text-align: left; - border-bottom: 1px solid #cbd1d7; - padding-top: 0.5rem; - padding-bottom: 0.5rem; - &:hover { - background: $secondary-6; - cursor: pointer; - } - .list-item { - padding-left: 1rem; - padding-right: 1rem; - } - } - img { - border-radius: $global-radius; - } - .header-bar { - background-color: $secondary-6; - min-height: rem-calc(60px); - cursor: default; - } - .header-title { - margin-left: 1rem; - margin-top: 0.5rem; - font-size: rem-calc(18px); - font-weight: 400; - } - .alert-box { - margin-left: 0.5rem; - margin-right: 0.5rem; - } -} - -ul.left-border { - border-left: 1px solid #cbd1d7; -} - -ul.right-border { - border-right: 1px solid #cbd1d7; -} - -//fa i class needs this -.arrow-sel { - margin-top: 0.25rem; - margin-right: 0.25rem; -} - -.create-autobuild-form { - .form-error { - border: 1px solid $primary-5; - } - .text-error { - color: $primary-5; - } -} diff --git a/app/styles/hub/badge.scss b/app/styles/hub/badge.scss deleted file mode 100644 index f17d6adac9..0000000000 --- a/app/styles/hub/badge.scss +++ /dev/null @@ -1,11 +0,0 @@ -.dux-badge { - border-radius: rem-calc(4px); - padding: rem-calc(3px); - &.official { - color: #23b8eb; - } - &.builds { - color: #86d800; - font-size: rem-calc(12px); - } -} diff --git a/app/styles/hub/flyout-menu.scss b/app/styles/hub/flyout-menu.scss deleted file mode 100644 index e8234f592f..0000000000 --- a/app/styles/hub/flyout-menu.scss +++ /dev/null @@ -1,185 +0,0 @@ -//@extend-elements -//original selectors -//.cssmenu ul, .cssmenu ul li, .cssmenu ul ul -%extend_1 { - list-style: none; - margin: 0; - padding: 0; -} - -//original selectors -//.cssmenu ul li.hover, .cssmenu ul li:hover -%extend_2 { - position: relative; - z-index: 599; - cursor: default; -} - - -@charset "UTF-8"; -.cssmenu { - padding: 0; - margin: 0; - border: 0; - line-height: 1; - width: 100%; - background: $panel-bg; - font-family: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif; - zoom: 1; - font-size: 12px; - ul { - @extend %extend_1; - position: relative; - z-index: 597; - float: left; - li { - @extend %extend_1; - min-height: 1px; - line-height: 3rem; - vertical-align: middle; - position: relative; - float: none; - &.hover { - @extend %extend_2; - } - &:hover { - @extend %extend_2; - > ul { - visibility: visible; - } - } - &.has-sub > a:after { - content: '+'; - position: absolute; - top: 50%; - right: 15px; - margin-top: -6px; - } - } - ul { - @extend %extend_1; - visibility: hidden; - position: absolute; - z-index: 598; - top: 0; - left: 100%; - margin-top: 0; - width: 100%; - //Instead of the line below you could use @includeborder-radius($radius, $vertical-radius) - border: 1px solid $panel-bg; - li { - float: none; - font-weight: normal; - border-bottom: 1px solid $panel-bg; - &.first { - //Instead of the line below you could use @includeborder-radius($radius, $vertical-radius) - border-radius: 0 3px 0 0; - } - &.last { - //Instead of the line below you could use @includeborder-radius($radius, $vertical-radius) - border-radius: 0 0 3px 0; - border-bottom: 0; - } - &:hover > a { - background: $button-bg-color; - color: $ghost; - } - } - ul { - top: -2px; - right: 0; - } - a { - font-size: 14px; - color: $ghost; - &:hover { - color: $ghost; - } - } - } - } - &:before { - content: ''; - display: block; - } - &:after { - content: ''; - display: table; - clear: both; - } - a { - display: block; - padding: 15px 20px; - color: $ghost; - text-decoration: none; - text-transform: uppercase; - } - li { - position: relative; - } - &.align-right { - float: right; - li { - text-align: right; - } - ul { - ul { - visibility: hidden; - position: absolute; - top: 0; - left: -100%; - z-index: 598; - width: 100%; - //Instead of the line below you could use @includeborder-radius($radius, $vertical-radius) - border-radius: $global-radius 0 0 $global-radius; - li { - &.first { - //Instead of the line below you could use @includeborder-radius($radius, $vertical-radius) - border-radius: $global-radius 0 0 0; - } - &.last { - //Instead of the line below you could use @includeborder-radius($radius, $vertical-radius) - border-radius: 0 0 0 $global-radius; - } - } - } - li.has-sub > a { - &:before { - content: '+'; - position: absolute; - top: 50%; - left: 15px; - margin-top: -6px; - } - &:after { - content: none; - } - } - } - > ul > li > a { - border-left: 2px solid lighten($panel-bg, 10%); - border-right: none; - } - } - > ul { - width: 100%; - > li { - > a { - border-right: 2px solid lighten($panel-bg, 10%); - color: $ghost; - &:hover { - color: $ghost; - } - } - &.active a { - background: lighten($panel-bg, 10%); - } - a:hover { - background: lighten($panel-bg, 10%); - } - &:hover a { - background: lighten($panel-bg, 10%); - } - } - } -} diff --git a/app/styles/hub/main-nav.scss b/app/styles/hub/main-nav.scss deleted file mode 100644 index 4683e7b2c0..0000000000 --- a/app/styles/hub/main-nav.scss +++ /dev/null @@ -1,132 +0,0 @@ -/* - * These top bar properties still need to be sassified. - * - */ - -.topnav-wrapper { - background-color: $topbar-dark; -} - -.top-bar .top-bar-section ul li:hover:not(.has-form) > a { - background: transparent; -} - -.top-bar-section ul li > a { - font-weight: 400; - font-size: 14px; -} - -.top-bar-section ul li > a.button.secondary:hover, -.top-bar-section ul li > a.button.secondary:focus { - color: #fff; - background: transparent; -} - -.top-bar-section ul li > a.button.secondary { - background-color: transparent; - color: #c4cdda; - font-size: 1em; - height: 40px; - margin-top: -3px; -} -.top-bar-section li:not(.has-form) a:not(.button) { - background: transparent; - line-height: 3.125rem; -} -/* - * - * - */ - -.top-bar-section { - ul li { - background: none; - a.button.tiny { - background-color: #86d800;/** temp color **/ - border-radius: $global-radius; - box-shadow: none; - &:hover { - background-color: #5fa736;/** temp color **/ - } - } - } - .profile-photo { - width: rem-calc(24px); - height: rem-calc(24px); - margin-right: 5px; - border-radius: $global-radius; - } - .title-area { - margin-top: .5rem; - a { - padding: 1rem; - } - img { - height: 36px; - margin-right: 10px - } - } - .nav-user-info { - background: none; - } - /* - * "+" menu - * - */ - .css-dropdown { - &:hover ul { - display: block; - opacity: 1; - visibility: visible; - } - ul:before { - border: 8px solid transparent; - border-bottom-color: #3d4c5a; - content: ""; - display: inline-block; - left: 90px; - position: absolute; - top: -16px; - } - ul { - // background: $topbar-dark; - background: #3d4c5a; - border-bottom-left-radius: 5px; - border-bottom-right-radius: 5px; - display: none; - padding: 0; - position: absolute; - top: 48px; - right: 4rem; - opacity: 0; - padding: .5rem 0; - visibility: hidden; - width: 220px; - z-index: 1; - li { - cursor: pointer; - float: none; - padding: .3em; - margin: 0; - position: relative; - a { - display: block; - padding-top: .23rem; - } - a:hover { - background: #7a8491; - } - } - li:not(.has-form) > a { - line-height: 1.7rem; - } - & i.fa { - font-size: 1.2rem; - padding-right: 7px; - } - &.with-button { - right: rem-calc(116px); - } - } - } -} \ No newline at end of file diff --git a/app/styles/hub/react-tagsinput.scss b/app/styles/hub/react-tagsinput.scss deleted file mode 100644 index 70287eee8f..0000000000 --- a/app/styles/hub/react-tagsinput.scss +++ /dev/null @@ -1,59 +0,0 @@ -//colors -$color_celeste_approx: #ccc; -$white: #fff; -$color_conifer_approx: #a5d24a; -$color_deco_approx: #cde69c; -$color_olive_drab_approx: #638421; -$color_cosmos_approx: #fbd8db; -$color_tamarillo_approx: #90111a; -$color_tapa_approx: #777; - -.react-tagsinput { - border: 1px solid lighten($panel-bg, 5%); - background: lighten($panel-bg, 8%); - padding: rem-calc(10px); - overflow-y: auto; - //Instead of the line below you could use @includeborder-radius($radius, $vertical-radius) - border-radius: rem-calc(2px); - input { - color: $charcoal; - } -} -.react-tagsinput-tag { - display: block; - border: 1px solid $secondary-5; - background: $secondary-6; - color: $oil; - font-size: 14px; - float: left; - padding: 15px; - margin-right: 10px; - margin-bottom: 10px; - text-decoration: none; - //Instead of the line below you could use @includeborder-radius($radius, $vertical-radius) - border-radius: $global-radius; -} -.react-tagsinput-invalid { - background: transparent; - color: $primary-5; -} -.react-tagsinput-remove { - font-weight: 300; - color: $secondary-4; - text-decoration: none; - font-size: 14px; - cursor: pointer; - &:before { - content: "x"; - } -} -.react-tagsinput-input { - background: transparent; - color: $charcoal; - border: 0; - font-size: 13px; - padding: 5px; - margin: 0; - width: 80px; - outline: none; -} \ No newline at end of file diff --git a/app/styles/hub/repositories.scss b/app/styles/hub/repositories.scss deleted file mode 100644 index 3323d95ff8..0000000000 --- a/app/styles/hub/repositories.scss +++ /dev/null @@ -1,155 +0,0 @@ -ul.repositories { - margin: 2.25rem 0.3rem 0 0.3rem; -} -.repo-header { - padding: rem-calc(10px); -} -.repo-content { - padding: rem-calc(10px); -} -.repository { - background: white; - .title { - color: $primary-color; - } - .logo { - width: 64px; - min-width: 64px; - height: 64px; - min-height: 64px; - padding: 10px; - background: $primary-color; - border-radius: $global-radius; - .d-logo { - color: $ghost; - font-size: rem-calc(48px); - margin: 0 auto; - } - } - .header { - padding-top: 0.325rem; - h6 small { - font-size: small; - } - h6 span { - font-size: small; - text-transform: capitalize; - color: #3f5167; - } - } - .repo-wrapper { - margin-left: 0.5rem; - margin-right: 0.5rem; - } - //TODO: These surely should be `scss-ified` - .repo-stars { - border: 1px solid #c4cdda; - border-left: none; - padding: 10px; - p { - font-size: smaller; - } - } - .repo-downloads { - border: 1px solid #c4cdda; - border-left: none; - border-right: none; - padding: 10px; - p { - font-size: smaller; - } - } -} - -.repo-separator { - font-weight: 300; - font-size: rem-calc(24px); - margin-right: 0px; - padding-right: 0px; - width: 20px; -} - -.repo-form-margin { - margin-left: -15px; -} - -//Need this to make foundation block-grid work with our design and borders -.repo-border { - border:1px solid white; - position:relative; - z-index:10 -} - -.repo-border:before { - content:""; - display:block; - position:absolute; - top:2px; - left:2px; - right:2px; - bottom:2px; - border:1px solid #c4cdda; - border-radius: $global-radius; -} - -.repository-page { - .repo-description-dockerfile { - .dockerfile { - font-family: $font-family-monospace; - white-space: pre; - overflow-x: auto; - } - } - .repo-details-content { - .repo-visibility { - margin-bottom: 1.25rem; - background: white; - border: 1px solid $docker-dark--placeholders; - padding: .75rem 1rem; - .privacy { - font-weight: $font-weight-bold; - display: inline-block; - } - .status { - display: inline-block; - } - } - - - - .temp-prof-icon { - height: 50px; - width: 50px; - border-radius: 100%; - border: 1px solid black; - display: inline-block; - margin-right: 10px; - } - } -} - -.explore-repo-list { - margin-top: 1rem; -} - -.add-repository-form { - margin-top: rem-calc(20px); -} - -.repo-tags { - margin: 0; - padding: 0; - list-style-type: none; - li { - float: left; - padding: 0.3rem 0.3rem 1rem 0; - margin-right: 0.5rem; - .repo-tag { - background-color: #3c5164; - color: white; - border-radius: $global-radius; - padding: 0.5rem 0.8rem; - } - } -} - diff --git a/app/styles/hub/repository-settings.scss b/app/styles/hub/repository-settings.scss deleted file mode 100644 index bf957d5600..0000000000 --- a/app/styles/hub/repository-settings.scss +++ /dev/null @@ -1,49 +0,0 @@ -.repo-settings { - color: $charcoal; - padding: 1rem; - h1, h2, h3, h4, h5, h6, input, label { - color: $charcoal; - } - .form-panel { - @include panel(); - background: $white; - button { - margin-right: $default-margin; - } - } - .help-text { - padding: 1rem 0 0 .9rem; - } - /** scope this to repo-settings only **/ - input[type="text"], - .bar { - width: 100%; - } - .repo-visibility { - margin-top: 1rem; - .visibility-form { - .visibility-toggle { - cursor: pointer; - * { - cursor: pointer; - } - .text-error { - color: $primary-5; - margin-left: 1rem; - } - } - .disabled { - cursor: default; - color: $secondary-5; - * { - cursor: default; - } - } - input { - &[name='visibility'] { - margin-right: 5px; - } - } - } - } -} diff --git a/app/styles/hub/reset-password.scss b/app/styles/hub/reset-password.scss deleted file mode 100644 index 810a6bf95d..0000000000 --- a/app/styles/hub/reset-password.scss +++ /dev/null @@ -1,49 +0,0 @@ -.pass-reset-wrapper { - align-items: center; - display: flex; - height: 100%; - width: 100%; - &.reset { - text-align: center; - } - .password-reset { - background-color: $white; - border: 1px solid rgb(233, 237, 240);// TODO: create/utilize variable - border-radius: $global-radius; - display: flex; - flex-direction: column; - justify-content: center; - min-height: 270px; - h3 { - color: $primary-1; - font-weight: 300; - } - &.error h3 { - color: $primary-5; - } - p { - color: rgb(113, 125, 144);// TODO: create/utilize variable - } - form { - margin-top: .6rem; - } - .group { - input, - .bar { - color: rgb(113, 125, 144);// TODO: create/utilize variable - width: 100%; - } - } - .resetPassSubmit { - background-color:$primary-color; - border: none; - border-radius: $global-radius; - color: $white; - float: right; - padding: 10px 20px; - &:disabled { - background-color:rgb(233, 237, 240);// TODO: create/utilize variable - } - } - } -} diff --git a/app/styles/hub/search.scss b/app/styles/hub/search.scss deleted file mode 100644 index a0a665c2e2..0000000000 --- a/app/styles/hub/search.scss +++ /dev/null @@ -1,191 +0,0 @@ -//search page -.search-page { - width: 100%; - overflow-x: hidden; - font-weight: 300; - .inline-list { - margin-top: rem-calc(12px); - li { - margin-left: 0.7rem; - } - } - select { - background-color: transparent; - border: 1px solid #c4cdda; - transition: border-color 0.15s linear 0s, background 0.15s linear 0s; - outline: 0; - color: #3f5167; - width: rem-calc(100px); - font-size: rem-calc(12px); - font-weight: 200; - border-color: #c4cdda; - border-radius: $global-radius; - } - input[type="text"] { - color: #7A8491; - } - - .search-results-container { - .no-results-item { - text-align: center; - } - } - - //Search Results - .search-results-list { - ul { - list-style-type: none; - text-align: center; - } - ul li { - display: inline-block; - padding-right: 5px; - } - .no-results-item { - list-style-type: none; - font-size: rem-calc(14px); - font-weight: normal; - } - .search-list-item { - background-color: white; - margin-bottom: rem-calc(10px);//5px 5px 5px 5px; - overflow-y: hidden; - font-weight: normal; - border: 1px solid #c4cdda; - border-radius: $global-radius; - - &:hover { - cursor: pointer; - } - - .logo { - width: 48px; - min-width: 48px; - height: 48px; - min-height: 48px; - padding: 10px; - background: $primary-color; - border-radius: $global-radius; - margin-left: rem-calc(10px); - margin-bottom: rem-calc(25px); - .d-logo { - color: $ghost; - font-size: rem-calc(32px); - margin: 0 auto; - } - } - - .search-item-avatar { - } - - .search-bar-details { - line-height: rem-calc(12px); - height: rem-calc(24px); - background-color: #c4cdda; - p { - font-weight: 300; - font-size: rem-calc(12px); - margin-bottom: 0; - line-height: 1.5rem; - } - } - - .search-item-basic-info { - .search-item-name { - font-size: 1.4rem; - font-weight: 600; - } - p { - font-size: 0.8rem; - } - .search-item-description { - font-size: rem-calc(12px); - } - } - - .search-item-other-info { - font-size: rem-calc(10px); - } - - .search-item-badges-stats { - ul li { - line-height: 0.6rem; - border-left: 1px solid #c4cdda; - } - p { - margin-bottom: 0; - font-size: rem-calc(12px); - font-weight: 500; - } - .search-item-badges { - } - .search-item-stats { - span { - padding-left: rem-calc(4px); - } - } - } - } - } -} - -.paging-bar { - display: inline-flex; - float: right; - margin-right: rem-calc(25px); - .paging-info { - align-self: center; - } - .paging-buttons { - align-self: center; - button { - margin: 0; - background-color: $body-bg; - color: $docker-dark; - padding-right: 0; - padding-left: rem-calc(4px); - box-shadow: none; - &:hover { - color: $primary-color; - box-shadow: none; - } - &:focus { - color: #7A8491; - outline: none; - box-shadow: none; - } - i { - font-size: 24; - } - } - button[disabled] { - opacity: 0.3; - box-shadow: none; - } - } -} - -.searchbar { - input[type=text] { - background: #69788a;/** need variable here **/ - border: 1px solid #4c5968;/** need variable here **/ - border-radius: $global-radius; - color: $white; - display: block; - height: 2rem; - padding: .2rem 2rem; - top: .6rem; - } - i.fa.fa-search { - color: #fff; - margin-top: -18px;/** lame **/ - margin-left: 11px;/** lame **/ - } -} - -// target webkit only meh -@media screen and (-webkit-min-device-pixel-ratio: 0) { - i.fa.fa-search { - margin-top: -16px!important;/** super lame, this can not be permanent **/ - } -} diff --git a/app/styles/hub/tabs.scss b/app/styles/hub/tabs.scss deleted file mode 100644 index ef90208ab0..0000000000 --- a/app/styles/hub/tabs.scss +++ /dev/null @@ -1,26 +0,0 @@ -.tabs { - position: relative; - float: left; - width: 100%; - li:first-child a { - border-top-left-radius: $global-radius; - } - li:last-child a { - border-top-right-radius: $global-radius; - border-right: 1px solid $docker-dark--placeholders; - } - a.repo-tab { - border-left: 1px solid $docker-dark--placeholders; - border-top: 1px solid $docker-dark--placeholders; - border-bottom: 1px solid $docker-dark--placeholders; - background:lighten($docker-dark--placeholders, 10%); - padding: .5rem 1.8rem; - font-size: 16px; - &.active { - border-bottom: 1px solid white; - background: white; - position: relative; - z-index: 2; - } - } -} diff --git a/app/styles/hub/usericons.scss b/app/styles/hub/usericons.scss deleted file mode 100644 index ca476b3191..0000000000 --- a/app/styles/hub/usericons.scss +++ /dev/null @@ -1,6 +0,0 @@ -.profile-photo { - width: rem-calc(24px); - height: rem-calc(24px); - margin-right: 5px; - border-radius: $global-radius; -} \ No newline at end of file diff --git a/app/styles/main.scss b/app/styles/main.scss deleted file mode 100644 index c7ee2ba6c6..0000000000 --- a/app/styles/main.scss +++ /dev/null @@ -1,170 +0,0 @@ -@import 'docker-ux'; -@import 'mono-blue'; -@import '_docker'; - -//============================REMOVE THIS====================================== - -$default-margin: 1.5rem; - -.flex-table { - display: flex; - flex-flow: column; - justify-content: center; - border: 1px solid $border-input; - border-radius: $global-radius; - font-size: 1rem; - margin: 0.5rem; - line-height: 1.5; - font-weight: 500; - color: $secondary-2; - .flex-row { - width: 100%; - display: flex; - border-bottom: 1px solid $secondary-5; - background: white; - &:last-child { - border-bottom: 0; - } - &.header { - background-color: $primary-1; - font-weight: 700; - color: white; - font-size: 1.2rem; - border-bottom: 0; - } - .flex-item { - display: flex; - flex-flow: row nowrap; - flex-grow: 1; - flex-basis: 0; - padding: 0.7em 1.2rem 0.7em 1.2rem; - word-break: break-word; - a { - color: $primary-1; - &:hover { - color: darken($primary-1, 10%); - } - } - } - } -} - -//============================================================================= - -@import 'hub'; - -.button { - // seems to feel unresponsive with almost any transition length - transition: 0.1s; - font-weight: 500; -} - -//TODO: could be global style -.create-object-btn { - background-color: white; - border: 4px dashed #c4cdda; - border-radius: $global-radius; - box-shadow: none; - color: $docker-dark; - line-height: 2.65rem; - margin: rem-calc(20px); - padding: 0.7rem; - font-size: large; - text-align: center; - width: 90%; - cursor: pointer; - &:hover { - background-color: $docker-light; - color: $docker-dark; - } - &:focus { - background-color: $docker-light; - color: $docker-dark; - } - i { - float: right; - } -} - -//TODO: could be global style -.blank-slate { - min-height: 600px; -} - -.page-top-header { - background-color: white; - h3 { - color: #22b8eb; - font-weight: 300; - } -} - -.temp-page { - margin-top: 2rem; - text-align: center; - h1 { - font-size: 24px; - font-weight: 300; - color: lighten(gray, 15%); - } -} - - - select { - background-color: transparent; - border: 1px solid #c4cdda; - transition: border-color 0.15s linear 0s, background 0.15s linear 0s; - outline: 0; - color: #3f5167; - width: rem-calc(100px); - font-size: rem-calc(14px); - font-weight: 300; - border-color: #c4cdda; - border-radius: $global-radius; - } - -form .row textarea.columns { - padding-left: 1rem; -} - -.global-select { - .text { - margin-right: 1rem; - color: $secondary-4; - } -} - -.alert-box { - border-radius: $global-radius; -} - -//TODO: fix in dux -.sk-cube { - background-color: #546473 !important; -} - -/* Pre-move to docker-ux */ -@import 'common/_secondary-top-bar'; -@import 'common/_repository-list-item'; - -// Don't kill me -.mktoForm { - margin-top: 10px; - select#Country { - margin-top: 20px; - } - #Phone { - margin-top: 20px; - } - #accept_eval_terms { - margin-top: 30px; - } -} -.mktoForm div.mktoFormRow { - padding-bottom: 20px; -} -.mktoFieldWrap { - label { - top: -15px; - } -} diff --git a/app/styles/vendor-overrides/rc-tooltip.css b/app/styles/vendor-overrides/rc-tooltip.css deleted file mode 100644 index ab6f60e661..0000000000 --- a/app/styles/vendor-overrides/rc-tooltip.css +++ /dev/null @@ -1,31 +0,0 @@ -.rc-tooltip-inner { - border: 0 none; - box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2); -} -.rc-tooltip-placement-top .rc-tooltip-arrow { - border-left: 0 none; - border-top: 0 none; - background: #fff; - width: 10px; - height: 10px; - transform: rotate(45deg); - border-right: 1px solid #ddd; - border-bottom: 1px solid #ddd; - z-index: 999; -} - -.rc-tooltip-placement-bottom .rc-tooltip-arrow { - background: #fff; - width: 10px; - height: 10px; - transform: rotate(45deg); - border-right: 0 none; - border-bottom: 0 none; - border-left: 1px solid #ddd; - border-top: 1px solid #ddd; - z-index: 999; -} - -.rc-tooltip-inner * { - word-wrap: break-word; -} diff --git a/app/styles/vendor-overrides/react-select.css b/app/styles/vendor-overrides/react-select.css deleted file mode 100644 index dbce7cfccd..0000000000 --- a/app/styles/vendor-overrides/react-select.css +++ /dev/null @@ -1,279 +0,0 @@ -/** - * React Select - * ============ - * Created by Jed Watson and Joss Mackison for KeystoneJS, http://www.keystonejs.com/ - * https://twitter.com/jedwatson https://twitter.com/jossmackison https://twitter.com/keystonejs - * MIT License: https://github.com/keystonejs/react-select - * - * Modified to match our styles -*/ - -.Select { - position: relative; -} -.Select-control { - position: relative; - overflow: hidden; - background-color: #fff; - border: 1px solid #ccc; - border-color: #d9d9d9 #ccc #b3b3b3; - border-radius: 3px; - box-sizing: border-box; - color: #333; - cursor: default; - outline: none; - padding: 8px 52px 8px 10px; -} -.Select-control:hover { - box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06); -} -.is-searchable.is-open > .Select-control { - cursor: text; -} -.is-open > .Select-control { - border-bottom-right-radius: 0; - border-bottom-left-radius: 0; - background: #fff; - border-color: #b3b3b3 #ccc #d9d9d9; -} -.is-open > .Select-control > .Select-arrow { - border-color: transparent transparent #999; - border-width: 0 5px 5px; -} -.is-searchable.is-focused:not(.is-open) > .Select-control { - cursor: text; -} -.is-focused:not(.is-open) > .Select-control { - border-color: #08c #0099e6 #0099e6; - box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 0 5px -1px rgba(0, 136, 204, 0.5); -} -.Select-placeholder { - color: #aaa; - padding: 4px 52px 8px 10px; - position: absolute; - top: 0; - left: 0; - right: -15px; - max-width: 100%; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} -.has-value > .Select-control > .Select-placeholder { - color: #333; -} -.Select-value { - color: #aaa; - padding: 4px 52px 8px 10px; - position: absolute; - top: 0; - left: 0; - right: -15px; - max-width: 100%; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} -.has-value > .Select-control > .Select-value { - color: #333; -} -.Select-input > input { - cursor: default; - background: none transparent; - box-shadow: none; - height: auto; - border: 0 none; - font-family: inherit; - font-size: inherit; - margin: 0; - padding: 0; - outline: none; - display: inline-block; - -webkit-appearance: none; -} -.is-focused .Select-input > input { - cursor: text; -} -.Select-control:not(.is-searchable) > .Select-input { - outline: none; -} -.Select-loading { - -webkit-animation: Select-animation-spin 400ms infinite linear; - -o-animation: Select-animation-spin 400ms infinite linear; - animation: Select-animation-spin 400ms infinite linear; - width: 16px; - height: 16px; - box-sizing: border-box; - border-radius: 50%; - border: 2px solid #ccc; - border-right-color: #333; - display: inline-block; - position: relative; - margin-top: -8px; - position: absolute; - right: 30px; - top: 50%; -} -.has-value > .Select-control > .Select-loading { - right: 46px; -} -.Select-clear { - color: #999; - cursor: pointer; - display: inline-block; - font-size: 12px; - padding: 6px 10px; - position: absolute; - right: 17px; - top: 0; -} -.Select-clear:hover { - color: #c0392b; -} -.Select-clear > span { - font-size: 0.8rem; -} -.Select-arrow-zone { - content: " "; - display: block; - position: absolute; - right: 0; - top: 0; - bottom: 0; - width: 30px; - cursor: pointer; -} -.Select-arrow { - border-color: #999 transparent transparent; - border-style: solid; - border-width: 5px 5px 0; - content: " "; - display: block; - height: 0; - margin-top: -ceil(2.5px); - position: absolute; - right: 10px; - top: 14px; - width: 0; - cursor: pointer; -} -.Select-menu-outer { - border-bottom-right-radius: 3px; - border-bottom-left-radius: 3px; - background-color: #fff; - border: 1px solid #ccc; - border-top-color: #e6e6e6; - box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06); - box-sizing: border-box; - margin-top: -1px; - max-height: 200px; - position: absolute; - top: 100%; - width: 100%; - z-index: 1000; - -webkit-overflow-scrolling: touch; -} -.Select-menu { - max-height: 198px; - overflow-y: auto; -} -.Select-option { - box-sizing: border-box; - color: #666666; - cursor: pointer; - display: block; - padding: 8px 10px; -} -.Select-option:last-child { - border-bottom-right-radius: 3px; - border-bottom-left-radius: 3px; -} -.Select-option.is-focused { - background-color: #f2f9fc; - color: #333; -} -.Select-option.is-disabled { - color: #cccccc; - cursor: not-allowed; -} -.Select-noresults, -.Select-search-prompt, -.Select-searching { - box-sizing: border-box; - color: #999999; - cursor: default; - display: block; - padding: 8px 10px; -} -.Select.is-multi .Select-control { - padding: 2px 52px 2px 3px; -} -.Select.is-multi .Select-input { - vertical-align: middle; - border: 1px solid transparent; - margin: 2px; - padding: 3px 0; -} -.Select-item { - background-color: #f2f9fc; - border-radius: 2px; - border: 1px solid #c9e6f2; - color: #08c; - display: inline-block; - font-size: 0.8rem; - margin: 2px; -} -.Select-item-icon, -.Select-item-label { - display: inline-block; - vertical-align: middle; -} -.Select-item-label { - cursor: default; - border-bottom-right-radius: 2px; - border-top-right-radius: 2px; - padding: 3px 5px; -} -.Select-item-label .Select-item-label__a { - color: #08c; - cursor: pointer; -} -.Select-item-icon { - cursor: pointer; - border-bottom-left-radius: 2px; - border-top-left-radius: 2px; - border-right: 1px solid #c9e6f2; - padding: 2px 5px 4px; -} -.Select-item-icon:hover, -.Select-item-icon:focus { - background-color: #ddeff7; - color: #0077b3; -} -.Select-item-icon:active { - background-color: #c9e6f2; -} -.Select.is-multi.is-disabled .Select-item { - background-color: #f2f2f2; - border: 1px solid #d9d9d9; - color: #888; -} -.Select.is-multi.is-disabled .Select-item-icon { - cursor: not-allowed; - border-right: 1px solid #d9d9d9; -} -.Select.is-multi.is-disabled .Select-item-icon:hover, -.Select.is-multi.is-disabled .Select-item-icon:focus, -.Select.is-multi.is-disabled .Select-item-icon:active { - background-color: #f2f2f2; -} -@keyframes Select-animation-spin { - to { - transform: rotate(1turn); - } -} -@-webkit-keyframes Select-animation-spin { - to { - -webkit-transform: rotate(1turn); - } -} diff --git a/circle.yml b/circle.yml deleted file mode 100644 index fee94207b8..0000000000 --- a/circle.yml +++ /dev/null @@ -1,41 +0,0 @@ -machine: - pre: - - echo 'DOCKER_OPTS="-s btrfs -e lxc -D --userland-proxy=false"' | sudo tee -a /etc/default/docker - - sudo curl -L -o /usr/bin/docker 'https://s3-external-1.amazonaws.com/circle-downloads/docker-1.8.2-circleci-cp-workaround' - - sudo chmod 0755 /usr/bin/docker - node: - version: 4.1.0 - services: - - docker -dependencies: - override: - - mkdir -p ./bin - - pip install fabric==1.8.1 - - pip install pycrypto - - make hub-deps -test: - override: - - docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_AUTH - - docker build -f dockerfiles/milky-way-no-bin -t milky-no-bin ./dockerfiles - - make stage - - mkdir .stage/ - - make copy-stage - - docker run -d --name milky milky-no-bin sleep 15m - - cd .stage/.build-prod && docker cp milky:/opt/hub/modules.tar . && docker build -t bagel/hub-stage . - - make prod - - make base-prod-tag - - make copy-prod - - docker run -d --name milky-2 milky-no-bin sleep 15m - - cd .build-prod && docker cp milky-2:/opt/hub/modules.tar . && docker build -t bagel/hub-prod . - - docker run -de ENV=production -p 3000:3000 --name hub-prod-tester bagel/hub-prod - - sleep 60s - - curl $(docker inspect --format '{{ .NetworkSettings.IPAddress }}' hub-prod-tester):3000 -deployment: - autodeploy: - branch: [master, autodeploy] - owner: docker - commands: - - docker push bagel/hub-prod - - docker push bagel/hub-stage - - chmod 400 ~/.ssh/id_console-demo - - fab -H root@console-demo.docker.com -i ~/.ssh/id_console-demo start_project:email=$DOCKER_EMAIL,user=$DOCKER_USER,auth=$DOCKER_AUTH,beta_password=$BETA_PASSWORD,sha=latest,new_relic_key=$NEW_RELIC_KEY,new_relic_app_name=$NEW_RELIC_APP_NAME diff --git a/compose/Dockerfile b/compose/Dockerfile deleted file mode 100644 index 7b5a3b2465..0000000000 --- a/compose/Dockerfile +++ /dev/null @@ -1,8 +0,0 @@ -FROM docs/base:oss -MAINTAINER Docker Docs - -ENV PROJECT=compose -# To get the git info for this repo -COPY . /src -RUN rm -rf /docs/content/$PROJECT/ -COPY . /docs/content/$PROJECT/ diff --git a/compose/Makefile b/compose/Makefile deleted file mode 100644 index e6629289b5..0000000000 --- a/compose/Makefile +++ /dev/null @@ -1,38 +0,0 @@ -.PHONY: all default docs docs-build docs-shell shell test - -# to allow `make DOCSDIR=1 docs-shell` (to create a bind mount in docs) -DOCS_MOUNT := $(if $(DOCSDIR),-v $(CURDIR):/docs/content/compose) - -# to allow `make DOCSPORT=9000 docs` -DOCSPORT := 8000 - -# Get the IP ADDRESS -DOCKER_IP=$(shell python -c "import urlparse ; print urlparse.urlparse('$(DOCKER_HOST)').hostname or ''") -HUGO_BASE_URL=$(shell test -z "$(DOCKER_IP)" && echo localhost || echo "$(DOCKER_IP)") -HUGO_BIND_IP=0.0.0.0 - -GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD 2>/dev/null) -GIT_BRANCH_CLEAN := $(shell echo $(GIT_BRANCH) | sed -e "s/[^[:alnum:]]/-/g") -DOCKER_DOCS_IMAGE := docker-docs$(if $(GIT_BRANCH_CLEAN),:$(GIT_BRANCH_CLEAN)) - -DOCKER_RUN_DOCS := docker run --rm -it $(DOCS_MOUNT) -e AWS_S3_BUCKET -e NOCACHE - -# for some docs workarounds (see below in "docs-build" target) -GITCOMMIT := $(shell git rev-parse --short HEAD 2>/dev/null) - -default: docs - -docs: docs-build - $(DOCKER_RUN_DOCS) -p $(if $(DOCSPORT),$(DOCSPORT):)8000 -e DOCKERHOST "$(DOCKER_DOCS_IMAGE)" hugo server --port=$(DOCSPORT) --baseUrl=$(HUGO_BASE_URL) --bind=$(HUGO_BIND_IP) --watch - -docs-draft: docs-build - $(DOCKER_RUN_DOCS) -p $(if $(DOCSPORT),$(DOCSPORT):)8000 -e DOCKERHOST "$(DOCKER_DOCS_IMAGE)" hugo server --buildDrafts="true" --port=$(DOCSPORT) --baseUrl=$(HUGO_BASE_URL) --bind=$(HUGO_BIND_IP) - -docs-shell: docs-build - $(DOCKER_RUN_DOCS) -p $(if $(DOCSPORT),$(DOCSPORT):)8000 "$(DOCKER_DOCS_IMAGE)" bash - -test: docs-build - $(DOCKER_RUN_DOCS) "$(DOCKER_DOCS_IMAGE)" - -docs-build: - docker build -t "$(DOCKER_DOCS_IMAGE)" . diff --git a/compose/README.md b/compose/README.md deleted file mode 100644 index e60fa48cd5..0000000000 --- a/compose/README.md +++ /dev/null @@ -1,86 +0,0 @@ - - -# Contributing to the Docker Compose documentation - -The documentation in this directory is part of the [https://docs.docker.com](https://docs.docker.com) website. Docker uses [the Hugo static generator](http://gohugo.io/overview/introduction/) to convert project Markdown files to a static HTML site. - -You don't need to be a Hugo expert to contribute to the compose documentation. If you are familiar with Markdown, you can modify the content in the `docs` files. - -If you want to add a new file or change the location of the document in the menu, you do need to know a little more. - -## Documentation contributing workflow - -1. Edit a Markdown file in the tree. - -2. Save your changes. - -3. Make sure you are in the `docs` subdirectory. - -4. Build the documentation. - - $ make docs - ---> ffcf3f6c4e97 - Removing intermediate container a676414185e8 - Successfully built ffcf3f6c4e97 - docker run --rm -it -e AWS_S3_BUCKET -e NOCACHE -p 8000:8000 -e DOCKERHOST "docs-base:test-tooling" hugo server --port=8000 --baseUrl=192.168.59.103 --bind=0.0.0.0 - ERROR: 2015/06/13 MenuEntry's .Url is deprecated and will be removed in Hugo 0.15. Use .URL instead. - 0 of 4 drafts rendered - 0 future content - 12 pages created - 0 paginator pages created - 0 tags created - 0 categories created - in 55 ms - Serving pages from /docs/public - Web Server is available at http://0.0.0.0:8000/ - Press Ctrl+C to stop - -5. Open the available server in your browser. - - The documentation server has the complete menu but only the Docker Compose - documentation resolves. You can't access the other project docs from this - localized build. - -## Tips on Hugo metadata and menu positioning - -The top of each Docker Compose documentation file contains TOML metadata. The metadata is commented out to prevent it from appearing in GitHub. - - - -The metadata alone has this structure: - - +++ - title = "Extending services in Compose" - description = "How to use Docker Compose's extends keyword to share configuration between files and projects" - keywords = ["fig, composition, compose, docker, orchestration, documentation, docs"] - [menu.main] - parent="workw_compose" - weight=2 - +++ - -The `[menu.main]` section refers to navigation defined [in the main Docker menu](https://github.com/docker/docs-base/blob/hugo/config.toml). This metadata says *add a menu item called* Extending services in Compose *to the menu with the* `smn_workdw_compose` *identifier*. If you locate the menu in the configuration, you'll find *Create multi-container applications* is the menu title. - -You can move an article in the tree by specifying a new parent. You can shift the location of the item by changing its weight. Higher numbers are heavier and shift the item to the bottom of menu. Low or no numbers shift it up. - - -## Other key documentation repositories - -The `docker/docs-base` repository contains [the Hugo theme and menu configuration](https://github.com/docker/docs-base). If you open the `Dockerfile` you'll see the `make docs` relies on this as a base image for building the Compose documentation. - -The `docker/docs.docker.com` repository contains [build system for building the Docker documentation site](https://github.com/docker/docs.docker.com). Fork this repository to build the entire documentation site. diff --git a/compose/bundles.md b/compose/bundles.md deleted file mode 100644 index 096c9ec3e2..0000000000 --- a/compose/bundles.md +++ /dev/null @@ -1,209 +0,0 @@ - - - -# Docker Stacks and Distributed Application Bundles (experimental) - -> **Note**: This is a copy of the [Docker Stacks and Distributed Application -> Bundles](https://github.com/docker/docker/blob/v1.12.0-rc4/experimental/docker-stacks-and-bundles.md) -> document in the [docker/docker repo](https://github.com/docker/docker). - -## Overview - -Docker Stacks and Distributed Application Bundles are experimental features -introduced in Docker 1.12 and Docker Compose 1.8, alongside the concept of -swarm mode, and Nodes and Services in the Engine API. - -A Dockerfile can be built into an image, and containers can be created from -that image. Similarly, a docker-compose.yml can be built into a **distributed -application bundle**, and **stacks** can be created from that bundle. In that -sense, the bundle is a multi-services distributable image format. - -As of Docker 1.12 and Compose 1.8, the features are experimental. Neither -Docker Engine nor the Docker Registry support distribution of bundles. - -## Producing a bundle - -The easiest way to produce a bundle is to generate it using `docker-compose` -from an existing `docker-compose.yml`. Of course, that's just *one* possible way -to proceed, in the same way that `docker build` isn't the only way to produce a -Docker image. - -From `docker-compose`: - -```bash -$ docker-compose bundle -WARNING: Unsupported key 'network_mode' in services.nsqd - ignoring -WARNING: Unsupported key 'links' in services.nsqd - ignoring -WARNING: Unsupported key 'volumes' in services.nsqd - ignoring -[...] -Wrote bundle to vossibility-stack.dab -``` - -## Creating a stack from a bundle - -> **Note**: Because support for stacks and bundles is in the experimental stage, -> you need to install an experimental build of Docker Engine to use it. -> -> If you're on Mac or Windows, download the “Beta channel” version of -> [Docker for Mac](https://docs.docker.com/docker-for-mac/) or -> [Docker for Windows](https://docs.docker.com/docker-for-windows/) to install -> it. If you're on Linux, follow the instructions in the -> [experimental build README](https://github.com/docker/docker/blob/master/experimental/README.md). - -A stack is created using the `docker deploy` command: - -```bash -# docker deploy --help - -Usage: docker deploy [OPTIONS] STACK - -Create and update a stack - -Options: - --file string Path to a Distributed Application Bundle file (Default: STACK.dab) - --help Print usage - --with-registry-auth Send registry authentication details to Swarm agents -``` - -Let's deploy the stack created before: - -```bash -# docker deploy vossibility-stack -Loading bundle from vossibility-stack.dab -Creating service vossibility-stack_elasticsearch -Creating service vossibility-stack_kibana -Creating service vossibility-stack_logstash -Creating service vossibility-stack_lookupd -Creating service vossibility-stack_nsqd -Creating service vossibility-stack_vossibility-collector -``` - -We can verify that services were correctly created: - -```bash -# docker service ls -ID NAME REPLICAS IMAGE -COMMAND -29bv0vnlm903 vossibility-stack_lookupd 1 nsqio/nsq@sha256:eeba05599f31eba418e96e71e0984c3dc96963ceb66924dd37a47bf7ce18a662 /nsqlookupd -4awt47624qwh vossibility-stack_nsqd 1 nsqio/nsq@sha256:eeba05599f31eba418e96e71e0984c3dc96963ceb66924dd37a47bf7ce18a662 /nsqd --data-path=/data --lookupd-tcp-address=lookupd:4160 -4tjx9biia6fs vossibility-stack_elasticsearch 1 elasticsearch@sha256:12ac7c6af55d001f71800b83ba91a04f716e58d82e748fa6e5a7359eed2301aa -7563uuzr9eys vossibility-stack_kibana 1 kibana@sha256:6995a2d25709a62694a937b8a529ff36da92ebee74bafd7bf00e6caf6db2eb03 -9gc5m4met4he vossibility-stack_logstash 1 logstash@sha256:2dc8bddd1bb4a5a34e8ebaf73749f6413c101b2edef6617f2f7713926d2141fe logstash -f /etc/logstash/conf.d/logstash.conf -axqh55ipl40h vossibility-stack_vossibility-collector 1 icecrime/vossibility-collector@sha256:f03f2977203ba6253988c18d04061c5ec7aab46bca9dfd89a9a1fa4500989fba --config /config/config.toml --debug -``` - -## Managing stacks - -Stacks are managed using the `docker stack` command: - -```bash -# docker stack --help - -Usage: docker stack COMMAND - -Manage Docker stacks - -Options: - --help Print usage - -Commands: - config Print the stack configuration - deploy Create and update a stack - rm Remove the stack - services List the services in the stack - tasks List the tasks in the stack - -Run 'docker stack COMMAND --help' for more information on a command. -``` - -## Bundle file format - -Distributed application bundles are described in a JSON format. When bundles -are persisted as files, the file extension is `.dab`. - -A bundle has two top-level fields: `version` and `services`. The version used -by Docker 1.12 tools is `0.1`. - -`services` in the bundle are the services that comprise the app. They -correspond to the new `Service` object introduced in the 1.12 Docker Engine API. - -A service has the following fields: - -
    -
    - Image (required) string -
    -
    - The image that the service will run. Docker images should be referenced - with full content hash to fully specify the deployment artifact for the - service. Example: - postgres@sha256:e0a230a9f5b4e1b8b03bb3e8cf7322b0e42b7838c5c87f4545edb48f5eb8f077 -
    -
    - Command []string -
    -
    - Command to run in service containers. -
    -
    - Args []string -
    -
    - Arguments passed to the service containers. -
    -
    - Env []string -
    -
    - Environment variables. -
    -
    - Labels map[string]string -
    -
    - Labels used for setting meta data on services. -
    -
    - Ports []Port -
    -
    - Service ports (composed of Port (int) and - Protocol (string). A service description can - only specify the container port to be exposed. These ports can be - mapped on runtime hosts at the operator's discretion. -
    - -
    - WorkingDir string -
    -
    - Working directory inside the service containers. -
    - -
    - User string -
    -
    - Username or UID (format: <name|uid>[:<group|gid>]). -
    - -
    - Networks []string -
    -
    - Networks that the service containers should be connected to. An entity - deploying a bundle should create networks as needed. -
    -
    - -> **Note:** Some configuration options are not yet supported in the DAB format, -> including volume mounts. diff --git a/compose/completion.md b/compose/completion.md deleted file mode 100644 index 2076d512c3..0000000000 --- a/compose/completion.md +++ /dev/null @@ -1,68 +0,0 @@ - - -# Command-line Completion - -Compose comes with [command completion](http://en.wikipedia.org/wiki/Command-line_completion) -for the bash and zsh shell. - -## Installing Command Completion - -### Bash - -Make sure bash completion is installed. If you use a current Linux in a non-minimal installation, bash completion should be available. -On a Mac, install with `brew install bash-completion` - -Place the completion script in `/etc/bash_completion.d/` (`/usr/local/etc/bash_completion.d/` on a Mac), using e.g. - - curl -L https://raw.githubusercontent.com/docker/compose/$(docker-compose version --short)/contrib/completion/bash/docker-compose > /etc/bash_completion.d/docker-compose - -Completion will be available upon next login. - -### Zsh - -Place the completion script in your `/path/to/zsh/completion`, using e.g. `~/.zsh/completion/` - - mkdir -p ~/.zsh/completion - curl -L https://raw.githubusercontent.com/docker/compose/$(docker-compose version --short)/contrib/completion/zsh/_docker-compose > ~/.zsh/completion/_docker-compose - -Include the directory in your `$fpath`, e.g. by adding in `~/.zshrc` - - fpath=(~/.zsh/completion $fpath) - -Make sure `compinit` is loaded or do it by adding in `~/.zshrc` - - autoload -Uz compinit && compinit -i - -Then reload your shell - - exec $SHELL -l - -## Available completions - -Depending on what you typed on the command line so far, it will complete - - - available docker-compose commands - - options that are available for a particular command - - service names that make sense in a given context (e.g. services with running or stopped instances or services based on images vs. services based on Dockerfiles). For `docker-compose scale`, completed service names will automatically have "=" appended. - - arguments for selected options, e.g. `docker-compose kill -s` will complete some signals like SIGHUP and SIGUSR1. - -Enjoy working with Compose faster and with less typos! - -## Compose documentation - -- [User guide](index.md) -- [Installing Compose](install.md) -- [Get started with Django](django.md) -- [Get started with Rails](rails.md) -- [Get started with WordPress](wordpress.md) -- [Command line reference](./reference/index.md) -- [Compose file reference](compose-file.md) diff --git a/compose/compose-file.md b/compose/compose-file.md deleted file mode 100644 index 853a886e78..0000000000 --- a/compose/compose-file.md +++ /dev/null @@ -1,1170 +0,0 @@ - - - -# Compose file reference - -The Compose file is a [YAML](http://yaml.org/) file defining -[services](#service-configuration-reference), -[networks](#network-configuration-reference) and -[volumes](#volume-configuration-reference). -The default path for a Compose file is `./docker-compose.yml`. - -A service definition contains configuration which will be applied to each -container started for that service, much like passing command-line parameters to -`docker run`. Likewise, network and volume definitions are analogous to -`docker network create` and `docker volume create`. - -As with `docker run`, options specified in the Dockerfile (e.g., `CMD`, -`EXPOSE`, `VOLUME`, `ENV`) are respected by default - you don't need to -specify them again in `docker-compose.yml`. - -You can use environment variables in configuration values with a Bash-like -`${VARIABLE}` syntax - see [variable substitution](#variable-substitution) for -full details. - - -## Service configuration reference - -> **Note:** There are two versions of the Compose file format – version 1 (the -> legacy format, which does not support volumes or networks) and version 2 (the -> most up-to-date). For more information, see the [Versioning](#versioning) -> section. - -This section contains a list of all configuration options supported by a service -definition. - -### build - -Configuration options that are applied at build time. - -`build` can be specified either as a string containing a path to the build -context, or an object with the path specified under [context](#context) and -optionally [dockerfile](#dockerfile) and [args](#args). - - build: ./dir - - build: - context: ./dir - dockerfile: Dockerfile-alternate - args: - buildno: 1 - -If you specify `image` as well as `build`, then Compose names the built image -with the `webapp` and optional `tag` specified in `image`: - - build: ./dir - image: webapp:tag - -This will result in an image named `webapp` and tagged `tag`, built from `./dir`. - -> **Note**: In the [version 1 file format](#version-1), `build` is different in -> two ways: -> -> - Only the string form (`build: .`) is allowed - not the object form. -> - Using `build` together with `image` is not allowed. Attempting to do so -> results in an error. - -#### context - -> [Version 2 file format](#version-2) only. In version 1, just use -> [build](#build). - -Either a path to a directory containing a Dockerfile, or a url to a git repository. - -When the value supplied is a relative path, it is interpreted as relative to the -location of the Compose file. This directory is also the build context that is -sent to the Docker daemon. - -Compose will build and tag it with a generated name, and use that image thereafter. - - build: - context: ./dir - -#### dockerfile - -Alternate Dockerfile. - -Compose will use an alternate file to build with. A build path must also be -specified. - - build: - context: . - dockerfile: Dockerfile-alternate - -> **Note**: In the [version 1 file format](#version-1), `dockerfile` is -> different in two ways: - - * It appears alongside `build`, not as a sub-option: - - build: . - dockerfile: Dockerfile-alternate - - * Using `dockerfile` together with `image` is not allowed. Attempting to do so results in an error. - -#### args - -> [Version 2 file format](#version-2) only. - -Add build arguments, which are environment variables accessible only during the -build process. - -First, specify the arguments in your Dockerfile: - - ARG buildno - ARG password - - RUN echo "Build number: $buildno" - RUN script-requiring-password.sh "$password" - -Then specify the arguments under the `build` key. You can pass either a mapping -or a list: - - build: - context: . - args: - buildno: 1 - password: secret - - build: - context: . - args: - - buildno=1 - - password=secret - -You can omit the value when specifying a build argument, in which case its value -at build time is the value in the environment where Compose is running. - - args: - - buildno - - password - -> **Note**: YAML boolean values (`true`, `false`, `yes`, `no`, `on`, `off`) must -> be enclosed in quotes, so that the parser interprets them as strings. - -### cap_add, cap_drop - -Add or drop container capabilities. -See `man 7 capabilities` for a full list. - - cap_add: - - ALL - - cap_drop: - - NET_ADMIN - - SYS_ADMIN - -### command - -Override the default command. - - command: bundle exec thin -p 3000 - -The command can also be a list, in a manner similar to [dockerfile](https://docs.docker.com/engine/reference/builder/#cmd): - - command: [bundle, exec, thin, -p, 3000] - -### cgroup_parent - -Specify an optional parent cgroup for the container. - - cgroup_parent: m-executor-abcd - -### container_name - -Specify a custom container name, rather than a generated default name. - - container_name: my-web-container - -Because Docker container names must be unique, you cannot scale a service -beyond 1 container if you have specified a custom name. Attempting to do so -results in an error. - -### devices - -List of device mappings. Uses the same format as the `--device` docker -client create option. - - devices: - - "/dev/ttyUSB0:/dev/ttyUSB0" - -### depends_on - -Express dependency between services, which has two effects: - -- `docker-compose up` will start services in dependency order. In the following - example, `db` and `redis` will be started before `web`. - -- `docker-compose up SERVICE` will automatically include `SERVICE`'s - dependencies. In the following example, `docker-compose up web` will also - create and start `db` and `redis`. - -Simple example: - - version: '2' - services: - web: - build: . - depends_on: - - db - - redis - redis: - image: redis - db: - image: postgres - -> **Note:** `depends_on` will not wait for `db` and `redis` to be "ready" before -> starting `web` - only until they have been started. If you need to wait -> for a service to be ready, see [Controlling startup order](startup-order.md) -> for more on this problem and strategies for solving it. - -### dns - -Custom DNS servers. Can be a single value or a list. - - dns: 8.8.8.8 - dns: - - 8.8.8.8 - - 9.9.9.9 - -### dns_search - -Custom DNS search domains. Can be a single value or a list. - - dns_search: example.com - dns_search: - - dc1.example.com - - dc2.example.com - -### tmpfs - -> [Version 2 file format](#version-2) only. - -Mount a temporary file system inside the container. Can be a single value or a list. - - tmpfs: /run - tmpfs: - - /run - - /tmp - -### entrypoint - -Override the default entrypoint. - - entrypoint: /code/entrypoint.sh - -The entrypoint can also be a list, in a manner similar to [dockerfile](https://docs.docker.com/engine/reference/builder/#entrypoint): - - entrypoint: - - php - - -d - - zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20100525/xdebug.so - - -d - - memory_limit=-1 - - vendor/bin/phpunit - - -### env_file - -Add environment variables from a file. Can be a single value or a list. - -If you have specified a Compose file with `docker-compose -f FILE`, paths in -`env_file` are relative to the directory that file is in. - -Environment variables specified in `environment` override these values. - - env_file: .env - - env_file: - - ./common.env - - ./apps/web.env - - /opt/secrets.env - -Compose expects each line in an env file to be in `VAR=VAL` format. Lines -beginning with `#` (i.e. comments) are ignored, as are blank lines. - - # Set Rails/Rack environment - RACK_ENV=development - -> **Note:** If your service specifies a [build](#build) option, variables -> defined in environment files will _not_ be automatically visible during the -> build. Use the [args](#args) sub-option of `build` to define build-time -> environment variables. - -### environment - -Add environment variables. You can use either an array or a dictionary. Any -boolean values; true, false, yes no, need to be enclosed in quotes to ensure -they are not converted to True or False by the YML parser. - -Environment variables with only a key are resolved to their values on the -machine Compose is running on, which can be helpful for secret or host-specific values. - - environment: - RACK_ENV: development - SHOW: 'true' - SESSION_SECRET: - - environment: - - RACK_ENV=development - - SHOW=true - - SESSION_SECRET - -> **Note:** If your service specifies a [build](#build) option, variables -> defined in `environment` will _not_ be automatically visible during the -> build. Use the [args](#args) sub-option of `build` to define build-time -> environment variables. - -### expose - -Expose ports without publishing them to the host machine - they'll only be -accessible to linked services. Only the internal port can be specified. - - expose: - - "3000" - - "8000" - -### extends - -Extend another service, in the current file or another, optionally overriding -configuration. - -You can use `extends` on any service together with other configuration keys. -The `extends` value must be a dictionary defined with a required `service` -and an optional `file` key. - - extends: - file: common.yml - service: webapp - -The `service` the name of the service being extended, for example -`web` or `database`. The `file` is the location of a Compose configuration -file defining that service. - -If you omit the `file` Compose looks for the service configuration in the -current file. The `file` value can be an absolute or relative path. If you -specify a relative path, Compose treats it as relative to the location of the -current file. - -You can extend a service that itself extends another. You can extend -indefinitely. Compose does not support circular references and `docker-compose` -returns an error if it encounters one. - -For more on `extends`, see the -[the extends documentation](extends.md#extending-services). - -### external_links - -Link to containers started outside this `docker-compose.yml` or even outside -of Compose, especially for containers that provide shared or common services. -`external_links` follow semantics similar to `links` when specifying both the -container name and the link alias (`CONTAINER:ALIAS`). - - external_links: - - redis_1 - - project_db_1:mysql - - project_db_1:postgresql - -> **Note:** If you're using the [version 2 file format](#version-2), the -> externally-created containers must be connected to at least one of the same -> networks as the service which is linking to them. - -### extra_hosts - -Add hostname mappings. Use the same values as the docker client `--add-host` parameter. - - extra_hosts: - - "somehost:162.242.195.82" - - "otherhost:50.31.209.229" - -An entry with the ip address and hostname will be created in `/etc/hosts` inside containers for this service, e.g: - - 162.242.195.82 somehost - 50.31.209.229 otherhost - -### image - -Specify the image to start the container from. Can either be a repository/tag or -a partial image ID. - - image: redis - image: ubuntu:14.04 - image: tutum/influxdb - image: example-registry.com:4000/postgresql - image: a4bc65fd - -If the image does not exist, Compose attempts to pull it, unless you have also -specified [build](#build), in which case it builds it using the specified -options and tags it with the specified tag. - -> **Note**: In the [version 1 file format](#version-1), using `build` together -> with `image` is not allowed. Attempting to do so results in an error. - -### labels - -Add metadata to containers using [Docker labels](https://docs.docker.com/engine/userguide/labels-custom-metadata/). You can use either an array or a dictionary. - -It's recommended that you use reverse-DNS notation to prevent your labels from conflicting with those used by other software. - - labels: - com.example.description: "Accounting webapp" - com.example.department: "Finance" - com.example.label-with-empty-value: "" - - labels: - - "com.example.description=Accounting webapp" - - "com.example.department=Finance" - - "com.example.label-with-empty-value" - -### links - -Link to containers in another service. Either specify both the service name and -a link alias (`SERVICE:ALIAS`), or just the service name. - - web: - links: - - db - - db:database - - redis - -Containers for the linked service will be reachable at a hostname identical to -the alias, or the service name if no alias was specified. - -Links also express dependency between services in the same way as -[depends_on](#depends-on), so they determine the order of service startup. - -> **Note:** If you define both links and [networks](#networks), services with -> links between them must share at least one network in common in order to -> communicate. - -### logging - -> [Version 2 file format](#version-2) only. In version 1, use -> [log_driver](#log_driver) and [log_opt](#log_opt). - -Logging configuration for the service. - - logging: - driver: syslog - options: - syslog-address: "tcp://192.168.0.42:123" - -The `driver` name specifies a logging driver for the service's -containers, as with the ``--log-driver`` option for docker run -([documented here](https://docs.docker.com/engine/reference/logging/overview/)). - -The default value is json-file. - - driver: "json-file" - driver: "syslog" - driver: "none" - -> **Note:** Only the `json-file` driver makes the logs available directly from -> `docker-compose up` and `docker-compose logs`. Using any other driver will not -> print any logs. - -Specify logging options for the logging driver with the ``options`` key, as with the ``--log-opt`` option for `docker run`. - -Logging options are key-value pairs. An example of `syslog` options: - - driver: "syslog" - options: - syslog-address: "tcp://192.168.0.42:123" - -### log_driver - -> [Version 1 file format](#version-1) only. In version 2, use -> [logging](#logging). - -Specify a log driver. The default is `json-file`. - - log_driver: syslog - -### log_opt - -> [Version 1 file format](#version-1) only. In version 2, use -> [logging](#logging). - -Specify logging options as key-value pairs. An example of `syslog` options: - - log_opt: - syslog-address: "tcp://192.168.0.42:123" - -### net - -> [Version 1 file format](#version-1) only. In version 2, use -> [network_mode](#network_mode). - -Network mode. Use the same values as the docker client `--net` parameter. -The `container:...` form can take a service name instead of a container name or -id. - - net: "bridge" - net: "host" - net: "none" - net: "container:[service name or container name/id]" - -### network_mode - -> [Version 2 file format](#version-2) only. In version 1, use [net](#net). - -Network mode. Use the same values as the docker client `--net` parameter, plus -the special form `service:[service name]`. - - network_mode: "bridge" - network_mode: "host" - network_mode: "none" - network_mode: "service:[service name]" - network_mode: "container:[container name/id]" - -### networks - -> [Version 2 file format](#version-2) only. In version 1, use [net](#net). - -Networks to join, referencing entries under the -[top-level `networks` key](#network-configuration-reference). - - services: - some-service: - networks: - - some-network - - other-network - -#### aliases - -Aliases (alternative hostnames) for this service on the network. Other containers on the same network can use either the service name or this alias to connect to one of the service's containers. - -Since `aliases` is network-scoped, the same service can have different aliases on different networks. - -> **Note**: A network-wide alias can be shared by multiple containers, and even by multiple services. If it is, then exactly which container the name will resolve to is not guaranteed. - -The general format is shown here. - - services: - some-service: - networks: - some-network: - aliases: - - alias1 - - alias3 - other-network: - aliases: - - alias2 - -In the example below, three services are provided (`web`, `worker`, and `db`), along with two networks (`new` and `legacy`). The `db` service is reachable at the hostname `db` or `database` on the `new` network, and at `db` or `mysql` on the `legacy` network. - - version: '2' - - services: - web: - build: ./web - networks: - - new - - worker: - build: ./worker - networks: - - legacy - - db: - image: mysql - networks: - new: - aliases: - - database - legacy: - aliases: - - mysql - - networks: - new: - legacy: - -#### ipv4_address, ipv6_address - -Specify a static IP address for containers for this service when joining the network. - -The corresponding network configuration in the [top-level networks section](#network-configuration-reference) must have an `ipam` block with subnet and gateway configurations covering each static address. If IPv6 addressing is desired, the `com.docker.network.enable_ipv6` driver option must be set to `true`. - -An example: - - version: '2' - - services: - app: - image: busybox - command: ifconfig - networks: - app_net: - ipv4_address: 172.16.238.10 - ipv6_address: 2001:3984:3989::10 - - networks: - app_net: - driver: bridge - driver_opts: - com.docker.network.enable_ipv6: "true" - ipam: - driver: default - config: - - subnet: 172.16.238.0/24 - gateway: 172.16.238.1 - - subnet: 2001:3984:3989::/64 - gateway: 2001:3984:3989::1 - -### pid - - pid: "host" - -Sets the PID mode to the host PID mode. This turns on sharing between -container and the host operating system the PID address space. Containers -launched with this flag will be able to access and manipulate other -containers in the bare-metal machine's namespace and vise-versa. - -### ports - -Expose ports. Either specify both ports (`HOST:CONTAINER`), or just the container -port (a random host port will be chosen). - -> **Note:** When mapping ports in the `HOST:CONTAINER` format, you may experience -> erroneous results when using a container port lower than 60, because YAML will -> parse numbers in the format `xx:yy` as sexagesimal (base 60). For this reason, -> we recommend always explicitly specifying your port mappings as strings. - - ports: - - "3000" - - "3000-3005" - - "8000:8000" - - "9090-9091:8080-8081" - - "49100:22" - - "127.0.0.1:8001:8001" - - "127.0.0.1:5000-5010:5000-5010" - -### security_opt - -Override the default labeling scheme for each container. - - security_opt: - - label:user:USER - - label:role:ROLE - -### stop_signal - -Sets an alternative signal to stop the container. By default `stop` uses -SIGTERM. Setting an alternative signal using `stop_signal` will cause -`stop` to send that signal instead. - - stop_signal: SIGUSR1 - -### ulimits - -Override the default ulimits for a container. You can either specify a single -limit as an integer or soft/hard limits as a mapping. - - - ulimits: - nproc: 65535 - nofile: - soft: 20000 - hard: 40000 - -### volumes, volume\_driver - -Mount paths or named volumes, optionally specifying a path on the host machine -(`HOST:CONTAINER`), or an access mode (`HOST:CONTAINER:ro`). -For [version 2 files](#version-2), named volumes need to be specified with the -[top-level `volumes` key](#volume-configuration-reference). -When using [version 1](#version-1), the Docker Engine will create the named -volume automatically if it doesn't exist. - -You can mount a relative path on the host, which will expand relative to -the directory of the Compose configuration file being used. Relative paths -should always begin with `.` or `..`. - - volumes: - # Just specify a path and let the Engine create a volume - - /var/lib/mysql - - # Specify an absolute path mapping - - /opt/data:/var/lib/mysql - - # Path on the host, relative to the Compose file - - ./cache:/tmp/cache - - # User-relative path - - ~/configs:/etc/configs/:ro - - # Named volume - - datavolume:/var/lib/mysql - -If you do not use a host path, you may specify a `volume_driver`. - - volume_driver: mydriver - -Note that for [version 2 files](#version-2), this driver -will not apply to named volumes (you should use the `driver` option when -[declaring the volume](#volume-configuration-reference) instead). -For [version 1](#version-1), both named volumes and container volumes will -use the specified driver. - -> Note: No path expansion will be done if you have also specified a -> `volume_driver`. - -See [Docker Volumes](https://docs.docker.com/engine/userguide/dockervolumes/) and -[Volume Plugins](https://docs.docker.com/engine/extend/plugins_volume/) for more -information. - -### volumes_from - -Mount all of the volumes from another service or container, optionally -specifying read-only access (``ro``) or read-write (``rw``). If no access level is specified, -then read-write will be used. - - volumes_from: - - service_name - - service_name:ro - - container:container_name - - container:container_name:rw - -> **Note:** The `container:...` formats are only supported in the -> [version 2 file format](#version-2). In [version 1](#version-1), you can use -> container names without marking them as such: -> -> - service_name -> - service_name:ro -> - container_name -> - container_name:rw - -### cpu\_shares, cpu\_quota, cpuset, domainname, hostname, ipc, mac\_address, mem\_limit, memswap\_limit, privileged, read\_only, restart, shm\_size, stdin\_open, tty, user, working\_dir - -Each of these is a single value, analogous to its -[docker run](https://docs.docker.com/engine/reference/run/) counterpart. - - cpu_shares: 73 - cpu_quota: 50000 - cpuset: 0,1 - - user: postgresql - working_dir: /code - - domainname: foo.com - hostname: foo - ipc: host - mac_address: 02:42:ac:11:65:43 - - mem_limit: 1000000000 - memswap_limit: 2000000000 - privileged: true - - restart: always - - read_only: true - shm_size: 64M - stdin_open: true - tty: true - - -## Volume configuration reference - -While it is possible to declare volumes on the fly as part of the service -declaration, this section allows you to create named volumes that can be -reused across multiple services (without relying on `volumes_from`), and are -easily retrieved and inspected using the docker command line or API. -See the [docker volume](https://docs.docker.com/engine/reference/commandline/volume_create/) -subcommand documentation for more information. - -### driver - -Specify which volume driver should be used for this volume. Defaults to -`local`. The Docker Engine will return an error if the driver is not available. - - driver: foobar - -### driver_opts - -Specify a list of options as key-value pairs to pass to the driver for this -volume. Those options are driver-dependent - consult the driver's -documentation for more information. Optional. - - driver_opts: - foo: "bar" - baz: 1 - -### external - -If set to `true`, specifies that this volume has been created outside of -Compose. `docker-compose up` will not attempt to create it, and will raise -an error if it doesn't exist. - -`external` cannot be used in conjunction with other volume configuration keys -(`driver`, `driver_opts`). - -In the example below, instead of attemping to create a volume called -`[projectname]_data`, Compose will look for an existing volume simply -called `data` and mount it into the `db` service's containers. - - version: '2' - - services: - db: - image: postgres - volumes: - - data:/var/lib/postgresql/data - - volumes: - data: - external: true - -You can also specify the name of the volume separately from the name used to -refer to it within the Compose file: - - volumes: - data: - external: - name: actual-name-of-volume - - -## Network configuration reference - -The top-level `networks` key lets you specify networks to be created. For a full -explanation of Compose's use of Docker networking features, see the -[Networking guide](networking.md). - -### driver - -Specify which driver should be used for this network. - -The default driver depends on how the Docker Engine you're using is configured, -but in most instances it will be `bridge` on a single host and `overlay` on a -Swarm. - -The Docker Engine will return an error if the driver is not available. - - driver: overlay - -### driver_opts - -Specify a list of options as key-value pairs to pass to the driver for this -network. Those options are driver-dependent - consult the driver's -documentation for more information. Optional. - - driver_opts: - foo: "bar" - baz: 1 - -### ipam - -Specify custom IPAM config. This is an object with several properties, each of -which is optional: - -- `driver`: Custom IPAM driver, instead of the default. -- `config`: A list with zero or more config blocks, each containing any of - the following keys: - - `subnet`: Subnet in CIDR format that represents a network segment - - `ip_range`: Range of IPs from which to allocate container IPs - - `gateway`: IPv4 or IPv6 gateway for the master subnet - - `aux_addresses`: Auxiliary IPv4 or IPv6 addresses used by Network driver, - as a mapping from hostname to IP - -A full example: - - ipam: - driver: default - config: - - subnet: 172.28.0.0/16 - ip_range: 172.28.5.0/24 - gateway: 172.28.5.254 - aux_addresses: - host1: 172.28.1.5 - host2: 172.28.1.6 - host3: 172.28.1.7 - -### external - -If set to `true`, specifies that this network has been created outside of -Compose. `docker-compose up` will not attempt to create it, and will raise -an error if it doesn't exist. - -`external` cannot be used in conjunction with other network configuration keys -(`driver`, `driver_opts`, `ipam`). - -In the example below, `proxy` is the gateway to the outside world. Instead of -attemping to create a network called `[projectname]_outside`, Compose will -look for an existing network simply called `outside` and connect the `proxy` -service's containers to it. - - version: '2' - - services: - proxy: - build: ./proxy - networks: - - outside - - default - app: - build: ./app - networks: - - default - - networks: - outside: - external: true - -You can also specify the name of the network separately from the name used to -refer to it within the Compose file: - - networks: - outside: - external: - name: actual-name-of-network - - -## Versioning - -There are two versions of the Compose file format: - -- Version 1, the legacy format. This is specified by omitting a `version` key at - the root of the YAML. -- Version 2, the recommended format. This is specified with a `version: '2'` entry - at the root of the YAML. - -To move your project from version 1 to 2, see the [Upgrading](#upgrading) -section. - -> **Note:** If you're using -> [multiple Compose files](extends.md#different-environments) or -> [extending services](extends.md#extending-services), each file must be of the -> same version - you cannot mix version 1 and 2 in a single project. - -Several things differ depending on which version you use: - -- The structure and permitted configuration keys -- The minimum Docker Engine version you must be running -- Compose's behaviour with regards to networking - -These differences are explained below. - - -### Version 1 - -Compose files that do not declare a version are considered "version 1". In -those files, all the [services](#service-configuration-reference) are declared -at the root of the document. - -Version 1 is supported by **Compose up to 1.6.x**. It will be deprecated in a -future Compose release. - -Version 1 files cannot declare named -[volumes](#volume-configuration-reference), [networks](networking.md) or -[build arguments](#args). - -Example: - - web: - build: . - ports: - - "5000:5000" - volumes: - - .:/code - links: - - redis - redis: - image: redis - - -### Version 2 - -Compose files using the version 2 syntax must indicate the version number at -the root of the document. All [services](#service-configuration-reference) -must be declared under the `services` key. - -Version 2 files are supported by **Compose 1.6.0+** and require a Docker Engine -of version **1.10.0+**. - -Named [volumes](#volume-configuration-reference) can be declared under the -`volumes` key, and [networks](#network-configuration-reference) can be declared -under the `networks` key. - -Simple example: - - version: '2' - services: - web: - build: . - ports: - - "5000:5000" - volumes: - - .:/code - redis: - image: redis - -A more extended example, defining volumes and networks: - - version: '2' - services: - web: - build: . - ports: - - "5000:5000" - volumes: - - .:/code - networks: - - front-tier - - back-tier - redis: - image: redis - volumes: - - redis-data:/var/lib/redis - networks: - - back-tier - volumes: - redis-data: - driver: local - networks: - front-tier: - driver: bridge - back-tier: - driver: bridge - - -### Upgrading - -In the majority of cases, moving from version 1 to 2 is a very simple process: - -1. Indent the whole file by one level and put a `services:` key at the top. -2. Add a `version: '2'` line at the top of the file. - -It's more complicated if you're using particular configuration features: - -- `dockerfile`: This now lives under the `build` key: - - build: - context: . - dockerfile: Dockerfile-alternate - -- `log_driver`, `log_opt`: These now live under the `logging` key: - - logging: - driver: syslog - options: - syslog-address: "tcp://192.168.0.42:123" - -- `links` with environment variables: As documented in the - [environment variables reference](link-env-deprecated.md), environment variables - created by - links have been deprecated for some time. In the new Docker network system, - they have been removed. You should either connect directly to the - appropriate hostname or set the relevant environment variable yourself, - using the link hostname: - - web: - links: - - db - environment: - - DB_PORT=tcp://db:5432 - -- `external_links`: Compose uses Docker networks when running version 2 - projects, so links behave slightly differently. In particular, two - containers must be connected to at least one network in common in order to - communicate, even if explicitly linked together. - - Either connect the external container to your app's - [default network](networking.md), or connect both the external container and - your service's containers to an - [external network](networking.md#using-a-pre-existing-network). - -- `net`: This is now replaced by [network_mode](#network_mode): - - net: host -> network_mode: host - net: bridge -> network_mode: bridge - net: none -> network_mode: none - - If you're using `net: "container:[service name]"`, you must now use - `network_mode: "service:[service name]"` instead. - - net: "container:web" -> network_mode: "service:web" - - If you're using `net: "container:[container name/id]"`, the value does not - need to change. - - net: "container:cont-name" -> network_mode: "container:cont-name" - net: "container:abc12345" -> network_mode: "container:abc12345" - -- `volumes` with named volumes: these must now be explicitly declared in a - top-level `volumes` section of your Compose file. If a service mounts a - named volume called `data`, you must declare a `data` volume in your - top-level `volumes` section. The whole file might look like this: - - version: '2' - services: - db: - image: postgres - volumes: - - data:/var/lib/postgresql/data - volumes: - data: {} - - By default, Compose creates a volume whose name is prefixed with your - project name. If you want it to just be called `data`, declare it as - external: - - volumes: - data: - external: true - -## Variable substitution - -Your configuration options can contain environment variables. Compose uses the -variable values from the shell environment in which `docker-compose` is run. -For example, suppose the shell contains `EXTERNAL_PORT=8000` and you supply -this configuration: - - web: - build: . - ports: - - "${EXTERNAL_PORT}:5000" - -When you run `docker-compose up` with this configuration, Compose looks for -the `EXTERNAL_PORT` environment variable in the shell and substitutes its -value in. In this example, Compose resolves the port mapping to `"8000:5000"` -before creating the `web` container. - -If an environment variable is not set, Compose substitutes with an empty -string. In the example above, if `EXTERNAL_PORT` is not set, the value for the -port mapping is `:5000` (which is of course an invalid port mapping, and will -result in an error when attempting to create the container). - -Both `$VARIABLE` and `${VARIABLE}` syntax are supported. Extended shell-style -features, such as `${VARIABLE-default}` and `${VARIABLE/foo/bar}`, are not -supported. - -You can use a `$$` (double-dollar sign) when your configuration needs a literal -dollar sign. This also prevents Compose from interpolating a value, so a `$$` -allows you to refer to environment variables that you don't want processed by -Compose. - - web: - build: . - command: "$$VAR_NOT_INTERPOLATED_BY_COMPOSE" - -If you forget and use a single dollar sign (`$`), Compose interprets the value as an environment variable and will warn you: - - The VAR_NOT_INTERPOLATED_BY_COMPOSE is not set. Substituting an empty string. - -## Compose documentation - -- [User guide](index.md) -- [Installing Compose](install.md) -- [Get started with Django](django.md) -- [Get started with Rails](rails.md) -- [Get started with WordPress](wordpress.md) -- [Command line reference](./reference/index.md) diff --git a/compose/django.md b/compose/django.md deleted file mode 100644 index 1cf2a5675c..0000000000 --- a/compose/django.md +++ /dev/null @@ -1,194 +0,0 @@ - - - -# Quickstart: Docker Compose and Django - -This quick-start guide demonstrates how to use Docker Compose to set up and run a simple Django/PostgreSQL app. Before starting, you'll need to have -[Compose installed](install.md). - -### Define the project components - -For this project, you need to create a Dockerfile, a Python dependencies file, -and a `docker-compose.yml` file. - -1. Create an empty project directory. - - You can name the directory something easy for you to remember. This directory is the context for your application image. The directory should only contain resources to build that image. - -2. Create a new file called `Dockerfile` in your project directory. - - The Dockerfile defines an application's image content via one or more build - commands that configure that image. Once built, you can run the image in a - container. For more information on `Dockerfiles`, see the [Docker user - guide](/engine/tutorials/dockerimages.md#building-an-image-from-a-dockerfile) - and the [Dockerfile reference](/engine/reference/builder.md). - -3. Add the following content to the `Dockerfile`. - - FROM python:2.7 - ENV PYTHONUNBUFFERED 1 - RUN mkdir /code - WORKDIR /code - ADD requirements.txt /code/ - RUN pip install -r requirements.txt - ADD . /code/ - - This `Dockerfile` starts with a Python 2.7 base image. The base image is - modified by adding a new `code` directory. The base image is further modified - by installing the Python requirements defined in the `requirements.txt` file. - -4. Save and close the `Dockerfile`. - -5. Create a `requirements.txt` in your project directory. - - This file is used by the `RUN pip install -r requirements.txt` command in your `Dockerfile`. - -6. Add the required software in the file. - - Django - psycopg2 - -7. Save and close the `requirements.txt` file. - -8. Create a file called `docker-compose.yml` in your project directory. - - The `docker-compose.yml` file describes the services that make your app. In - this example those services are a web server and database. The compose file - also describes which Docker images these services use, how they link - together, any volumes they might need mounted inside the containers. - Finally, the `docker-compose.yml` file describes which ports these services - expose. See the [`docker-compose.yml` reference](compose-file.md) for more - information on how this file works. - -9. Add the following configuration to the file. - - version: '2' - services: - db: - image: postgres - web: - build: . - command: python manage.py runserver 0.0.0.0:8000 - volumes: - - .:/code - ports: - - "8000:8000" - depends_on: - - db - - This file defines two services: The `db` service and the `web` service. - -10. Save and close the `docker-compose.yml` file. - -### Create a Django project - -In this step, you create a Django started project by building the image from the build context defined in the previous procedure. - -1. Change to the root of your project directory. - -2. Create the Django project using the `docker-compose` command. - - $ docker-compose run web django-admin.py startproject composeexample . - - This instructs Compose to run `django-admin.py startproject composeeexample` - in a container, using the `web` service's image and configuration. Because - the `web` image doesn't exist yet, Compose builds it from the current - directory, as specified by the `build: .` line in `docker-compose.yml`. - - Once the `web` service image is built, Compose runs it and executes the - `django-admin.py startproject` command in the container. This command - instructs Django to create a set of files and directories representing a - Django project. - -3. After the `docker-compose` command completes, list the contents of your project. - - $ ls -l - drwxr-xr-x 2 root root composeexample - -rw-rw-r-- 1 user user docker-compose.yml - -rw-rw-r-- 1 user user Dockerfile - -rwxr-xr-x 1 root root manage.py - -rw-rw-r-- 1 user user requirements.txt - - If you are running Docker on Linux, the files `django-admin` created are owned - by root. This happens because the container runs as the root user. Change the - ownership of the the new files. - - sudo chown -R $USER:$USER . - - If you are running Docker on Mac or Windows, you should already have ownership - of all files, including those generated by `django-admin`. List the files just - verify this. - - $ ls -l - total 32 - -rw-r--r-- 1 user staff 145 Feb 13 23:00 Dockerfile - drwxr-xr-x 6 user staff 204 Feb 13 23:07 composeexample - -rw-r--r-- 1 user staff 159 Feb 13 23:02 docker-compose.yml - -rwxr-xr-x 1 user staff 257 Feb 13 23:07 manage.py - -rw-r--r-- 1 user staff 16 Feb 13 23:01 requirements.txt - - -### Connect the database - -In this section, you set up the database connection for Django. - -1. In your project directory, edit the `composeexample/settings.py` file. - -2. Replace the `DATABASES = ...` with the following: - - DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.postgresql_psycopg2', - 'NAME': 'postgres', - 'USER': 'postgres', - 'HOST': 'db', - 'PORT': 5432, - } - } - - These settings are determined by the - [postgres](https://hub.docker.com/_/postgres/) Docker image - specified in `docker-compose.yml`. - -3. Save and close the file. - -4. Run the `docker-compose up` command. - - $ docker-compose up - Starting composepractice_db_1... - Starting composepractice_web_1... - Attaching to composepractice_db_1, composepractice_web_1 - ... - db_1 | PostgreSQL init process complete; ready for start up. - ... - db_1 | LOG: database system is ready to accept connections - db_1 | LOG: autovacuum launcher started - .. - web_1 | Django version 1.8.4, using settings 'composeexample.settings' - web_1 | Starting development server at http://0.0.0.0:8000/ - web_1 | Quit the server with CONTROL-C. - - At this point, your Django app should be running at port `8000` on your - Docker host. If you are using a Docker Machine VM, you can use the - `docker-machine ip MACHINE_NAME` to get the IP address. - - ![Django example](images/django-it-worked.png) - -## More Compose documentation - -- [User guide](index.md) -- [Installing Compose](install.md) -- [Getting Started](gettingstarted.md) -- [Get started with Rails](rails.md) -- [Get started with WordPress](wordpress.md) -- [Command line reference](./reference/index.md) -- [Compose file reference](compose-file.md) diff --git a/compose/env-file.md b/compose/env-file.md deleted file mode 100644 index be2625f889..0000000000 --- a/compose/env-file.md +++ /dev/null @@ -1,43 +0,0 @@ - - - -# Environment file - -Compose supports declaring default environment variables in an environment -file named `.env` placed in the folder `docker-compose` command is executed from -*(current working directory)*. - -Compose expects each line in an env file to be in `VAR=VAL` format. Lines -beginning with `#` (i.e. comments) are ignored, as are blank lines. - -> Note: Values present in the environment at runtime will always override -> those defined inside the `.env` file. Similarly, values passed via -> command-line arguments take precedence as well. - -Those environment variables will be used for -[variable substitution](compose-file.md#variable-substitution) in your Compose -file, but can also be used to define the following -[CLI variables](reference/envvars.md): - -- `COMPOSE_API_VERSION` -- `COMPOSE_FILE` -- `COMPOSE_HTTP_TIMEOUT` -- `COMPOSE_PROJECT_NAME` -- `DOCKER_CERT_PATH` -- `DOCKER_HOST` -- `DOCKER_TLS_VERIFY` - -## More Compose documentation - -- [User guide](index.md) -- [Command line reference](./reference/index.md) -- [Compose file reference](compose-file.md) diff --git a/compose/environment-variables.md b/compose/environment-variables.md deleted file mode 100644 index a2e74f0a96..0000000000 --- a/compose/environment-variables.md +++ /dev/null @@ -1,107 +0,0 @@ - - -# Environment variables in Compose - -There are multiple parts of Compose that deal with environment variables in one sense or another. This page should help you find the information you need. - - -## Substituting environment variables in Compose files - -It's possible to use environment variables in your shell to populate values inside a Compose file: - - web: - image: "webapp:${TAG}" - -For more information, see the [Variable substitution](compose-file.md#variable-substitution) section in the Compose file reference. - - -## Setting environment variables in containers - -You can set environment variables in a service's containers with the ['environment' key](compose-file.md#environment), just like with `docker run -e VARIABLE=VALUE ...`: - - web: - environment: - - DEBUG=1 - - -## Passing environment variables through to containers - -You can pass environment variables from your shell straight through to a service's containers with the ['environment' key](compose-file.md#environment) by not giving them a value, just like with `docker run -e VARIABLE ...`: - - web: - environment: - - DEBUG - -The value of the `DEBUG` variable in the container will be taken from the value for the same variable in the shell in which Compose is run. - - -## The “env_file” configuration option - -You can pass multiple environment variables from an external file through to a service's containers with the ['env_file' option](compose-file.md#env-file), just like with `docker run --env-file=FILE ...`: - - web: - env_file: - - web-variables.env - - -## Setting environment variables with 'docker-compose run' - -Just like with `docker run -e`, you can set environment variables on a one-off container with `docker-compose run -e`: - - $ docker-compose run -e DEBUG=1 web python console.py - -You can also pass a variable through from the shell by not giving it a value: - - $ docker-compose run -e DEBUG web python console.py - -The value of the `DEBUG` variable in the container will be taken from the value for the same variable in the shell in which Compose is run. - - -## The “.env” file - -You can set default values for any environment variables referenced in the Compose file, or used to configure Compose, in an [environment file](env-file.md) named `.env`: - - $ cat .env - TAG=v1.5 - - $ cat docker-compose.yml - version: '2.0' - services: - web: - image: "webapp:${TAG}" - -When you run `docker-compose up`, the `web` service defined above uses the image `webapp:v1.5`. You can verify this with the [config command](reference/config.md), which prints your resolved application config to the terminal: - - $ docker-compose config - version: '2.0' - services: - web: - image: 'webapp:v1.5' - -Values in the shell take precedence over those specified in the `.env` file. If you set `TAG` to a different value in your shell, the substitution in `image` uses that instead: - - $ export TAG=v2.0 - - $ docker-compose config - version: '2.0' - services: - web: - image: 'webapp:v2.0' - -## Configuring Compose using environment variables - -Several environment variables are available for you to configure the Docker Compose command-line behaviour. They begin with `COMPOSE_` or `DOCKER_`, and are documented in [CLI Environment Variables](reference/envvars.md). - - -## Environment variables created by links - -When using the ['links' option](compose-file.md#links) in a [v1 Compose file](compose-file.md#version-1), environment variables will be created for each link. They are documented in the [Link environment variables reference](link-env-deprecated.md). Please note, however, that these variables are deprecated - you should just use the link alias as a hostname instead. diff --git a/compose/extends.md b/compose/extends.md deleted file mode 100644 index 6f457391f5..0000000000 --- a/compose/extends.md +++ /dev/null @@ -1,354 +0,0 @@ - - - -# Extending services and Compose files - -Compose supports two methods of sharing common configuration: - -1. Extending an entire Compose file by - [using multiple Compose files](#multiple-compose-files) -2. Extending individual services with [the `extends` field](#extending-services) - - -## Multiple Compose files - -Using multiple Compose files enables you to customize a Compose application -for different environments or different workflows. - -### Understanding multiple Compose files - -By default, Compose reads two files, a `docker-compose.yml` and an optional -`docker-compose.override.yml` file. By convention, the `docker-compose.yml` -contains your base configuration. The override file, as its name implies, can -contain configuration overrides for existing services or entirely new -services. - -If a service is defined in both files Compose merges the configurations using -the rules described in [Adding and overriding -configuration](#adding-and-overriding-configuration). - -To use multiple override files, or an override file with a different name, you -can use the `-f` option to specify the list of files. Compose merges files in -the order they're specified on the command line. See the [`docker-compose` -command reference](./reference/overview.md) for more information about -using `-f`. - -When you use multiple configuration files, you must make sure all paths in the -files are relative to the base Compose file (the first Compose file specified -with `-f`). This is required because override files need not be valid -Compose files. Override files can contain small fragments of configuration. -Tracking which fragment of a service is relative to which path is difficult and -confusing, so to keep paths easier to understand, all paths must be defined -relative to the base file. - -### Example use case - -In this section are two common use cases for multiple compose files: changing a -Compose app for different environments, and running administrative tasks -against a Compose app. - -#### Different environments - -A common use case for multiple files is changing a development Compose app -for a production-like environment (which may be production, staging or CI). -To support these differences, you can split your Compose configuration into -a few different files: - -Start with a base file that defines the canonical configuration for the -services. - -**docker-compose.yml** - - web: - image: example/my_web_app:latest - links: - - db - - cache - - db: - image: postgres:latest - - cache: - image: redis:latest - -In this example the development configuration exposes some ports to the -host, mounts our code as a volume, and builds the web image. - -**docker-compose.override.yml** - - - web: - build: . - volumes: - - '.:/code' - ports: - - 8883:80 - environment: - DEBUG: 'true' - - db: - command: '-d' - ports: - - 5432:5432 - - cache: - ports: - - 6379:6379 - -When you run `docker-compose up` it reads the overrides automatically. - -Now, it would be nice to use this Compose app in a production environment. So, -create another override file (which might be stored in a different git -repo or managed by a different team). - -**docker-compose.prod.yml** - - web: - ports: - - 80:80 - environment: - PRODUCTION: 'true' - - cache: - environment: - TTL: '500' - -To deploy with this production Compose file you can run - - docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d - -This deploys all three services using the configuration in -`docker-compose.yml` and `docker-compose.prod.yml` (but not the -dev configuration in `docker-compose.override.yml`). - - -See [production](production.md) for more information about Compose in -production. - -#### Administrative tasks - -Another common use case is running adhoc or administrative tasks against one -or more services in a Compose app. This example demonstrates running a -database backup. - -Start with a **docker-compose.yml**. - - web: - image: example/my_web_app:latest - links: - - db - - db: - image: postgres:latest - -In a **docker-compose.admin.yml** add a new service to run the database -export or backup. - - dbadmin: - build: database_admin/ - links: - - db - -To start a normal environment run `docker-compose up -d`. To run a database -backup, include the `docker-compose.admin.yml` as well. - - docker-compose -f docker-compose.yml -f docker-compose.admin.yml \ - run dbadmin db-backup - - -## Extending services - -Docker Compose's `extends` keyword enables sharing of common configurations -among different files, or even different projects entirely. Extending services -is useful if you have several services that reuse a common set of configuration -options. Using `extends` you can define a common set of service options in one -place and refer to it from anywhere. - -> **Note:** `links`, `volumes_from`, and `depends_on` are never shared between -> services using >`extends`. These exceptions exist to avoid -> implicit dependencies—you always define `links` and `volumes_from` -> locally. This ensures dependencies between services are clearly visible when -> reading the current file. Defining these locally also ensures changes to the -> referenced file don't result in breakage. - -### Understand the extends configuration - -When defining any service in `docker-compose.yml`, you can declare that you are -extending another service like this: - - web: - extends: - file: common-services.yml - service: webapp - -This instructs Compose to re-use the configuration for the `webapp` service -defined in the `common-services.yml` file. Suppose that `common-services.yml` -looks like this: - - webapp: - build: . - ports: - - "8000:8000" - volumes: - - "/data" - -In this case, you'll get exactly the same result as if you wrote -`docker-compose.yml` with the same `build`, `ports` and `volumes` configuration -values defined directly under `web`. - -You can go further and define (or re-define) configuration locally in -`docker-compose.yml`: - - web: - extends: - file: common-services.yml - service: webapp - environment: - - DEBUG=1 - cpu_shares: 5 - - important_web: - extends: web - cpu_shares: 10 - -You can also write other services and link your `web` service to them: - - web: - extends: - file: common-services.yml - service: webapp - environment: - - DEBUG=1 - cpu_shares: 5 - links: - - db - db: - image: postgres - -### Example use case - -Extending an individual service is useful when you have multiple services that -have a common configuration. The example below is a Compose app with -two services: a web application and a queue worker. Both services use the same -codebase and share many configuration options. - -In a **common.yml** we define the common configuration: - - app: - build: . - environment: - CONFIG_FILE_PATH: /code/config - API_KEY: xxxyyy - cpu_shares: 5 - -In a **docker-compose.yml** we define the concrete services which use the -common configuration: - - webapp: - extends: - file: common.yml - service: app - command: /code/run_web_app - ports: - - 8080:8080 - links: - - queue - - db - - queue_worker: - extends: - file: common.yml - service: app - command: /code/run_worker - links: - - queue - -## Adding and overriding configuration - -Compose copies configurations from the original service over to the local one. -If a configuration option is defined in both the original service the local -service, the local value *replaces* or *extends* the original value. - -For single-value options like `image`, `command` or `mem_limit`, the new value -replaces the old value. - - # original service - command: python app.py - - # local service - command: python otherapp.py - - # result - command: python otherapp.py - -> **Note:** In the case of `build` and `image`, when using -> [version 1 of the Compose file format](compose-file.md#version-1), using one -> option in the local service causes Compose to discard the other option if it -> was defined in the original service. -> -> For example, if the original service defines `image: webapp` and the -> local service defines `build: .` then the resulting service will have -> `build: .` and no `image` option. -> -> This is because `build` and `image` cannot be used together in a version 1 -> file. - -For the **multi-value options** `ports`, `expose`, `external_links`, `dns`, -`dns_search`, and `tmpfs`, Compose concatenates both sets of values: - - # original service - expose: - - "3000" - - # local service - expose: - - "4000" - - "5000" - - # result - expose: - - "3000" - - "4000" - - "5000" - -In the case of `environment`, `labels`, `volumes` and `devices`, Compose -"merges" entries together with locally-defined values taking precedence: - - # original service - environment: - - FOO=original - - BAR=original - - # local service - environment: - - BAR=local - - BAZ=local - - # result - environment: - - FOO=original - - BAR=local - - BAZ=local - - - - -## Compose documentation - -- [User guide](index.md) -- [Installing Compose](install.md) -- [Getting Started](gettingstarted.md) -- [Get started with Django](django.md) -- [Get started with Rails](rails.md) -- [Get started with WordPress](wordpress.md) -- [Command line reference](./reference/index.md) -- [Compose file reference](compose-file.md) diff --git a/compose/faq.md b/compose/faq.md deleted file mode 100644 index 45885255f8..0000000000 --- a/compose/faq.md +++ /dev/null @@ -1,128 +0,0 @@ - - -# Frequently asked questions - -If you don’t see your question here, feel free to drop by `#docker-compose` on -freenode IRC and ask the community. - - -## Can I control service startup order? - -Yes - see [Controlling startup order](startup-order.md). - - -## Why do my services take 10 seconds to recreate or stop? - -Compose stop attempts to stop a container by sending a `SIGTERM`. It then waits -for a [default timeout of 10 seconds](./reference/stop.md). After the timeout, -a `SIGKILL` is sent to the container to forcefully kill it. If you -are waiting for this timeout, it means that your containers aren't shutting down -when they receive the `SIGTERM` signal. - -There has already been a lot written about this problem of -[processes handling signals](https://medium.com/@gchudnov/trapping-signals-in-docker-containers-7a57fdda7d86) -in containers. - -To fix this problem, try the following: - -* Make sure you're using the JSON form of `CMD` and `ENTRYPOINT` -in your Dockerfile. - - For example use `["program", "arg1", "arg2"]` not `"program arg1 arg2"`. - Using the string form causes Docker to run your process using `bash` which - doesn't handle signals properly. Compose always uses the JSON form, so don't - worry if you override the command or entrypoint in your Compose file. - -* If you are able, modify the application that you're running to -add an explicit signal handler for `SIGTERM`. - -* Set the `stop_signal` to a signal which the application knows how to handle: - - web: - build: . - stop_signal: SIGINT - -* If you can't modify the application, wrap the application in a lightweight init -system (like [s6](http://skarnet.org/software/s6/)) or a signal proxy (like -[dumb-init](https://github.com/Yelp/dumb-init) or -[tini](https://github.com/krallin/tini)). Either of these wrappers take care of -handling `SIGTERM` properly. - -## How do I run multiple copies of a Compose file on the same host? - -Compose uses the project name to create unique identifiers for all of a -project's containers and other resources. To run multiple copies of a project, -set a custom project name using the [`-p` command line -option](./reference/overview.md) or the [`COMPOSE_PROJECT_NAME` -environment variable](./reference/envvars.md#compose-project-name). - -## What's the difference between `up`, `run`, and `start`? - -Typically, you want `docker-compose up`. Use `up` to start or restart all the -services defined in a `docker-compose.yml`. In the default "attached" -mode, you'll see all the logs from all the containers. In "detached" mode (`-d`), -Compose exits after starting the containers, but the containers continue to run -in the background. - -The `docker-compose run` command is for running "one-off" or "adhoc" tasks. It -requires the service name you want to run and only starts containers for services -that the running service depends on. Use `run` to run tests or perform -an administrative task such as removing or adding data to a data volume -container. The `run` command acts like `docker run -ti` in that it opens an -interactive terminal to the container and returns an exit status matching the -exit status of the process in the container. - -The `docker-compose start` command is useful only to restart containers -that were previously created, but were stopped. It never creates new -containers. - -## Can I use json instead of yaml for my Compose file? - -Yes. [Yaml is a superset of json](http://stackoverflow.com/a/1729545/444646) so -any JSON file should be valid Yaml. To use a JSON file with Compose, -specify the filename to use, for example: - -```bash -docker-compose -f docker-compose.json up -``` - -## Should I include my code with `COPY`/`ADD` or a volume? - -You can add your code to the image using `COPY` or `ADD` directive in a -`Dockerfile`. This is useful if you need to relocate your code along with the -Docker image, for example when you're sending code to another environment -(production, CI, etc). - -You should use a `volume` if you want to make changes to your code and see them -reflected immediately, for example when you're developing code and your server -supports hot code reloading or live-reload. - -There may be cases where you'll want to use both. You can have the image -include the code using a `COPY`, and use a `volume` in your Compose file to -include the code from the host during development. The volume overrides -the directory contents of the image. - -## Where can I find example compose files? - -There are [many examples of Compose files on -github](https://github.com/search?q=in%3Apath+docker-compose.yml+extension%3Ayml&type=Code). - - -## Compose documentation - -- [Installing Compose](install.md) -- [Get started with Django](django.md) -- [Get started with Rails](rails.md) -- [Get started with WordPress](wordpress.md) -- [Command line reference](./reference/index.md) -- [Compose file reference](compose-file.md) diff --git a/compose/gettingstarted.md b/compose/gettingstarted.md deleted file mode 100644 index 249bff725e..0000000000 --- a/compose/gettingstarted.md +++ /dev/null @@ -1,191 +0,0 @@ - - - -# Getting Started - -On this page you build a simple Python web application running on Docker Compose. The -application uses the Flask framework and increments a value in Redis. While the -sample uses Python, the concepts demonstrated here should be understandable even -if you're not familiar with it. - -## Prerequisites - -Make sure you have already -[installed both Docker Engine and Docker Compose](install.md). You -don't need to install Python, it is provided by a Docker image. - -## Step 1: Setup - -1. Create a directory for the project: - - $ mkdir composetest - $ cd composetest - -2. With your favorite text editor create a file called `app.py` in your project - directory. - - from flask import Flask - from redis import Redis - - app = Flask(__name__) - redis = Redis(host='redis', port=6379) - - @app.route('/') - def hello(): - redis.incr('hits') - return 'Hello World! I have been seen %s times.' % redis.get('hits') - - if __name__ == "__main__": - app.run(host="0.0.0.0", debug=True) - -3. Create another file called `requirements.txt` in your project directory and - add the following: - - flask - redis - - These define the applications dependencies. - -## Step 2: Create a Docker image - -In this step, you build a new Docker image. The image contains all the -dependencies the Python application requires, including Python itself. - -1. In your project directory create a file named `Dockerfile` and add the - following: - - FROM python:2.7 - ADD . /code - WORKDIR /code - RUN pip install -r requirements.txt - CMD python app.py - - This tells Docker to: - - * Build an image starting with the Python 2.7 image. - * Add the current directory `.` into the path `/code` in the image. - * Set the working directory to `/code`. - * Install the Python dependencies. - * Set the default command for the container to `python app.py` - - For more information on how to write Dockerfiles, see the [Docker user guide](/engine/tutorials/dockerimages.md#building-an-image-from-a-dockerfile) and the [Dockerfile reference](/engine/reference/builder.md). - -2. Build the image. - - $ docker build -t web . - - This command builds an image named `web` from the contents of the current - directory. The command automatically locates the `Dockerfile`, `app.py`, and - `requirements.txt` files. - - -## Step 3: Define services - -Define a set of services using `docker-compose.yml`: - -1. Create a file called docker-compose.yml in your project directory and add - the following: - - - version: '2' - services: - web: - build: . - ports: - - "5000:5000" - volumes: - - .:/code - depends_on: - - redis - redis: - image: redis - -This Compose file defines two services, `web` and `redis`. The web service: - -* Builds from the `Dockerfile` in the current directory. -* Forwards the exposed port 5000 on the container to port 5000 on the host machine. -* Mounts the project directory on the host to `/code` inside the container allowing you to modify the code without having to rebuild the image. -* Links the web service to the Redis service. - -The `redis` service uses the latest public [Redis](https://registry.hub.docker.com/_/redis/) image pulled from the Docker Hub registry. - -## Step 4: Build and run your app with Compose - -1. From your project directory, start up your application. - - $ docker-compose up - Pulling image redis... - Building web... - Starting composetest_redis_1... - Starting composetest_web_1... - redis_1 | [8] 02 Jan 18:43:35.576 # Server started, Redis version 2.8.3 - web_1 | * Running on http://0.0.0.0:5000/ - web_1 | * Restarting with stat - - Compose pulls a Redis image, builds an image for your code, and start the - services you defined. - -2. Enter `http://0.0.0.0:5000/` in a browser to see the application running. - - If you're using Docker on Linux natively, then the web app should now be - listening on port 5000 on your Docker daemon host. If `http://0.0.0.0:5000` - doesn't resolve, you can also try `http://localhost:5000`. - - If you're using Docker Machine on a Mac, use `docker-machine ip MACHINE_VM` to get - the IP address of your Docker host. Then, `open http://MACHINE_VM_IP:5000` in a - browser. - - You should see a message in your browser saying: - - `Hello World! I have been seen 1 times.` - -3. Refresh the page. - - The number should increment. - -## Step 5: Experiment with some other commands - -If you want to run your services in the background, you can pass the `-d` flag -(for "detached" mode) to `docker-compose up` and use `docker-compose ps` to -see what is currently running: - - $ docker-compose up -d - Starting composetest_redis_1... - Starting composetest_web_1... - $ docker-compose ps - Name Command State Ports - ------------------------------------------------------------------- - composetest_redis_1 /usr/local/bin/run Up - composetest_web_1 /bin/sh -c python app.py Up 5000->5000/tcp - -The `docker-compose run` command allows you to run one-off commands for your -services. For example, to see what environment variables are available to the -`web` service: - - $ docker-compose run web env - -See `docker-compose --help` to see other available commands. You can also install [command completion](completion.md) for the bash and zsh shell, which will also show you available commands. - -If you started Compose with `docker-compose up -d`, you'll probably want to stop -your services once you've finished with them: - - $ docker-compose stop - -At this point, you have seen the basics of how Compose works. - - -## Where to go next - -- Next, try the quick start guide for [Django](django.md), - [Rails](rails.md), or [WordPress](wordpress.md). -- [Explore the full list of Compose commands](./reference/index.md) -- [Compose configuration file reference](compose-file.md) diff --git a/compose/images/django-it-worked.png b/compose/images/django-it-worked.png deleted file mode 100644 index 75769754b9..0000000000 Binary files a/compose/images/django-it-worked.png and /dev/null differ diff --git a/compose/images/rails-welcome.png b/compose/images/rails-welcome.png deleted file mode 100644 index 51512dbda6..0000000000 Binary files a/compose/images/rails-welcome.png and /dev/null differ diff --git a/compose/images/wordpress-files.png b/compose/images/wordpress-files.png deleted file mode 100644 index 4762935bae..0000000000 Binary files a/compose/images/wordpress-files.png and /dev/null differ diff --git a/compose/images/wordpress-lang.png b/compose/images/wordpress-lang.png deleted file mode 100644 index f0bd864ef0..0000000000 Binary files a/compose/images/wordpress-lang.png and /dev/null differ diff --git a/compose/images/wordpress-welcome.png b/compose/images/wordpress-welcome.png deleted file mode 100644 index c9ba20368c..0000000000 Binary files a/compose/images/wordpress-welcome.png and /dev/null differ diff --git a/compose/index.md b/compose/index.md deleted file mode 100644 index f1b710794e..0000000000 --- a/compose/index.md +++ /dev/null @@ -1,30 +0,0 @@ - - - -# Docker Compose - -Compose is a tool for defining and running multi-container Docker applications. To learn more about Compose refer to the following documentation: - -- [Compose Overview](overview.md) -- [Install Compose](install.md) -- [Getting Started](gettingstarted.md) -- [Get started with Django](django.md) -- [Get started with Rails](rails.md) -- [Get started with WordPress](wordpress.md) -- [Frequently asked questions](faq.md) -- [Command line reference](./reference/index.md) -- [Compose file reference](compose-file.md) -- [Environment file](env-file.md) - -To see a detailed list of changes for past and current releases of Docker -Compose, please refer to the -[CHANGELOG](https://github.com/docker/compose/blob/master/CHANGELOG.md). diff --git a/compose/install.md b/compose/install.md deleted file mode 100644 index bb7f07b3d1..0000000000 --- a/compose/install.md +++ /dev/null @@ -1,136 +0,0 @@ - - - -# Install Docker Compose - -You can run Compose on OS X, Windows and 64-bit Linux. To install it, you'll need to install Docker first. - -To install Compose, do the following: - -1. Install Docker Engine: - - * Mac OS X installation - - * Windows installation - - * Ubuntu installation - - * other system installations - -2. The Docker Toolbox installation includes both Engine and Compose, so Mac and Windows users are done installing. Others should continue to the next step. - -3. Go to the Compose repository release page on GitHub. - -4. Follow the instructions from the release page and run the `curl` command, -which the release page specifies, in your terminal. - - > Note: If you get a "Permission denied" error, your `/usr/local/bin` directory - probably isn't writable and you'll need to install Compose as the superuser. Run - `sudo -i`, then the two commands below, then `exit`. - - The following is an example command illustrating the format: - - curl -L https://github.com/docker/compose/releases/download/1.8.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose - - If you have problems installing with `curl`, see - [Alternative Install Options](#alternative-install-options). - -5. Apply executable permissions to the binary: - - $ chmod +x /usr/local/bin/docker-compose - -6. Optionally, install [command completion](completion.md) for the -`bash` and `zsh` shell. - -7. Test the installation. - - $ docker-compose --version - docker-compose version: 1.8.0 - - -## Alternative install options - -### Install using pip - -Compose can be installed from [pypi](https://pypi.python.org/pypi/docker-compose) -using `pip`. If you install using `pip` it is highly recommended that you use a -[virtualenv](https://virtualenv.pypa.io/en/latest/) because many operating systems -have python system packages that conflict with docker-compose dependencies. See -the [virtualenv tutorial](http://docs.python-guide.org/en/latest/dev/virtualenvs/) -to get started. - - $ pip install docker-compose - -> **Note:** pip version 6.0 or greater is required - -### Install as a container - -Compose can also be run inside a container, from a small bash script wrapper. -To install compose as a container run: - - $ curl -L https://github.com/docker/compose/releases/download/1.8.0/run.sh > /usr/local/bin/docker-compose - $ chmod +x /usr/local/bin/docker-compose - -## Master builds - -If you're interested in trying out a pre-release build you can download a -binary from https://dl.bintray.com/docker-compose/master/. Pre-release -builds allow you to try out new features before they are released, but may -be less stable. - - -## Upgrading - -If you're upgrading from Compose 1.2 or earlier, you'll need to remove or migrate -your existing containers after upgrading Compose. This is because, as of version -1.3, Compose uses Docker labels to keep track of containers, and so they need to -be recreated with labels added. - -If Compose detects containers that were created without labels, it will refuse -to run so that you don't end up with two sets of them. If you want to keep using -your existing containers (for example, because they have data volumes you want -to preserve) you can use compose 1.5.x to migrate them with the following command: - - $ docker-compose migrate-to-labels - -Alternatively, if you're not worried about keeping them, you can remove them. -Compose will just create new ones. - - $ docker rm -f -v myapp_web_1 myapp_db_1 ... - - -## Uninstallation - -To uninstall Docker Compose if you installed using `curl`: - - $ rm /usr/local/bin/docker-compose - - -To uninstall Docker Compose if you installed using `pip`: - - $ pip uninstall docker-compose - ->**Note**: If you get a "Permission denied" error using either of the above ->methods, you probably do not have the proper permissions to remove ->`docker-compose`. To force the removal, prepend `sudo` to either of the above ->commands and run again. - - -## Where to go next - -- [User guide](index.md) -- [Getting Started](gettingstarted.md) -- [Get started with Django](django.md) -- [Get started with Rails](rails.md) -- [Get started with WordPress](wordpress.md) -- [Command line reference](./reference/index.md) -- [Compose file reference](compose-file.md) diff --git a/compose/link-env-deprecated.md b/compose/link-env-deprecated.md deleted file mode 100644 index b1f01b3b6a..0000000000 --- a/compose/link-env-deprecated.md +++ /dev/null @@ -1,48 +0,0 @@ - - -# Link environment variables reference - -> **Note:** Environment variables are no longer the recommended method for connecting to linked services. Instead, you should use the link name (by default, the name of the linked service) as the hostname to connect to. See the [docker-compose.yml documentation](compose-file.md#links) for details. -> -> Environment variables will only be populated if you're using the [legacy version 1 Compose file format](compose-file.md#versioning). - -Compose uses [Docker links](/engine/userguide/networking/default_network/dockerlinks.md) -to expose services' containers to one another. Each linked container injects a set of -environment variables, each of which begins with the uppercase name of the container. - -To see what environment variables are available to a service, run `docker-compose run SERVICE env`. - -name\_PORT
    -Full URL, e.g. `DB_PORT=tcp://172.17.0.5:5432` - -name\_PORT\_num\_protocol
    -Full URL, e.g. `DB_PORT_5432_TCP=tcp://172.17.0.5:5432` - -name\_PORT\_num\_protocol\_ADDR
    -Container's IP address, e.g. `DB_PORT_5432_TCP_ADDR=172.17.0.5` - -name\_PORT\_num\_protocol\_PORT
    -Exposed port number, e.g. `DB_PORT_5432_TCP_PORT=5432` - -name\_PORT\_num\_protocol\_PROTO
    -Protocol (tcp or udp), e.g. `DB_PORT_5432_TCP_PROTO=tcp` - -name\_NAME
    -Fully qualified container name, e.g. `DB_1_NAME=/myapp_web_1/myapp_db_1` - -## Related Information - -- [User guide](index.md) -- [Installing Compose](install.md) -- [Command line reference](./reference/index.md) -- [Compose file reference](compose-file.md) diff --git a/compose/networking.md b/compose/networking.md deleted file mode 100644 index 9739a08840..0000000000 --- a/compose/networking.md +++ /dev/null @@ -1,154 +0,0 @@ - - - -# Networking in Compose - -> **Note:** This document only applies if you're using [version 2 of the Compose file format](compose-file.md#versioning). Networking features are not supported for version 1 (legacy) Compose files. - -By default Compose sets up a single -[network](https://docs.docker.com/engine/reference/commandline/network_create/) for your app. Each -container for a service joins the default network and is both *reachable* by -other containers on that network, and *discoverable* by them at a hostname -identical to the container name. - -> **Note:** Your app's network is given a name based on the "project name", -> which is based on the name of the directory it lives in. You can override the -> project name with either the [`--project-name` -> flag](reference/overview.md) or the [`COMPOSE_PROJECT_NAME` environment -> variable](reference/envvars.md#compose-project-name). - -For example, suppose your app is in a directory called `myapp`, and your `docker-compose.yml` looks like this: - - version: '2' - - services: - web: - build: . - ports: - - "8000:8000" - db: - image: postgres - -When you run `docker-compose up`, the following happens: - -1. A network called `myapp_default` is created. -2. A container is created using `web`'s configuration. It joins the network - `myapp_default` under the name `web`. -3. A container is created using `db`'s configuration. It joins the network - `myapp_default` under the name `db`. - -Each container can now look up the hostname `web` or `db` and -get back the appropriate container's IP address. For example, `web`'s -application code could connect to the URL `postgres://db:5432` and start -using the Postgres database. - -Because `web` explicitly maps a port, it's also accessible from the outside world via port 8000 on your Docker host's network interface. - -## Updating containers - -If you make a configuration change to a service and run `docker-compose up` to update it, the old container will be removed and the new one will join the network under a different IP address but the same name. Running containers will be able to look up that name and connect to the new address, but the old address will stop working. - -If any containers have connections open to the old container, they will be closed. It is a container's responsibility to detect this condition, look up the name again and reconnect. - -## Links - -Links allow you to define extra aliases by which a service is reachable from another service. They are not required to enable services to communicate - by default, any service can reach any other service at that service's name. In the following example, `db` is reachable from `web` at the hostnames `db` and `database`: - - version: '2' - services: - web: - build: . - links: - - "db:database" - db: - image: postgres - -See the [links reference](compose-file.md#links) for more information. - -## Multi-host networking - -When [deploying a Compose application to a Swarm cluster](swarm.md), you can make use of the built-in `overlay` driver to enable multi-host communication between containers with no changes to your Compose file or application code. - -Consult the [Getting started with multi-host networking](https://docs.docker.com/engine/userguide/networking/get-started-overlay/) to see how to set up a Swarm cluster. The cluster will use the `overlay` driver by default, but you can specify it explicitly if you prefer - see below for how to do this. - -## Specifying custom networks - -Instead of just using the default app network, you can specify your own networks with the top-level `networks` key. This lets you create more complex topologies and specify [custom network drivers](https://docs.docker.com/engine/extend/plugins_network/) and options. You can also use it to connect services to externally-created networks which aren't managed by Compose. - -Each service can specify what networks to connect to with the *service-level* `networks` key, which is a list of names referencing entries under the *top-level* `networks` key. - -Here's an example Compose file defining two custom networks. The `proxy` service is isolated from the `db` service, because they do not share a network in common - only `app` can talk to both. - - version: '2' - - services: - proxy: - build: ./proxy - networks: - - front - app: - build: ./app - networks: - - front - - back - db: - image: postgres - networks: - - back - - networks: - front: - # Use a custom driver - driver: custom-driver-1 - back: - # Use a custom driver which takes special options - driver: custom-driver-2 - driver_opts: - foo: "1" - bar: "2" - -Networks can be configured with static IP addresses by setting the [ipv4_address and/or ipv6_address](compose-file.md#ipv4-address-ipv6-address) for each attached network. - -For full details of the network configuration options available, see the following references: - -- [Top-level `networks` key](compose-file.md#network-configuration-reference) -- [Service-level `networks` key](compose-file.md#networks) - -## Configuring the default network - -Instead of (or as well as) specifying your own networks, you can also change the settings of the app-wide default network by defining an entry under `networks` named `default`: - - version: '2' - - services: - web: - build: . - ports: - - "8000:8000" - db: - image: postgres - - networks: - default: - # Use a custom driver - driver: custom-driver-1 - -## Using a pre-existing network - -If you want your containers to join a pre-existing network, use the [`external` option](compose-file.md#network-configuration-reference): - - networks: - default: - external: - name: my-pre-existing-network - -Instead of attemping to create a network called `[projectname]_default`, Compose will look for a network called `my-pre-existing-network` and connect your app's containers to it. diff --git a/compose/overview.md b/compose/overview.md deleted file mode 100644 index ef07a45be5..0000000000 --- a/compose/overview.md +++ /dev/null @@ -1,188 +0,0 @@ - - - -# Overview of Docker Compose - -Compose is a tool for defining and running multi-container Docker applications. -With Compose, you use a Compose file to configure your application's services. -Then, using a single command, you create and start all the services -from your configuration. To learn more about all the features of Compose -see [the list of features](#features). - -Compose is great for development, testing, and staging environments, as well as -CI workflows. You can learn more about each case in -[Common Use Cases](#common-use-cases). - -Using Compose is basically a three-step process. - -1. Define your app's environment with a `Dockerfile` so it can be reproduced -anywhere. - -2. Define the services that make up your app in `docker-compose.yml` -so they can be run together in an isolated environment. - -3. Lastly, run -`docker-compose up` and Compose will start and run your entire app. - -A `docker-compose.yml` looks like this: - - version: '2' - services: - web: - build: . - ports: - - "5000:5000" - volumes: - - .:/code - - logvolume01:/var/log - links: - - redis - redis: - image: redis - volumes: - logvolume01: {} - -For more information about the Compose file, see the -[Compose file reference](compose-file.md) - -Compose has commands for managing the whole lifecycle of your application: - - * Start, stop and rebuild services - * View the status of running services - * Stream the log output of running services - * Run a one-off command on a service - -## Compose documentation - -- [Installing Compose](install.md) -- [Getting Started](gettingstarted.md) -- [Get started with Django](django.md) -- [Get started with Rails](rails.md) -- [Get started with WordPress](wordpress.md) -- [Frequently asked questions](faq.md) -- [Command line reference](./reference/index.md) -- [Compose file reference](compose-file.md) - -## Features - -The features of Compose that make it effective are: - -* [Multiple isolated environments on a single host](#Multiple-isolated-environments-on-a-single-host) -* [Preserve volume data when containers are created](#preserve-volume-data-when-containers-are-created) -* [Only recreate containers that have changed](#only-recreate-containers-that-have-changed) -* [Variables and moving a composition between environments](#variables-and-moving-a-composition-between-environments) - -### Multiple isolated environments on a single host - -Compose uses a project name to isolate environments from each other. You can make use of this project name in several different contexts: - -* on a dev host, to create multiple copies of a single environment (e.g., you want to run a stable copy for each feature branch of a project) -* on a CI server, to keep builds from interfering with each other, you can set - the project name to a unique build number -* on a shared host or dev host, to prevent different projects, which may use the - same service names, from interfering with each other - -The default project name is the basename of the project directory. You can set -a custom project name by using the -[`-p` command line option](./reference/overview.md) or the -[`COMPOSE_PROJECT_NAME` environment variable](./reference/envvars.md#compose-project-name). - -### Preserve volume data when containers are created - -Compose preserves all volumes used by your services. When `docker-compose up` -runs, if it finds any containers from previous runs, it copies the volumes from -the old container to the new container. This process ensures that any data -you've created in volumes isn't lost. - - -### Only recreate containers that have changed - -Compose caches the configuration used to create a container. When you -restart a service that has not changed, Compose re-uses the existing -containers. Re-using containers means that you can make changes to your -environment very quickly. - - -### Variables and moving a composition between environments - -Compose supports variables in the Compose file. You can use these variables -to customize your composition for different environments, or different users. -See [Variable substitution](compose-file.md#variable-substitution) for more -details. - -You can extend a Compose file using the `extends` field or by creating multiple -Compose files. See [extends](extends.md) for more details. - - -## Common Use Cases - -Compose can be used in many different ways. Some common use cases are outlined -below. - -### Development environments - -When you're developing software, the ability to run an application in an -isolated environment and interact with it is crucial. The Compose command -line tool can be used to create the environment and interact with it. - -The [Compose file](compose-file.md) provides a way to document and configure -all of the application's service dependencies (databases, queues, caches, -web service APIs, etc). Using the Compose command line tool you can create -and start one or more containers for each dependency with a single command -(`docker-compose up`). - -Together, these features provide a convenient way for developers to get -started on a project. Compose can reduce a multi-page "developer getting -started guide" to a single machine readable Compose file and a few commands. - -### Automated testing environments - -An important part of any Continuous Deployment or Continuous Integration process -is the automated test suite. Automated end-to-end testing requires an -environment in which to run tests. Compose provides a convenient way to create -and destroy isolated testing environments for your test suite. By defining the full environment in a [Compose file](compose-file.md) you can create and destroy these environments in just a few commands: - - $ docker-compose up -d - $ ./run_tests - $ docker-compose down - -### Single host deployments - -Compose has traditionally been focused on development and testing workflows, -but with each release we're making progress on more production-oriented features. You can use Compose to deploy to a remote Docker Engine. The Docker Engine may be a single instance provisioned with -[Docker Machine](/machine/overview.md) or an entire -[Docker Swarm](/swarm/overview.md) cluster. - -For details on using production-oriented features, see -[compose in production](production.md) in this documentation. - - -## Release Notes - -To see a detailed list of changes for past and current releases of Docker -Compose, please refer to the -[CHANGELOG](https://github.com/docker/compose/blob/master/CHANGELOG.md). - -## Getting help - -Docker Compose is under active development. If you need help, would like to -contribute, or simply want to talk about the project with like-minded -individuals, we have a number of open channels for communication. - -* To report bugs or file feature requests: please use the [issue tracker on Github](https://github.com/docker/compose/issues). - -* To talk about the project with people in real time: please join the - `#docker-compose` channel on freenode IRC. - -* To contribute code or documentation changes: please submit a [pull request on Github](https://github.com/docker/compose/pulls). - -For more information and resources, please visit the [Getting Help project page](https://docs.docker.com/opensource/get-help/). diff --git a/compose/production.md b/compose/production.md deleted file mode 100644 index cfb8729363..0000000000 --- a/compose/production.md +++ /dev/null @@ -1,88 +0,0 @@ - - - -## Using Compose in production - -When you define your app with Compose in development, you can use this -definition to run your application in different environments such as CI, -staging, and production. - -The easiest way to deploy an application is to run it on a single server, -similar to how you would run your development environment. If you want to scale -up your application, you can run Compose apps on a Swarm cluster. - -### Modify your Compose file for production - -You'll almost certainly want to make changes to your app configuration that are -more appropriate to a live environment. These changes may include: - -- Removing any volume bindings for application code, so that code stays inside - the container and can't be changed from outside -- Binding to different ports on the host -- Setting environment variables differently (e.g., to decrease the verbosity of - logging, or to enable email sending) -- Specifying a restart policy (e.g., `restart: always`) to avoid downtime -- Adding extra services (e.g., a log aggregator) - -For this reason, you'll probably want to define an additional Compose file, say -`production.yml`, which specifies production-appropriate -configuration. This configuration file only needs to include the changes you'd -like to make from the original Compose file. The additional Compose file -can be applied over the original `docker-compose.yml` to create a new configuration. - -Once you've got a second configuration file, tell Compose to use it with the -`-f` option: - - $ docker-compose -f docker-compose.yml -f production.yml up -d - -See [Using multiple compose files](extends.md#different-environments) for a more -complete example. - -### Deploying changes - -When you make changes to your app code, you'll need to rebuild your image and -recreate your app's containers. To redeploy a service called -`web`, you would use: - - $ docker-compose build web - $ docker-compose up --no-deps -d web - -This will first rebuild the image for `web` and then stop, destroy, and recreate -*just* the `web` service. The `--no-deps` flag prevents Compose from also -recreating any services which `web` depends on. - -### Running Compose on a single server - -You can use Compose to deploy an app to a remote Docker host by setting the -`DOCKER_HOST`, `DOCKER_TLS_VERIFY`, and `DOCKER_CERT_PATH` environment variables -appropriately. For tasks like this, -[Docker Machine](/machine/overview.md) makes managing local and -remote Docker hosts very easy, and is recommended even if you're not deploying -remotely. - -Once you've set up your environment variables, all the normal `docker-compose` -commands will work with no further configuration. - -### Running Compose on a Swarm cluster - -[Docker Swarm](/swarm/overview.md), a Docker-native clustering -system, exposes the same API as a single Docker host, which means you can use -Compose against a Swarm instance and run your apps across multiple hosts. - -Read more about the Compose/Swarm integration in the -[integration guide](swarm.md). - -## Compose documentation - -- [Installing Compose](install.md) -- [Command line reference](./reference/index.md) -- [Compose file reference](compose-file.md) diff --git a/compose/rails.md b/compose/rails.md deleted file mode 100644 index 267776872e..0000000000 --- a/compose/rails.md +++ /dev/null @@ -1,174 +0,0 @@ - - -## Quickstart: Docker Compose and Rails - -This Quickstart guide will show you how to use Docker Compose to set up and run a Rails/PostgreSQL app. Before starting, you'll need to have [Compose installed](install.md). - -### Define the project - -Start by setting up the three files you'll need to build the app. First, since -your app is going to run inside a Docker container containing all of its -dependencies, you'll need to define exactly what needs to be included in the -container. This is done using a file called `Dockerfile`. To begin with, the -Dockerfile consists of: - - FROM ruby:2.2.0 - RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs - RUN mkdir /myapp - WORKDIR /myapp - ADD Gemfile /myapp/Gemfile - ADD Gemfile.lock /myapp/Gemfile.lock - RUN bundle install - ADD . /myapp - -That'll put your application code inside an image that will build a container -with Ruby, Bundler and all your dependencies inside it. For more information on -how to write Dockerfiles, see the [Docker user guide](/engine/tutorials/dockerimages.md#building-an-image-from-a-dockerfile) and the [Dockerfile reference](/engine/reference/builder.md). - -Next, create a bootstrap `Gemfile` which just loads Rails. It'll be overwritten in a moment by `rails new`. - - source 'https://rubygems.org' - gem 'rails', '4.2.0' - -You'll need an empty `Gemfile.lock` in order to build our `Dockerfile`. - - $ touch Gemfile.lock - -Finally, `docker-compose.yml` is where the magic happens. This file describes -the services that comprise your app (a database and a web app), how to get each -one's Docker image (the database just runs on a pre-made PostgreSQL image, and -the web app is built from the current directory), and the configuration needed -to link them together and expose the web app's port. - - version: '2' - services: - db: - image: postgres - web: - build: . - command: bundle exec rails s -p 3000 -b '0.0.0.0' - volumes: - - .:/myapp - ports: - - "3000:3000" - depends_on: - - db - -### Build the project - -With those three files in place, you can now generate the Rails skeleton app -using `docker-compose run`: - - $ docker-compose run web rails new . --force --database=postgresql --skip-bundle - -First, Compose will build the image for the `web` service using the `Dockerfile`. Then it'll run `rails new` inside a new container, using that image. Once it's done, you should have generated a fresh app: - - $ ls -l - total 56 - -rw-r--r-- 1 user staff 215 Feb 13 23:33 Dockerfile - -rw-r--r-- 1 user staff 1480 Feb 13 23:43 Gemfile - -rw-r--r-- 1 user staff 2535 Feb 13 23:43 Gemfile.lock - -rw-r--r-- 1 root root 478 Feb 13 23:43 README.rdoc - -rw-r--r-- 1 root root 249 Feb 13 23:43 Rakefile - drwxr-xr-x 8 root root 272 Feb 13 23:43 app - drwxr-xr-x 6 root root 204 Feb 13 23:43 bin - drwxr-xr-x 11 root root 374 Feb 13 23:43 config - -rw-r--r-- 1 root root 153 Feb 13 23:43 config.ru - drwxr-xr-x 3 root root 102 Feb 13 23:43 db - -rw-r--r-- 1 user staff 161 Feb 13 23:35 docker-compose.yml - drwxr-xr-x 4 root root 136 Feb 13 23:43 lib - drwxr-xr-x 3 root root 102 Feb 13 23:43 log - drwxr-xr-x 7 root root 238 Feb 13 23:43 public - drwxr-xr-x 9 root root 306 Feb 13 23:43 test - drwxr-xr-x 3 root root 102 Feb 13 23:43 tmp - drwxr-xr-x 3 root root 102 Feb 13 23:43 vendor - - -If you are running Docker on Linux, the files `rails new` created are owned by -root. This happens because the container runs as the root user. Change the -ownership of the the new files. - - sudo chown -R $USER:$USER . - -If you are running Docker on Mac or Windows, you should already have ownership -of all files, including those generated by `rails new`. List the files just to -verify this. - -Uncomment the line in your new `Gemfile` which loads `therubyracer`, so you've -got a Javascript runtime: - - gem 'therubyracer', platforms: :ruby - -Now that you've got a new `Gemfile`, you need to build the image again. (This, -and changes to the Dockerfile itself, should be the only times you'll need to -rebuild.) - - $ docker-compose build - - -### Connect the database - -The app is now bootable, but you're not quite there yet. By default, Rails -expects a database to be running on `localhost` - so you need to point it at the -`db` container instead. You also need to change the database and username to -align with the defaults set by the `postgres` image. - -Replace the contents of `config/database.yml` with the following: - - development: &default - adapter: postgresql - encoding: unicode - database: postgres - pool: 5 - username: postgres - password: - host: db - - test: - <<: *default - database: myapp_test - -You can now boot the app with: - - $ docker-compose up - -If all's well, you should see some PostgreSQL output, and then—after a few -seconds—the familiar refrain: - - myapp_web_1 | [2014-01-17 17:16:29] INFO WEBrick 1.3.1 - myapp_web_1 | [2014-01-17 17:16:29] INFO ruby 2.2.0 (2014-12-25) [x86_64-linux-gnu] - myapp_web_1 | [2014-01-17 17:16:29] INFO WEBrick::HTTPServer#start: pid=1 port=3000 - -Finally, you need to create the database. In another terminal, run: - - $ docker-compose run web rake db:create - -That's it. Your app should now be running on port 3000 on your Docker daemon. If you're using [Docker Machine](/machine/overview.md), then `docker-machine ip MACHINE_VM` returns the Docker host IP address. - -![Rails example](images/rails-welcome.png) - ->**Note**: If you stop the example application and attempt to restart it, you might get the -following error: `web_1 | A server is already running. Check -/myapp/tmp/pids/server.pid.` One way to resolve this is to delete the file -`tmp/pids/server.pid`, and then re-start the application with `docker-compose -up`. - - -## More Compose documentation - -- [User guide](index.md) -- [Installing Compose](install.md) -- [Getting Started](gettingstarted.md) -- [Get started with Django](django.md) -- [Get started with WordPress](wordpress.md) -- [Command line reference](./reference/index.md) -- [Compose file reference](compose-file.md) diff --git a/compose/reference/build.md b/compose/reference/build.md deleted file mode 100644 index 84aefc253f..0000000000 --- a/compose/reference/build.md +++ /dev/null @@ -1,25 +0,0 @@ - - -# build - -``` -Usage: build [options] [SERVICE...] - -Options: ---force-rm Always remove intermediate containers. ---no-cache Do not use cache when building the image. ---pull Always attempt to pull a newer version of the image. -``` - -Services are built once and then tagged as `project_service`, e.g., -`composetest_db`. If you change a service's Dockerfile or the contents of its -build directory, run `docker-compose build` to rebuild it. diff --git a/compose/reference/bundle.md b/compose/reference/bundle.md deleted file mode 100644 index fca93a8aa6..0000000000 --- a/compose/reference/bundle.md +++ /dev/null @@ -1,31 +0,0 @@ - - -# bundle - -``` -Usage: bundle [options] - -Options: - --push-images Automatically push images for any services - which have a `build` option specified. - - -o, --output PATH Path to write the bundle file to. - Defaults to ".dab". -``` - -Generate a Distributed Application Bundle (DAB) from the Compose file. - -Images must have digests stored, which requires interaction with a -Docker registry. If digests aren't stored for all images, you can fetch -them with `docker-compose pull` or `docker-compose push`. To push images -automatically when bundling, pass `--push-images`. Only services with -a `build` option specified will have their images pushed. diff --git a/compose/reference/config.md b/compose/reference/config.md deleted file mode 100644 index 1a9706f4da..0000000000 --- a/compose/reference/config.md +++ /dev/null @@ -1,23 +0,0 @@ - - -# config - -```: -Usage: config [options] - -Options: --q, --quiet Only validate the configuration, don't print - anything. ---services Print the service names, one per line. -``` - -Validate and view the compose file. diff --git a/compose/reference/create.md b/compose/reference/create.md deleted file mode 100644 index 5065e8bebe..0000000000 --- a/compose/reference/create.md +++ /dev/null @@ -1,26 +0,0 @@ - - -# create - -``` -Creates containers for a service. - -Usage: create [options] [SERVICE...] - -Options: - --force-recreate Recreate containers even if their configuration and - image haven't changed. Incompatible with --no-recreate. - --no-recreate If containers already exist, don't recreate them. - Incompatible with --force-recreate. - --no-build Don't build an image, even if it's missing. - --build Build images before creating containers. -``` diff --git a/compose/reference/down.md b/compose/reference/down.md deleted file mode 100644 index ffe88b4e05..0000000000 --- a/compose/reference/down.md +++ /dev/null @@ -1,38 +0,0 @@ - - -# down - -``` -Usage: down [options] - -Options: - --rmi type Remove images. Type must be one of: - 'all': Remove all images used by any service. - 'local': Remove only images that don't have a custom tag - set by the `image` field. - -v, --volumes Remove named volumes declared in the `volumes` section - of the Compose file and anonymous volumes - attached to containers. - --remove-orphans Remove containers for services not defined in the - Compose file -``` - -Stops containers and removes containers, networks, volumes, and images -created by `up`. - -By default, the only things removed are: - -- Containers for services defined in the Compose file -- Networks defined in the `networks` section of the Compose file -- The default network, if one is used - -Networks and volumes defined as `external` are never removed. diff --git a/compose/reference/envvars.md b/compose/reference/envvars.md deleted file mode 100644 index 22516debdc..0000000000 --- a/compose/reference/envvars.md +++ /dev/null @@ -1,92 +0,0 @@ - - - -# CLI Environment Variables - -Several environment variables are available for you to configure the Docker Compose command-line behaviour. - -Variables starting with `DOCKER_` are the same as those used to configure the -Docker command-line client. If you're using `docker-machine`, then the `eval "$(docker-machine env my-docker-vm)"` command should set them to their correct values. (In this example, `my-docker-vm` is the name of a machine you created.) - -> Note: Some of these variables can also be provided using an -> [environment file](../env-file.md) - -## COMPOSE\_PROJECT\_NAME - -Sets the project name. This value is prepended along with the service name to the container container on start up. For example, if you project name is `myapp` and it includes two services `db` and `web` then compose starts containers named `myapp_db_1` and `myapp_web_1` respectively. - -Setting this is optional. If you do not set this, the `COMPOSE_PROJECT_NAME` -defaults to the `basename` of the project directory. See also the `-p` -[command-line option](overview.md). - -## COMPOSE\_FILE - -Specify the path to a Compose file. If not provided, Compose looks for a file named -`docker-compose.yml` in the current directory and then each parent directory in -succession until a file by that name is found. - -This variable supports multiple compose files separate by a path separator (on -Linux and OSX the path separator is `:`, on Windows it is `;`). For example: -`COMPOSE_FILE=docker-compose.yml:docker-compose.prod.yml` - -See also the `-f` [command-line option](overview.md). - -## COMPOSE\_API\_VERSION - -The Docker API only supports requests from clients which report a specific -version. If you receive a `client and server don't have same version error` using -`docker-compose`, you can workaround this error by setting this environment -variable. Set the version value to match the server version. - -Setting this variable is intended as a workaround for situations where you need -to run temporarily with a mismatch between the client and server version. For -example, if you can upgrade the client but need to wait to upgrade the server. - -Running with this variable set and a known mismatch does prevent some Docker -features from working properly. The exact features that fail would depend on the -Docker client and server versions. For this reason, running with this variable -set is only intended as a workaround and it is not officially supported. - -If you run into problems running with this set, resolve the mismatch through -upgrade and remove this setting to see if your problems resolve before notifying -support. - -## DOCKER\_HOST - -Sets the URL of the `docker` daemon. As with the Docker client, defaults to `unix:///var/run/docker.sock`. - -## DOCKER\_TLS\_VERIFY - -When set to anything other than an empty string, enables TLS communication with -the `docker` daemon. - -## DOCKER\_CERT\_PATH - -Configures the path to the `ca.pem`, `cert.pem`, and `key.pem` files used for TLS verification. Defaults to `~/.docker`. - -## COMPOSE\_HTTP\_TIMEOUT - -Configures the time (in seconds) a request to the Docker daemon is allowed to hang before Compose considers -it failed. Defaults to 60 seconds. - -## COMPOSE\_TLS\_VERSION - -Configure which TLS version is used for TLS communication with the `docker` -daemon. Defaults to `TLSv1`. -Supported values are: `TLSv1`, `TLSv1_1`, `TLSv1_2`. - -## Related Information - -- [User guide](../index.md) -- [Installing Compose](../install.md) -- [Compose file reference](../compose-file.md) -- [Environment file](../env-file.md) diff --git a/compose/reference/events.md b/compose/reference/events.md deleted file mode 100644 index 827258f249..0000000000 --- a/compose/reference/events.md +++ /dev/null @@ -1,34 +0,0 @@ - - -# events - -``` -Usage: events [options] [SERVICE...] - -Options: - --json Output events as a stream of json objects -``` - -Stream container events for every container in the project. - -With the `--json` flag, a json object will be printed one per line with the -format: - -``` -{ - "service": "web", - "event": "create", - "container": "213cf75fc39a", - "image": "alpine:edge", - "time": "2015-11-20T18:01:03.615550", -} -``` diff --git a/compose/reference/exec.md b/compose/reference/exec.md deleted file mode 100644 index 6c0eeb04dc..0000000000 --- a/compose/reference/exec.md +++ /dev/null @@ -1,29 +0,0 @@ - - -# exec - -``` -Usage: exec [options] SERVICE COMMAND [ARGS...] - -Options: --d Detached mode: Run command in the background. ---privileged Give extended privileges to the process. ---user USER Run the command as this user. --T Disable pseudo-tty allocation. By default `docker-compose exec` - allocates a TTY. ---index=index index of the container if there are multiple - instances of a service [default: 1] -``` - -This is equivalent of `docker exec`. With this subcommand you can run arbitrary -commands in your services. Commands are by default allocating a TTY, so you can -do e.g. `docker-compose exec web sh` to get an interactive prompt. diff --git a/compose/reference/help.md b/compose/reference/help.md deleted file mode 100644 index 613708ed2f..0000000000 --- a/compose/reference/help.md +++ /dev/null @@ -1,18 +0,0 @@ - - -# help - -``` -Usage: help COMMAND -``` - -Displays help and usage instructions for a command. diff --git a/compose/reference/index.md b/compose/reference/index.md deleted file mode 100644 index 2ac3676af0..0000000000 --- a/compose/reference/index.md +++ /dev/null @@ -1,42 +0,0 @@ - - -## Compose command-line reference - -The following pages describe the usage information for the [docker-compose](overview.md) subcommands. You can also see this information by running `docker-compose [SUBCOMMAND] --help` from the command line. - -* [docker-compose](overview.md) -* [build](build.md) -* [config](config.md) -* [create](create.md) -* [down](down.md) -* [events](events.md) -* [help](help.md) -* [kill](kill.md) -* [logs](logs.md) -* [pause](pause.md) -* [port](port.md) -* [ps](ps.md) -* [pull](pull.md) -* [restart](restart.md) -* [rm](rm.md) -* [run](run.md) -* [scale](scale.md) -* [start](start.md) -* [stop](stop.md) -* [unpause](unpause.md) -* [up](up.md) - -## Where to go next - -* [CLI environment variables](envvars.md) -* [docker-compose Command](overview.md) diff --git a/compose/reference/kill.md b/compose/reference/kill.md deleted file mode 100644 index dc4bf23a1b..0000000000 --- a/compose/reference/kill.md +++ /dev/null @@ -1,24 +0,0 @@ - - -# kill - -``` -Usage: kill [options] [SERVICE...] - -Options: --s SIGNAL SIGNAL to send to the container. Default signal is SIGKILL. -``` - -Forces running containers to stop by sending a `SIGKILL` signal. Optionally the -signal can be passed, for example: - - $ docker-compose kill -s SIGINT diff --git a/compose/reference/logs.md b/compose/reference/logs.md deleted file mode 100644 index 745d24f7fe..0000000000 --- a/compose/reference/logs.md +++ /dev/null @@ -1,25 +0,0 @@ - - -# logs - -``` -Usage: logs [options] [SERVICE...] - -Options: ---no-color Produce monochrome output. --f, --follow Follow log output --t, --timestamps Show timestamps ---tail Number of lines to show from the end of the logs - for each container. -``` - -Displays log output from services. diff --git a/compose/reference/overview.md b/compose/reference/overview.md deleted file mode 100644 index d59fa56575..0000000000 --- a/compose/reference/overview.md +++ /dev/null @@ -1,127 +0,0 @@ - - - -# Overview of docker-compose CLI - -This page provides the usage information for the `docker-compose` Command. -You can also see this information by running `docker-compose --help` from the -command line. - -``` -Define and run multi-container applications with Docker. - -Usage: - docker-compose [-f=...] [options] [COMMAND] [ARGS...] - docker-compose -h|--help - -Options: - -f, --file FILE Specify an alternate compose file (default: docker-compose.yml) - -p, --project-name NAME Specify an alternate project name (default: directory name) - --verbose Show more output - -v, --version Print version and exit - -H, --host HOST Daemon socket to connect to - - --tls Use TLS; implied by --tlsverify - --tlscacert CA_PATH Trust certs signed only by this CA - --tlscert CLIENT_CERT_PATH Path to TLS certificate file - --tlskey TLS_KEY_PATH Path to TLS key file - --tlsverify Use TLS and verify the remote - --skip-hostname-check Don't check the daemon's hostname against the name specified - in the client certificate (for example if your docker host - is an IP address) - -Commands: - build Build or rebuild services - config Validate and view the compose file - create Create services - down Stop and remove containers, networks, images, and volumes - events Receive real time events from containers - help Get help on a command - kill Kill containers - logs View output from containers - pause Pause services - port Print the public port for a port binding - ps List containers - pull Pulls service images - restart Restart services - rm Remove stopped containers - run Run a one-off command - scale Set number of containers for a service - start Start services - stop Stop services - unpause Unpause services - up Create and start containers - version Show the Docker-Compose version information - -``` - -The Docker Compose binary. You use this command to build and manage multiple -services in Docker containers. - -Use the `-f` flag to specify the location of a Compose configuration file. You -can supply multiple `-f` configuration files. When you supply multiple files, -Compose combines them into a single configuration. Compose builds the -configuration in the order you supply the files. Subsequent files override and -add to their successors. - -For example, consider this command line: - -``` -$ docker-compose -f docker-compose.yml -f docker-compose.admin.yml run backup_db` -``` - -The `docker-compose.yml` file might specify a `webapp` service. - -``` -webapp: - image: examples/web - ports: - - "8000:8000" - volumes: - - "/data" -``` - -If the `docker-compose.admin.yml` also specifies this same service, any matching -fields will override the previous file. New values, add to the `webapp` service -configuration. - -``` -webapp: - build: . - environment: - - DEBUG=1 -``` - -Use a `-f` with `-` (dash) as the filename to read the configuration from -stdin. When stdin is used all paths in the configuration are -relative to the current working directory. - -The `-f` flag is optional. If you don't provide this flag on the command line, -Compose traverses the working directory and its parent directories looking for a -`docker-compose.yml` and a `docker-compose.override.yml` file. You must -supply at least the `docker-compose.yml` file. If both files are present on the -same directory level, Compose combines the two files into a single configuration. -The configuration in the `docker-compose.override.yml` file is applied over and -in addition to the values in the `docker-compose.yml` file. - -See also the `COMPOSE_FILE` [environment variable](envvars.md#compose-file). - -Each configuration has a project name. If you supply a `-p` flag, you can -specify a project name. If you don't specify the flag, Compose uses the current -directory name. See also the `COMPOSE_PROJECT_NAME` [environment variable]( -envvars.md#compose-project-name) - - -## Where to go next - -* [CLI environment variables](envvars.md) diff --git a/compose/reference/pause.md b/compose/reference/pause.md deleted file mode 100644 index a0ffab0359..0000000000 --- a/compose/reference/pause.md +++ /dev/null @@ -1,18 +0,0 @@ - - -# pause - -``` -Usage: pause [SERVICE...] -``` - -Pauses running containers of a service. They can be unpaused with `docker-compose unpause`. diff --git a/compose/reference/port.md b/compose/reference/port.md deleted file mode 100644 index c946a97d39..0000000000 --- a/compose/reference/port.md +++ /dev/null @@ -1,23 +0,0 @@ - - -# port - -``` -Usage: port [options] SERVICE PRIVATE_PORT - -Options: ---protocol=proto tcp or udp [default: tcp] ---index=index index of the container if there are multiple - instances of a service [default: 1] -``` - -Prints the public port for a port binding. diff --git a/compose/reference/ps.md b/compose/reference/ps.md deleted file mode 100644 index 546d68e76c..0000000000 --- a/compose/reference/ps.md +++ /dev/null @@ -1,21 +0,0 @@ - - -# ps - -``` -Usage: ps [options] [SERVICE...] - -Options: --q Only display IDs -``` - -Lists containers. diff --git a/compose/reference/pull.md b/compose/reference/pull.md deleted file mode 100644 index 5ec184b72c..0000000000 --- a/compose/reference/pull.md +++ /dev/null @@ -1,21 +0,0 @@ - - -# pull - -``` -Usage: pull [options] [SERVICE...] - -Options: ---ignore-pull-failures Pull what it can and ignores images with pull failures. -``` - -Pulls service images. diff --git a/compose/reference/push.md b/compose/reference/push.md deleted file mode 100644 index bdc3112e83..0000000000 --- a/compose/reference/push.md +++ /dev/null @@ -1,21 +0,0 @@ - - -# push - -``` -Usage: push [options] [SERVICE...] - -Options: - --ignore-push-failures Push what it can and ignores images with push failures. -``` - -Pushes images for services. diff --git a/compose/reference/restart.md b/compose/reference/restart.md deleted file mode 100644 index bbd4a68b0f..0000000000 --- a/compose/reference/restart.md +++ /dev/null @@ -1,21 +0,0 @@ - - -# restart - -``` -Usage: restart [options] [SERVICE...] - -Options: --t, --timeout TIMEOUT Specify a shutdown timeout in seconds. (default: 10) -``` - -Restarts services. diff --git a/compose/reference/rm.md b/compose/reference/rm.md deleted file mode 100644 index 8285a4ae52..0000000000 --- a/compose/reference/rm.md +++ /dev/null @@ -1,29 +0,0 @@ - - -# rm - -``` -Usage: rm [options] [SERVICE...] - -Options: - -f, --force Don't ask to confirm removal - -v Remove any anonymous volumes attached to containers - -a, --all Also remove one-off containers created by - docker-compose run -``` - -Removes stopped service containers. - -By default, anonymous volumes attached to containers will not be removed. You -can override this with `-v`. To list all volumes, use `docker volume ls`. - -Any data which is not in a volume will be lost. diff --git a/compose/reference/run.md b/compose/reference/run.md deleted file mode 100644 index 863544246d..0000000000 --- a/compose/reference/run.md +++ /dev/null @@ -1,56 +0,0 @@ - - -# run - -``` -Usage: run [options] [-e KEY=VAL...] SERVICE [COMMAND] [ARGS...] - -Options: --d Detached mode: Run container in the background, print - new container name. ---name NAME Assign a name to the container ---entrypoint CMD Override the entrypoint of the image. --e KEY=VAL Set an environment variable (can be used multiple times) --u, --user="" Run as specified username or uid ---no-deps Don't start linked services. ---rm Remove container after run. Ignored in detached mode. --p, --publish=[] Publish a container's port(s) to the host ---service-ports Run command with the service's ports enabled and mapped to the host. --T Disable pseudo-tty allocation. By default `docker-compose run` allocates a TTY. --w, --workdir="" Working directory inside the container -``` - -Runs a one-time command against a service. For example, the following command starts the `web` service and runs `bash` as its command. - - $ docker-compose run web bash - -Commands you use with `run` start in new containers with the same configuration as defined by the service' configuration. This means the container has the same volumes, links, as defined in the configuration file. There two differences though. - -First, the command passed by `run` overrides the command defined in the service configuration. For example, if the `web` service configuration is started with `bash`, then `docker-compose run web python app.py` overrides it with `python app.py`. - -The second difference is the `docker-compose run` command does not create any of the ports specified in the service configuration. This prevents the port collisions with already open ports. If you *do want* the service's ports created and mapped to the host, specify the `--service-ports` flag: - - $ docker-compose run --service-ports web python manage.py shell - -Alternatively manual port mapping can be specified. Same as when running Docker's `run` command - using `--publish` or `-p` options: - - $ docker-compose run --publish 8080:80 -p 2022:22 -p 127.0.0.1:2021:21 web python manage.py shell - -If you start a service configured with links, the `run` command first checks to see if the linked service is running and starts the service if it is stopped. Once all the linked services are running, the `run` executes the command you passed it. So, for example, you could run: - - $ docker-compose run db psql -h db -U docker - -This would open up an interactive PostgreSQL shell for the linked `db` container. - -If you do not want the `run` command to start linked containers, specify the `--no-deps` flag: - - $ docker-compose run --no-deps web python manage.py shell diff --git a/compose/reference/scale.md b/compose/reference/scale.md deleted file mode 100644 index 75140ee9e5..0000000000 --- a/compose/reference/scale.md +++ /dev/null @@ -1,21 +0,0 @@ - - -# scale - -``` -Usage: scale [SERVICE=NUM...] -``` - -Sets the number of containers to run for a service. - -Numbers are specified as arguments in the form `service=num`. For example: - - $ docker-compose scale web=2 worker=3 diff --git a/compose/reference/start.md b/compose/reference/start.md deleted file mode 100644 index f0bdd5a97c..0000000000 --- a/compose/reference/start.md +++ /dev/null @@ -1,18 +0,0 @@ - - -# start - -``` -Usage: start [SERVICE...] -``` - -Starts existing containers for a service. diff --git a/compose/reference/stop.md b/compose/reference/stop.md deleted file mode 100644 index ec7e6688a5..0000000000 --- a/compose/reference/stop.md +++ /dev/null @@ -1,22 +0,0 @@ - - -# stop - -``` -Usage: stop [options] [SERVICE...] - -Options: --t, --timeout TIMEOUT Specify a shutdown timeout in seconds (default: 10). -``` - -Stops running containers without removing them. They can be started again with -`docker-compose start`. diff --git a/compose/reference/unpause.md b/compose/reference/unpause.md deleted file mode 100644 index 846b229e3c..0000000000 --- a/compose/reference/unpause.md +++ /dev/null @@ -1,18 +0,0 @@ - - -# unpause - -``` -Usage: unpause [SERVICE...] -``` - -Unpauses paused containers of a service. diff --git a/compose/reference/up.md b/compose/reference/up.md deleted file mode 100644 index 3951f87925..0000000000 --- a/compose/reference/up.md +++ /dev/null @@ -1,55 +0,0 @@ - - -# up - -``` -Usage: up [options] [SERVICE...] - -Options: - -d Detached mode: Run containers in the background, - print new container names. - Incompatible with --abort-on-container-exit. - --no-color Produce monochrome output. - --no-deps Don't start linked services. - --force-recreate Recreate containers even if their configuration - and image haven't changed. - Incompatible with --no-recreate. - --no-recreate If containers already exist, don't recreate them. - Incompatible with --force-recreate. - --no-build Don't build an image, even if it's missing. - --build Build images before starting containers. - --abort-on-container-exit Stops all containers if any container was stopped. - Incompatible with -d. - -t, --timeout TIMEOUT Use this timeout in seconds for container shutdown - when attached or when containers are already - running. (default: 10) - --remove-orphans Remove containers for services not defined in - the Compose file - -``` - -Builds, (re)creates, starts, and attaches to containers for a service. - -Unless they are already running, this command also starts any linked services. - -The `docker-compose up` command aggregates the output of each container. When -the command exits, all containers are stopped. Running `docker-compose up -d` -starts the containers in the background and leaves them running. - -If there are existing containers for a service, and the service's configuration -or image was changed after the container's creation, `docker-compose up` picks -up the changes by stopping and recreating the containers (preserving mounted -volumes). To prevent Compose from picking up changes, use the `--no-recreate` -flag. - -If you want to force Compose to stop and recreate all containers, use the -`--force-recreate` flag. diff --git a/compose/startup-order.md b/compose/startup-order.md deleted file mode 100644 index c67e18295a..0000000000 --- a/compose/startup-order.md +++ /dev/null @@ -1,88 +0,0 @@ - - -# Controlling startup order in Compose - -You can control the order of service startup with the -[depends_on](compose-file.md#depends-on) option. Compose always starts -containers in dependency order, where dependencies are determined by -`depends_on`, `links`, `volumes_from` and `network_mode: "service:..."`. - -However, Compose will not wait until a container is "ready" (whatever that means -for your particular application) - only until it's running. There's a good -reason for this. - -The problem of waiting for a database (for example) to be ready is really just -a subset of a much larger problem of distributed systems. In production, your -database could become unavailable or move hosts at any time. Your application -needs to be resilient to these types of failures. - -To handle this, your application should attempt to re-establish a connection to -the database after a failure. If the application retries the connection, -it should eventually be able to connect to the database. - -The best solution is to perform this check in your application code, both at -startup and whenever a connection is lost for any reason. However, if you don't -need this level of resilience, you can work around the problem with a wrapper -script: - -- Use a tool such as [wait-for-it](https://github.com/vishnubob/wait-for-it) - or [dockerize](https://github.com/jwilder/dockerize). These are small - wrapper scripts which you can include in your application's image and will - poll a given host and port until it's accepting TCP connections. - - Supposing your application's image has a `CMD` set in its Dockerfile, you - can wrap it by setting the entrypoint in `docker-compose.yml`: - - version: "2" - services: - web: - build: . - ports: - - "80:8000" - depends_on: - - "db" - entrypoint: ./wait-for-it.sh db:5432 - db: - image: postgres - -- Write your own wrapper script to perform a more application-specific health - check. For example, you might want to wait until Postgres is definitely - ready to accept commands: - - #!/bin/bash - - set -e - - host="$1" - shift - cmd="$@" - - until psql -h "$host" -U "postgres" -c '\l'; do - >&2 echo "Postgres is unavailable - sleeping" - sleep 1 - done - - >&2 echo "Postgres is up - executing command" - exec $cmd - - You can use this as a wrapper script as in the previous example, by setting - `entrypoint: ./wait-for-postgres.sh db`. - - -## Compose documentation - -- [Installing Compose](install.md) -- [Get started with Django](django.md) -- [Get started with Rails](rails.md) -- [Get started with WordPress](wordpress.md) -- [Command line reference](./reference/index.md) -- [Compose file reference](compose-file.md) diff --git a/compose/swarm.md b/compose/swarm.md deleted file mode 100644 index bbab690879..0000000000 --- a/compose/swarm.md +++ /dev/null @@ -1,181 +0,0 @@ - - - -# Using Compose with Swarm - -Docker Compose and [Docker Swarm](/swarm/overview.md) aim to have full integration, meaning -you can point a Compose app at a Swarm cluster and have it all just work as if -you were using a single Docker host. - -The actual extent of integration depends on which version of the [Compose file -format](compose-file.md#versioning) you are using: - -1. If you're using version 1 along with `links`, your app will work, but Swarm - will schedule all containers on one host, because links between containers - do not work across hosts with the old networking system. - -2. If you're using version 2, your app should work with no changes: - - - subject to the [limitations](#limitations) described below, - - - as long as the Swarm cluster is configured to use the [overlay driver](https://docs.docker.com/engine/userguide/networking/dockernetworks/#an-overlay-network), - or a custom driver which supports multi-host networking. - -Read [Get started with multi-host networking](https://docs.docker.com/engine/userguide/networking/get-started-overlay/) to see how to -set up a Swarm cluster with [Docker Machine](/machine/overview.md) and the overlay driver. Once you've got it running, deploying your app to it should be as simple as: - - $ eval "$(docker-machine env --swarm )" - $ docker-compose up - - -## Limitations - -### Building images - -Swarm can build an image from a Dockerfile just like a single-host Docker -instance can, but the resulting image will only live on a single node and won't -be distributed to other nodes. - -If you want to use Compose to scale the service in question to multiple nodes, -you'll have to build it yourself, push it to a registry (e.g. the Docker Hub) -and reference it from `docker-compose.yml`: - - $ docker build -t myusername/web . - $ docker push myusername/web - - $ cat docker-compose.yml - web: - image: myusername/web - - $ docker-compose up -d - $ docker-compose scale web=3 - -### Multiple dependencies - -If a service has multiple dependencies of the type which force co-scheduling -(see [Automatic scheduling](#automatic-scheduling) below), it's possible that -Swarm will schedule the dependencies on different nodes, making the dependent -service impossible to schedule. For example, here `foo` needs to be co-scheduled -with `bar` and `baz`: - - version: "2" - services: - foo: - image: foo - volumes_from: ["bar"] - network_mode: "service:baz" - bar: - image: bar - baz: - image: baz - -The problem is that Swarm might first schedule `bar` and `baz` on different -nodes (since they're not dependent on one another), making it impossible to -pick an appropriate node for `foo`. - -To work around this, use [manual scheduling](#manual-scheduling) to ensure that -all three services end up on the same node: - - version: "2" - services: - foo: - image: foo - volumes_from: ["bar"] - network_mode: "service:baz" - environment: - - "constraint:node==node-1" - bar: - image: bar - environment: - - "constraint:node==node-1" - baz: - image: baz - environment: - - "constraint:node==node-1" - -### Host ports and recreating containers - -If a service maps a port from the host, e.g. `80:8000`, then you may get an -error like this when running `docker-compose up` on it after the first time: - - docker: Error response from daemon: unable to find a node that satisfies - container==6ab2dfe36615ae786ef3fc35d641a260e3ea9663d6e69c5b70ce0ca6cb373c02. - -The usual cause of this error is that the container has a volume (defined either -in its image or in the Compose file) without an explicit mapping, and so in -order to preserve its data, Compose has directed Swarm to schedule the new -container on the same node as the old container. This results in a port clash. - -There are two viable workarounds for this problem: - -- Specify a named volume, and use a volume driver which is capable of mounting - the volume into the container regardless of what node it's scheduled on. - - Compose does not give Swarm any specific scheduling instructions if a - service uses only named volumes. - - version: "2" - - services: - web: - build: . - ports: - - "80:8000" - volumes: - - web-logs:/var/log/web - - volumes: - web-logs: - driver: custom-volume-driver - -- Remove the old container before creating the new one. You will lose any data - in the volume. - - $ docker-compose stop web - $ docker-compose rm -f web - $ docker-compose up web - - -## Scheduling containers - -### Automatic scheduling - -Some configuration options will result in containers being automatically -scheduled on the same Swarm node to ensure that they work correctly. These are: - -- `network_mode: "service:..."` and `network_mode: "container:..."` (and - `net: "container:..."` in the version 1 file format). - -- `volumes_from` - -- `links` - -### Manual scheduling - -Swarm offers a rich set of scheduling and affinity hints, enabling you to -control where containers are located. They are specified via container -environment variables, so you can use Compose's `environment` option to set -them. - - # Schedule containers on a specific node - environment: - - "constraint:node==node-1" - - # Schedule containers on a node that has the 'storage' label set to 'ssd' - environment: - - "constraint:storage==ssd" - - # Schedule containers where the 'redis' image is already pulled - environment: - - "affinity:image==redis" - -For the full set of available filters and expressions, see the [Swarm -documentation](/swarm/scheduler/filter.md). diff --git a/compose/wordpress.md b/compose/wordpress.md deleted file mode 100644 index b39a8bbbe6..0000000000 --- a/compose/wordpress.md +++ /dev/null @@ -1,112 +0,0 @@ - - - -# Quickstart: Docker Compose and WordPress - -You can use Docker Compose to easily run WordPress in an isolated environment built -with Docker containers. This quick-start guide demonstrates how to use Compose to set up and run WordPress. Before starting, you'll need to have -[Compose installed](install.md). - -### Define the project - -1. Create an empty project directory. - - You can name the directory something easy for you to remember. This directory is the context for your application image. The directory should only contain resources to build that image. - - This project directory will contain a `docker-compose.yaml` file which will be complete in itself for a good starter wordpress project. - -2. Change directories into your project directory. - - For example, if you named your directory `my_wordpress`: - - $ cd my-wordpress/ - -3. Create a `docker-compose.yml` file that will start your `Wordpress` blog and a separate `MySQL` instance with a volume mount for data persistence: - - version: '2' - services: - db: - image: mysql:5.7 - volumes: - - "./.data/db:/var/lib/mysql" - restart: always - environment: - MYSQL_ROOT_PASSWORD: wordpress - MYSQL_DATABASE: wordpress - MYSQL_USER: wordpress - MYSQL_PASSWORD: wordpress - - wordpress: - depends_on: - - db - image: wordpress:latest - links: - - db - ports: - - "8000:80" - restart: always - environment: - WORDPRESS_DB_HOST: db:3306 - WORDPRESS_DB_PASSWORD: wordpress - - **NOTE**: The folder `./.data/db` will be automatically created in the project directory - alongside the `docker-compose.yml` which will persist any updates made by wordpress to the - database. - -### Build the project - -Now, run `docker-compose up -d` from your project directory. - -This pulls the needed images, and starts the wordpress and database containers, as shown in the example below. - - $ docker-compose up -d - Creating network "my_wordpress_default" with the default driver - Pulling db (mysql:5.7)... - 5.7: Pulling from library/mysql - efd26ecc9548: Pull complete - a3ed95caeb02: Pull complete - ... - Digest: sha256:34a0aca88e85f2efa5edff1cea77cf5d3147ad93545dbec99cfe705b03c520de - Status: Downloaded newer image for mysql:5.7 - Pulling wordpress (wordpress:latest)... - latest: Pulling from library/wordpress - efd26ecc9548: Already exists - a3ed95caeb02: Pull complete - 589a9d9a7c64: Pull complete - ... - Digest: sha256:ed28506ae44d5def89075fd5c01456610cd6c64006addfe5210b8c675881aff6 - Status: Downloaded newer image for wordpress:latest - Creating my_wordpress_db_1 - Creating my_wordpress_wordpress_1 - -### Bring up WordPress in a web browser - -If you're using [Docker Machine](https://docs.docker.com/machine/), then `docker-machine ip MACHINE_VM` gives you the machine address and you can open `http://MACHINE_VM_IP:8000` in a browser. - -At this point, WordPress should be running on port `8000` of your Docker Host, and you can complete the "famous five-minute installation" as a WordPress administrator. - -**NOTE**: The Wordpress site will not be immediately available on port `8000` because the containers are still being initialized and may take a couple of minutes before the first load. - -![Choose language for WordPress install](images/wordpress-lang.png) - -![WordPress Welcome](images/wordpress-welcome.png) - - -## More Compose documentation - -- [User guide](index.md) -- [Installing Compose](install.md) -- [Getting Started](gettingstarted.md) -- [Get started with Django](django.md) -- [Get started with Rails](rails.md) -- [Command line reference](./reference/index.md) -- [Compose file reference](compose-file.md) diff --git a/containers/README.md b/containers/README.md deleted file mode 100644 index 6cb24e12b8..0000000000 --- a/containers/README.md +++ /dev/null @@ -1,48 +0,0 @@ - -# Containers - -These are the "accessory" containers with which Hub 2.0 is run. - -## dnsmasq - -dnsmasq is used to fake the `Origin` header in CORS requests. This is -necessary because the browser automatically sends `Origin: localhost` -(users can't modify it) and we need it to be in the `*.docker.com` -space, since staging is set up to handle single dot subdomains. - -We've chosen `bagels.docker.com` as the development domain (something -that is unlikely to ever be deployed in production so that we won't -have to change the name in the future). - -### prerequisites - -```bash -cd $PROJECT -make dns -``` - -This runs `$PROJECT/containers/configure_system_dns.sh`, which will -add `bagels.docker.com` to your host system's `/etc/resolver/`. This -makes it so that `bagels.docker.com` will resolver to `boot2docker ip`. - -### run - -```bash -cd $PROJECT/containers/dnsmasq -docker build -t bagelteam/dnsmasq -docker run -itp 53:53/udp bagelteam/dnsmasq -``` - -## HAProxy - -HAProxy is a load balancer used to terminate SSL. - -Currently Out-of-Order. - -```bash -docker run -itp 80:80 -p 443:433 bagelteam/haproxy -``` - -HAProxy will load balance `bagels.docker.com` across a single -container (hah), and more importantly, take care of SSL Offloading at -the load balancer. The image has it's own SSL certificates. diff --git a/containers/dnsmasq/Dockerfile b/containers/dnsmasq/Dockerfile deleted file mode 100644 index 40c00e83d5..0000000000 --- a/containers/dnsmasq/Dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM debian:jessie - -MAINTAINER Chris Biscardi - -RUN apt-get update && apt-get install -y dnsmasq - -EXPOSE 53/udp - -ADD ./run /opt/run - -CMD "/opt/run" -# docker run -d -p 53:53/udp --name docker-dnsmasq dnsmasq --address=/dev.docker.io/172.16.200.100 diff --git a/containers/dnsmasq/configure_system_dns.sh b/containers/dnsmasq/configure_system_dns.sh deleted file mode 100755 index d84112198a..0000000000 --- a/containers/dnsmasq/configure_system_dns.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash - -# Docker Bridge IP - https://docs.docker.com/articles/networking/ -# $DOCKER_HOST will be the IP of the boot2docker or docker-machine -# instance *currently sourced in your shell*. This means something -# like $(docker-machine env dev) or $(boot2docker shellinit) -if [[ $DOCKER_HOST =~ ([0-9]{1,3}[\.]){3}[0-9]{1,3} ]]; then - DAEMON_IPV4=$BASH_REMATCH - echo $DAEMON_IPV4 -else - echo "unable to parse string $DOCKER_HOST" -fi - -set_dev_resolver() { - echo "Bagels need your permission to configure system DNS." - sudo mkdir -p /etc/resolver - echo "nameserver $DAEMON_IPV4" | sudo tee /etc/resolver/bagels.docker.com -} - -if [ ! -f /etc/resolver/bagels.docker.com ]; then - set_dev_resolver -elif [ "$(cat /etc/resolver/bagels.docker.com)" != "nameserver $DAEMON_IPV4" ]; then - set_dev_resolver -fi diff --git a/containers/dnsmasq/run b/containers/dnsmasq/run deleted file mode 100755 index b2b60ad240..0000000000 --- a/containers/dnsmasq/run +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -# match the ip address from a DOCKER_HOST which is set by boot2docker -# and docker-machine -if [[ $DOCKER_HOST =~ ([0-9]{1,3}[\.]){3}[0-9]{1,3} ]]; then - strresult=$BASH_REMATCH - echo $strresult -else - echo "unable to parse string $DOCKER_HOST" -fi - -/usr/sbin/dnsmasq -q --no-daemon --address=/bagels.docker.com/$strresult -#$strresult diff --git a/containers/haproxy/Dockerfile b/containers/haproxy/Dockerfile deleted file mode 100644 index 034260c7e2..0000000000 --- a/containers/haproxy/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM fish/haproxy - -ADD . /haproxy - -EXPOSE 80 443 - -# Check is haproxy.cfg is valid before we start -# CMD "(haproxy -c -f /haproxy/haproxy.cfg || ( echo 'Bad haproxy config'; exit; )) && /usr/sbin/haproxy -f /haproxy/haproxy.cfg & && wait $!" - -ENTRYPOINT ["/haproxy/run"] \ No newline at end of file diff --git a/containers/haproxy/haproxy.cfg b/containers/haproxy/haproxy.cfg deleted file mode 100644 index b9d1c5014a..0000000000 --- a/containers/haproxy/haproxy.cfg +++ /dev/null @@ -1,41 +0,0 @@ -global - chroot /var/lib/haproxy - user haproxy - group haproxy - -defaults - log global - mode http - option httplog - option dontlognull - timeout connect 5000 - timeout client 50000 - timeout server 50000 - errorfile 400 /etc/haproxy/errors/400.http - errorfile 403 /etc/haproxy/errors/403.http - errorfile 408 /etc/haproxy/errors/408.http - errorfile 500 /etc/haproxy/errors/500.http - errorfile 502 /etc/haproxy/errors/502.http - errorfile 503 /etc/haproxy/errors/503.http - errorfile 504 /etc/haproxy/errors/504.http - stats enable - stats auth haproxy:hapass - -frontend https - bind :443 ssl crt /haproxy/keys/bagels.docker.com/bagels.docker.pem - acl is-ssl dst_port 443 - - http-request set-header X-Real-IP %ci - - reqadd X-Forwarded-Proto:\ https if is-ssl - reqadd X-Forwarded-Port:\ 443 if is-ssl - rspadd Strict-Transport-Security:\ max-age=31536000 if is-ssl - - acl is_hub_dev hdr(host) -i bagels.docker.com - - use_backend hub_dev if is_hub_dev - -backend hub_dev - balance leastconn - option httpclose - server docker-1 {DOCKER_HOST}:7001 check \ No newline at end of file diff --git a/containers/haproxy/keys/bagels.docker.com/bagels.docker.crt b/containers/haproxy/keys/bagels.docker.com/bagels.docker.crt deleted file mode 100644 index 44765408fb..0000000000 --- a/containers/haproxy/keys/bagels.docker.com/bagels.docker.crt +++ /dev/null @@ -1,14 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICNTCCAZ4CCQDY33gN8y9BQzANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJV -UzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xDzANBgNVBAoT -BkRvY2tlcjEaMBgGA1UEAxMRYmFnZWxzLmRvY2tlci5jb20wHhcNMTUwMTIxMDM1 -NTEzWhcNMTYwMTIxMDM1NTEzWjBfMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0Ex -FjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xDzANBgNVBAoTBkRvY2tlcjEaMBgGA1UE -AxMRYmFnZWxzLmRvY2tlci5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGB -AMluBCvOUrdFkFGCmpKBPduoZgYE/hNKnmX3Cqrn+FsodOBiin1lOs7+XX3EY078 -u5QIULNZ3j/LUSuxgHBS8RcVc3ljCkvwRURwVy6FWunahdTULLEq+qOByv6Hq2/W -itlzT2Rw6Tu29IThb7Mtxb1B6LoAorkWX/YEXankpVPnAgMBAAEwDQYJKoZIhvcN -AQEFBQADgYEAPdqZ2jLxOuZ52wucJN1DoOBUCWnCM5bfBHOU3wBqSPA/mT2Bw5Fo -evqqd+mRWizgmSkDM9NpO9cj9tpeidTrHsTutkqjQttIeNAtZm82sSWH7ul1N1du -4aDDKwAk4j9BYPUmYQFaSRKNtE/OpGVPxxK/ZBS8YeVT0knzTr/a9to= ------END CERTIFICATE----- diff --git a/containers/haproxy/keys/bagels.docker.com/bagels.docker.csr b/containers/haproxy/keys/bagels.docker.com/bagels.docker.csr deleted file mode 100644 index b9d96abb7e..0000000000 --- a/containers/haproxy/keys/bagels.docker.com/bagels.docker.csr +++ /dev/null @@ -1,11 +0,0 @@ ------BEGIN CERTIFICATE REQUEST----- -MIIBnzCCAQgCAQAwXzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQH -Ew1TYW4gRnJhbmNpc2NvMQ8wDQYDVQQKEwZEb2NrZXIxGjAYBgNVBAMTEWJhZ2Vs -cy5kb2NrZXIuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJbgQrzlK3 -RZBRgpqSgT3bqGYGBP4TSp5l9wqq5/hbKHTgYop9ZTrO/l19xGNO/LuUCFCzWd4/ -y1ErsYBwUvEXFXN5YwpL8EVEcFcuhVrp2oXU1CyxKvqjgcr+h6tv1orZc09kcOk7 -tvSE4W+zLcW9Qei6AKK5Fl/2BF2p5KVT5wIDAQABoAAwDQYJKoZIhvcNAQEFBQAD -gYEAlAQKhy4j7wenWqnKzfpp/o0cbzQAcve76XSwfWrzONFDZidhQlwAKBdYbYN3 -4ITqNw4MPSCMBkMMCQFFFHM/+NqlAmYYbJHv8uDxKel/7IsxIEPRun0b6k/+wL2e -2nyJJrMwesVrzvDwfB+8eoUOZFJIiX6htpxU4vgq9xMgMAg= ------END CERTIFICATE REQUEST----- diff --git a/containers/haproxy/keys/bagels.docker.com/bagels.docker.key b/containers/haproxy/keys/bagels.docker.com/bagels.docker.key deleted file mode 100644 index 6659dc144c..0000000000 --- a/containers/haproxy/keys/bagels.docker.com/bagels.docker.key +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIICWwIBAAKBgQDJbgQrzlK3RZBRgpqSgT3bqGYGBP4TSp5l9wqq5/hbKHTgYop9 -ZTrO/l19xGNO/LuUCFCzWd4/y1ErsYBwUvEXFXN5YwpL8EVEcFcuhVrp2oXU1Cyx -Kvqjgcr+h6tv1orZc09kcOk7tvSE4W+zLcW9Qei6AKK5Fl/2BF2p5KVT5wIDAQAB -AoGAcA+Qqn5Cbkt5Gp+6Nr9IFqf8+mRUpY7hyIBDowkiljRPsXWg7loe+YFxqcJU -LWFVSenGW8Enb/5AzjoV5md+UAiERbF13SzrEx7J7riwb1ljHe82RqUbyfpnnDWT -aSZ/ce+9LYoYggFVfH7DloT8NNsQzTDi2/g+66dXi8fcIIECQQDqykIcF20sz8Ar -H3StlgITEorJiZRpvbzuQ6G7XoC1XOI1/0+1NbIHm3lv4XfvaRSdKv0mnPaZmi3h -PWZC/zj3AkEA26BE6iEGO3eJ39l1zRpB1jS/VrEAa7pzGeEFeL+k/5XEWqsgHOtQ -qIbPtCyKcN5mtCYEg6GEK/pqNALWL6ZwkQJATT9CRO/IMaggd4+f2cSy5geBthEX -zTppwJJr0bOj8QegPVfEp8AE1M/oQlESHqiZ6aPNKjkWQS8izSpgTMafvQJAILDT -cTInNlTNvfcldLkS0aqaTHIeSOrA1TpMUTPdgHmvd3t/VS6lm+AtLHlwxeokyW3b -QCibftxQUJuXfBI/MQJAAt2m8P0V+U/MFjNhYUd2jwJIFFh7AVYeSH26NxzQMgO0 -YNQAaRKxwuhDrxyVwezryzyBcVWKdfhCtgOK6U5mFw== ------END RSA PRIVATE KEY----- diff --git a/containers/haproxy/keys/bagels.docker.com/bagels.docker.pem b/containers/haproxy/keys/bagels.docker.com/bagels.docker.pem deleted file mode 100644 index 753429af60..0000000000 --- a/containers/haproxy/keys/bagels.docker.com/bagels.docker.pem +++ /dev/null @@ -1,29 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICNTCCAZ4CCQDY33gN8y9BQzANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJV -UzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xDzANBgNVBAoT -BkRvY2tlcjEaMBgGA1UEAxMRYmFnZWxzLmRvY2tlci5jb20wHhcNMTUwMTIxMDM1 -NTEzWhcNMTYwMTIxMDM1NTEzWjBfMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0Ex -FjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xDzANBgNVBAoTBkRvY2tlcjEaMBgGA1UE -AxMRYmFnZWxzLmRvY2tlci5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGB -AMluBCvOUrdFkFGCmpKBPduoZgYE/hNKnmX3Cqrn+FsodOBiin1lOs7+XX3EY078 -u5QIULNZ3j/LUSuxgHBS8RcVc3ljCkvwRURwVy6FWunahdTULLEq+qOByv6Hq2/W -itlzT2Rw6Tu29IThb7Mtxb1B6LoAorkWX/YEXankpVPnAgMBAAEwDQYJKoZIhvcN -AQEFBQADgYEAPdqZ2jLxOuZ52wucJN1DoOBUCWnCM5bfBHOU3wBqSPA/mT2Bw5Fo -evqqd+mRWizgmSkDM9NpO9cj9tpeidTrHsTutkqjQttIeNAtZm82sSWH7ul1N1du -4aDDKwAk4j9BYPUmYQFaSRKNtE/OpGVPxxK/ZBS8YeVT0knzTr/a9to= ------END CERTIFICATE----- ------BEGIN RSA PRIVATE KEY----- -MIICWwIBAAKBgQDJbgQrzlK3RZBRgpqSgT3bqGYGBP4TSp5l9wqq5/hbKHTgYop9 -ZTrO/l19xGNO/LuUCFCzWd4/y1ErsYBwUvEXFXN5YwpL8EVEcFcuhVrp2oXU1Cyx -Kvqjgcr+h6tv1orZc09kcOk7tvSE4W+zLcW9Qei6AKK5Fl/2BF2p5KVT5wIDAQAB -AoGAcA+Qqn5Cbkt5Gp+6Nr9IFqf8+mRUpY7hyIBDowkiljRPsXWg7loe+YFxqcJU -LWFVSenGW8Enb/5AzjoV5md+UAiERbF13SzrEx7J7riwb1ljHe82RqUbyfpnnDWT -aSZ/ce+9LYoYggFVfH7DloT8NNsQzTDi2/g+66dXi8fcIIECQQDqykIcF20sz8Ar -H3StlgITEorJiZRpvbzuQ6G7XoC1XOI1/0+1NbIHm3lv4XfvaRSdKv0mnPaZmi3h -PWZC/zj3AkEA26BE6iEGO3eJ39l1zRpB1jS/VrEAa7pzGeEFeL+k/5XEWqsgHOtQ -qIbPtCyKcN5mtCYEg6GEK/pqNALWL6ZwkQJATT9CRO/IMaggd4+f2cSy5geBthEX -zTppwJJr0bOj8QegPVfEp8AE1M/oQlESHqiZ6aPNKjkWQS8izSpgTMafvQJAILDT -cTInNlTNvfcldLkS0aqaTHIeSOrA1TpMUTPdgHmvd3t/VS6lm+AtLHlwxeokyW3b -QCibftxQUJuXfBI/MQJAAt2m8P0V+U/MFjNhYUd2jwJIFFh7AVYeSH26NxzQMgO0 -YNQAaRKxwuhDrxyVwezryzyBcVWKdfhCtgOK6U5mFw== ------END RSA PRIVATE KEY----- diff --git a/containers/haproxy/run b/containers/haproxy/run deleted file mode 100755 index b26edf0b91..0000000000 --- a/containers/haproxy/run +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -# match the ip address from a DOCKER_HOST which is set by boot2docker -# and docker-machine -if [[ $DOCKER_HOST =~ ([0-9]{1,3}[\.]){3}[0-9]{1,3} ]]; then - strresult=$BASH_REMATCH - echo $strresult -else - echo "unable to parse string $DOCKER_HOST" -fi - -sed -i s/{DOCKER_HOST}/"$strresult"/g /haproxy/haproxy.cfg - -# Check is haproxy.cfg is valid before we start -haproxy -c -f /haproxy/haproxy.cfg || ( echo 'Bad haproxy config'; exit; ) - -/usr/sbin/haproxy -f /haproxy/haproxy.cfg & - -wait $! diff --git a/containers/prod/build b/containers/prod/build deleted file mode 100755 index af29f19d61..0000000000 --- a/containers/prod/build +++ /dev/null @@ -1 +0,0 @@ -docker build -t bagel/haproxy_beta ./haproxy \ No newline at end of file diff --git a/containers/prod/docker-compose.yml b/containers/prod/docker-compose.yml deleted file mode 100644 index 838d385d12..0000000000 --- a/containers/prod/docker-compose.yml +++ /dev/null @@ -1,13 +0,0 @@ -haproxy: - build: ./haproxy - ports: - - "80:80" - - "443:443" -hub: - build: bagelteam/hubtest - volumes: - - .:/opt/hub - ports: - - "7001:3000" - environment: - ENV: production \ No newline at end of file diff --git a/containers/prod/haproxy/Dockerfile b/containers/prod/haproxy/Dockerfile deleted file mode 100644 index 12a913f9de..0000000000 --- a/containers/prod/haproxy/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -FROM fish/haproxy - -ADD ./haproxy.cfg /haproxy/haproxy.cfg -ADD ./run /haproxy/run - -EXPOSE 80 443 - -ENTRYPOINT ["/haproxy/run"] - diff --git a/containers/prod/haproxy/haproxy.cfg b/containers/prod/haproxy/haproxy.cfg deleted file mode 100644 index 72a144b20e..0000000000 --- a/containers/prod/haproxy/haproxy.cfg +++ /dev/null @@ -1,46 +0,0 @@ -global - chroot /var/lib/haproxy - user haproxy - group haproxy - -defaults - log global - mode http - option httplog - option dontlognull - timeout connect 5000 - timeout client 50000 - timeout server 50000 - errorfile 400 /etc/haproxy/errors/400.http - errorfile 403 /etc/haproxy/errors/403.http - errorfile 408 /etc/haproxy/errors/408.http - errorfile 500 /etc/haproxy/errors/500.http - errorfile 502 /etc/haproxy/errors/502.http - errorfile 503 /etc/haproxy/errors/503.http - errorfile 504 /etc/haproxy/errors/504.http - stats enable - stats auth haproxy:hapass - -userlist Bagels - user betalist insecure-password {BETA_PASSWORD} - -frontend https - bind :443 ssl crt /haproxy/keys/hub-beta.docker.com/hub-beta.docker.pem - acl is-ssl dst_port 443 - acl Auth_Bagels http_auth(Bagels) - http-request auth realm HubBeta if !Auth_Bagels - - http-request set-header X-Real-IP %ci - - reqadd X-Forwarded-Proto:\ https if is-ssl - reqadd X-Forwarded-Port:\ 443 if is-ssl - rspadd Strict-Transport-Security:\ max-age=31536000 if is-ssl - - acl is_hub_dev hdr(host) -i hub-beta.docker.com - - use_backend hub_dev if is_hub_dev - -backend hub_dev - balance leastconn - option httpclose - server docker-1 172.17.42.1:7001 check diff --git a/containers/prod/haproxy/keys/bagels.docker.com/bagels.docker.crt b/containers/prod/haproxy/keys/bagels.docker.com/bagels.docker.crt deleted file mode 100644 index 44765408fb..0000000000 --- a/containers/prod/haproxy/keys/bagels.docker.com/bagels.docker.crt +++ /dev/null @@ -1,14 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICNTCCAZ4CCQDY33gN8y9BQzANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJV -UzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xDzANBgNVBAoT -BkRvY2tlcjEaMBgGA1UEAxMRYmFnZWxzLmRvY2tlci5jb20wHhcNMTUwMTIxMDM1 -NTEzWhcNMTYwMTIxMDM1NTEzWjBfMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0Ex -FjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xDzANBgNVBAoTBkRvY2tlcjEaMBgGA1UE -AxMRYmFnZWxzLmRvY2tlci5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGB -AMluBCvOUrdFkFGCmpKBPduoZgYE/hNKnmX3Cqrn+FsodOBiin1lOs7+XX3EY078 -u5QIULNZ3j/LUSuxgHBS8RcVc3ljCkvwRURwVy6FWunahdTULLEq+qOByv6Hq2/W -itlzT2Rw6Tu29IThb7Mtxb1B6LoAorkWX/YEXankpVPnAgMBAAEwDQYJKoZIhvcN -AQEFBQADgYEAPdqZ2jLxOuZ52wucJN1DoOBUCWnCM5bfBHOU3wBqSPA/mT2Bw5Fo -evqqd+mRWizgmSkDM9NpO9cj9tpeidTrHsTutkqjQttIeNAtZm82sSWH7ul1N1du -4aDDKwAk4j9BYPUmYQFaSRKNtE/OpGVPxxK/ZBS8YeVT0knzTr/a9to= ------END CERTIFICATE----- diff --git a/containers/prod/haproxy/keys/bagels.docker.com/bagels.docker.csr b/containers/prod/haproxy/keys/bagels.docker.com/bagels.docker.csr deleted file mode 100644 index b9d96abb7e..0000000000 --- a/containers/prod/haproxy/keys/bagels.docker.com/bagels.docker.csr +++ /dev/null @@ -1,11 +0,0 @@ ------BEGIN CERTIFICATE REQUEST----- -MIIBnzCCAQgCAQAwXzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQH -Ew1TYW4gRnJhbmNpc2NvMQ8wDQYDVQQKEwZEb2NrZXIxGjAYBgNVBAMTEWJhZ2Vs -cy5kb2NrZXIuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJbgQrzlK3 -RZBRgpqSgT3bqGYGBP4TSp5l9wqq5/hbKHTgYop9ZTrO/l19xGNO/LuUCFCzWd4/ -y1ErsYBwUvEXFXN5YwpL8EVEcFcuhVrp2oXU1CyxKvqjgcr+h6tv1orZc09kcOk7 -tvSE4W+zLcW9Qei6AKK5Fl/2BF2p5KVT5wIDAQABoAAwDQYJKoZIhvcNAQEFBQAD -gYEAlAQKhy4j7wenWqnKzfpp/o0cbzQAcve76XSwfWrzONFDZidhQlwAKBdYbYN3 -4ITqNw4MPSCMBkMMCQFFFHM/+NqlAmYYbJHv8uDxKel/7IsxIEPRun0b6k/+wL2e -2nyJJrMwesVrzvDwfB+8eoUOZFJIiX6htpxU4vgq9xMgMAg= ------END CERTIFICATE REQUEST----- diff --git a/containers/prod/haproxy/keys/bagels.docker.com/bagels.docker.key b/containers/prod/haproxy/keys/bagels.docker.com/bagels.docker.key deleted file mode 100644 index 6659dc144c..0000000000 --- a/containers/prod/haproxy/keys/bagels.docker.com/bagels.docker.key +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIICWwIBAAKBgQDJbgQrzlK3RZBRgpqSgT3bqGYGBP4TSp5l9wqq5/hbKHTgYop9 -ZTrO/l19xGNO/LuUCFCzWd4/y1ErsYBwUvEXFXN5YwpL8EVEcFcuhVrp2oXU1Cyx -Kvqjgcr+h6tv1orZc09kcOk7tvSE4W+zLcW9Qei6AKK5Fl/2BF2p5KVT5wIDAQAB -AoGAcA+Qqn5Cbkt5Gp+6Nr9IFqf8+mRUpY7hyIBDowkiljRPsXWg7loe+YFxqcJU -LWFVSenGW8Enb/5AzjoV5md+UAiERbF13SzrEx7J7riwb1ljHe82RqUbyfpnnDWT -aSZ/ce+9LYoYggFVfH7DloT8NNsQzTDi2/g+66dXi8fcIIECQQDqykIcF20sz8Ar -H3StlgITEorJiZRpvbzuQ6G7XoC1XOI1/0+1NbIHm3lv4XfvaRSdKv0mnPaZmi3h -PWZC/zj3AkEA26BE6iEGO3eJ39l1zRpB1jS/VrEAa7pzGeEFeL+k/5XEWqsgHOtQ -qIbPtCyKcN5mtCYEg6GEK/pqNALWL6ZwkQJATT9CRO/IMaggd4+f2cSy5geBthEX -zTppwJJr0bOj8QegPVfEp8AE1M/oQlESHqiZ6aPNKjkWQS8izSpgTMafvQJAILDT -cTInNlTNvfcldLkS0aqaTHIeSOrA1TpMUTPdgHmvd3t/VS6lm+AtLHlwxeokyW3b -QCibftxQUJuXfBI/MQJAAt2m8P0V+U/MFjNhYUd2jwJIFFh7AVYeSH26NxzQMgO0 -YNQAaRKxwuhDrxyVwezryzyBcVWKdfhCtgOK6U5mFw== ------END RSA PRIVATE KEY----- diff --git a/containers/prod/haproxy/keys/bagels.docker.com/bagels.docker.pem b/containers/prod/haproxy/keys/bagels.docker.com/bagels.docker.pem deleted file mode 100644 index 753429af60..0000000000 --- a/containers/prod/haproxy/keys/bagels.docker.com/bagels.docker.pem +++ /dev/null @@ -1,29 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICNTCCAZ4CCQDY33gN8y9BQzANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJV -UzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xDzANBgNVBAoT -BkRvY2tlcjEaMBgGA1UEAxMRYmFnZWxzLmRvY2tlci5jb20wHhcNMTUwMTIxMDM1 -NTEzWhcNMTYwMTIxMDM1NTEzWjBfMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0Ex -FjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xDzANBgNVBAoTBkRvY2tlcjEaMBgGA1UE -AxMRYmFnZWxzLmRvY2tlci5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGB -AMluBCvOUrdFkFGCmpKBPduoZgYE/hNKnmX3Cqrn+FsodOBiin1lOs7+XX3EY078 -u5QIULNZ3j/LUSuxgHBS8RcVc3ljCkvwRURwVy6FWunahdTULLEq+qOByv6Hq2/W -itlzT2Rw6Tu29IThb7Mtxb1B6LoAorkWX/YEXankpVPnAgMBAAEwDQYJKoZIhvcN -AQEFBQADgYEAPdqZ2jLxOuZ52wucJN1DoOBUCWnCM5bfBHOU3wBqSPA/mT2Bw5Fo -evqqd+mRWizgmSkDM9NpO9cj9tpeidTrHsTutkqjQttIeNAtZm82sSWH7ul1N1du -4aDDKwAk4j9BYPUmYQFaSRKNtE/OpGVPxxK/ZBS8YeVT0knzTr/a9to= ------END CERTIFICATE----- ------BEGIN RSA PRIVATE KEY----- -MIICWwIBAAKBgQDJbgQrzlK3RZBRgpqSgT3bqGYGBP4TSp5l9wqq5/hbKHTgYop9 -ZTrO/l19xGNO/LuUCFCzWd4/y1ErsYBwUvEXFXN5YwpL8EVEcFcuhVrp2oXU1Cyx -Kvqjgcr+h6tv1orZc09kcOk7tvSE4W+zLcW9Qei6AKK5Fl/2BF2p5KVT5wIDAQAB -AoGAcA+Qqn5Cbkt5Gp+6Nr9IFqf8+mRUpY7hyIBDowkiljRPsXWg7loe+YFxqcJU -LWFVSenGW8Enb/5AzjoV5md+UAiERbF13SzrEx7J7riwb1ljHe82RqUbyfpnnDWT -aSZ/ce+9LYoYggFVfH7DloT8NNsQzTDi2/g+66dXi8fcIIECQQDqykIcF20sz8Ar -H3StlgITEorJiZRpvbzuQ6G7XoC1XOI1/0+1NbIHm3lv4XfvaRSdKv0mnPaZmi3h -PWZC/zj3AkEA26BE6iEGO3eJ39l1zRpB1jS/VrEAa7pzGeEFeL+k/5XEWqsgHOtQ -qIbPtCyKcN5mtCYEg6GEK/pqNALWL6ZwkQJATT9CRO/IMaggd4+f2cSy5geBthEX -zTppwJJr0bOj8QegPVfEp8AE1M/oQlESHqiZ6aPNKjkWQS8izSpgTMafvQJAILDT -cTInNlTNvfcldLkS0aqaTHIeSOrA1TpMUTPdgHmvd3t/VS6lm+AtLHlwxeokyW3b -QCibftxQUJuXfBI/MQJAAt2m8P0V+U/MFjNhYUd2jwJIFFh7AVYeSH26NxzQMgO0 -YNQAaRKxwuhDrxyVwezryzyBcVWKdfhCtgOK6U5mFw== ------END RSA PRIVATE KEY----- diff --git a/containers/prod/haproxy/run b/containers/prod/haproxy/run deleted file mode 100755 index 145832a4d5..0000000000 --- a/containers/prod/haproxy/run +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -sed -i s/{BETA_PASSWORD}/"$BETA_PASSWORD"/g /haproxy/haproxy.cfg - -# Check is haproxy.cfg is valid before we start -haproxy -c -f /haproxy/haproxy.cfg || ( echo 'Bad haproxy config'; exit; ) - -/usr/sbin/haproxy -f /haproxy/haproxy.cfg & - -wait $! diff --git a/deployment/deploy.sh b/deployment/deploy.sh deleted file mode 100755 index 9eded10710..0000000000 --- a/deployment/deploy.sh +++ /dev/null @@ -1,171 +0,0 @@ -#!/bin/sh - -DOCKER_CMD=docker - -alias AWS_HUB_PROD='aws ec2 describe-instances --filters "Name=tag:aws:cloudformation:stack-name,Values=us-east-1*" "Name=tag:secondary-role,Values=hub" "Name=instance-state-name,Values=running" --output=json' -alias AWS_HUB_STAGE='aws ec2 describe-instances --filters "Name=tag:aws:cloudformation:stack-name,Values=stage-us-east-1*" "Name=tag:secondary-role,Values=hub" "Name=instance-state-name,Values=running" --output=json' -alias AWS_IP="jq -r '.Reservations[].Instances[].PrivateIpAddress'" - -HUB_GATEWAY="https://hub.docker.com" -HUB_SERVICE_NAME="hub-web-v2" - -DEFAULT_IMAGE_PROD="bagel/hub-prod" -DEFAULT_IMAGE_STAGE="bagel/hub-stage" - -NEW_RELIC_APP_NAME="hub.docker.com(aws-node)" -NEW_RELIC_LICENSE_KEY="582e3891446a63a3f99b4d32f9585ec74af1d8d7" - -NO_COLOR="\033[0m" -RED="\033[0;31m" -GREEN="\033[0;32m" -YELLOW="\033[0;33m" - -MESSAGE_MISSING_OR_INVALID_ARGS="${RED}Missing or invalid arguments${NO_COLOR}" - -# $1: prod or stage -getAWSHosts() { - if [ $1 == "prod" ]; then - echo $(AWS_HUB_PROD | ( AWS_IP ; echo ) | sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/:2376 /g') - elif [ $1 == "stage" ]; then - echo $(AWS_HUB_STAGE | ( AWS_IP ; echo ) | sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/:2376 /g') - fi -} - -# $1: Exit code -printUsageAndExit() { - echo - echo "Usage: deploy.sh [prod|stage|-h ] [IMAGE]" - echo - echo " prod A predefined list of hosts for production" - echo " stage A predefined list of hosts for staging" - echo " -h A single host address" - echo - exit $1 -} - -# $1: Image argument -parseImageArg() { - if [ -z "$1" ]; then - echo $MESSAGE_MISSING_OR_INVALID_ARGS - printUsageAndExit 1 - fi - IMAGE=$1 -} - -parseArgs() { - if [ $1 == "-h" ]; then - parseImageArg $3 - HOSTS=$2 - else - if [ $1 == "prod" ]; then - if [ -z "$2" ]; then - IMAGE=$DEFAULT_IMAGE_PROD - else - parseImageArg $2 - fi - HOSTS=$( getAWSHosts "prod" ) - elif [ $1 == "stage" ]; then - if [ -z "$2" ]; then - IMAGE=$DEFAULT_IMAGE_STAGE - else - parseImageArg $2 - fi - HOSTS=$( getAWSHosts "stage" ) - else - echo - echo $MESSAGE_MISSING_OR_INVALID_ARGS - printUsageAndExit 1 - fi - fi -} - -# $1: Host IP -# $2: Image -# $3: Container name -# $4: Container port -runContainer() { - $DOCKER_CMD --tlsverify=false -H tcp://$1 run \ - -de ENV=production \ - -e HUB_API_BASE_URL=$HUB_GATEWAY \ - -e REGISTRY_API_BASE_URL=$HUB_GATEWAY \ - -e SERVICE_NAME=$HUB_SERVICE_NAME \ - -e SERVICE_80_NAME=$HUB_SERVICE_NAME \ - -e NEW_RELIC_LICENSE_KEY=$NEW_RELIC_LICENSE_KEY \ - -e NEW_RELIC_APP_NAME=$NEW_RELIC_APP_NAME \ - -e PORT=80 \ - -p $4:80 \ - --restart "unless-stopped" \ - --name $3 \ - $2 -} - -# $1: Host IP -# $2: Container name -removeContainer() { - $DOCKER_CMD --tlsverify=false -H tcp://$1 stop $2 - $DOCKER_CMD --tlsverify=false -H tcp://$1 rm $2 -} - -# $1: Host IP -# $2: Image name -pullImage() { - $DOCKER_CMD --tlsverify=false -H tcp://$1 pull $2 -} - -# $1: Host IP -# $2: Image -deployHost() { - echo - echo "Starting to deploy ${YELLOW}$IMAGE${NO_COLOR} to ${YELLOW}$1${NO_COLOR}" - - pullImage $1 $2 - - removeContainer $1 "hub_2_0" - runContainer $1 $2 "hub_2_0" 6600 - - removeContainer $1 "hub_2_1" - runContainer $1 $2 "hub_2_1" 6601 - - removeContainer $1 "hub_2_2" - runContainer $1 $2 "hub_2_2" 6602 -} - -# Prerequisites: -# 1- AWS -type aws >/dev/null 2>&1 || { echo >&2 "AWS client is required. Make sure 'aws' command is available:\nhttp://docs.aws.amazon.com/cli/latest/userguide/installing.html"; exit 1; } -# 2- JQ -type jq >/dev/null 2>&1 || { echo >&2 "jq JSON processor is required. Make sure 'jq' command is available:\nbrew install jq"; exit 1; } - -# Case for no paremeters specified -if [ -z "$1" ] - then - echo - echo $MESSAGE_MISSING_OR_INVALID_ARGS - printUsageAndExit 1 -fi - -parseArgs "$@" - -echo -echo "Image: ${YELLOW}$IMAGE ${NO_COLOR}" -echo "Hosts: ${YELLOW}$HOSTS${NO_COLOR}" -echo -read -p "Do you want to proceed? [Y/n]" -s -n 1 KEY -echo -if [[ ! $KEY =~ ^[Yy]$ ]]; then - exit 1 -fi - -# Run deployment for each host -for HUB_HOST in $HOSTS -do - deployHost $HUB_HOST $IMAGE - echo - echo "Sleeping for 10 seconds to let the containers boot up..." - echo - sleep 10 -done - -echo -echo "${GREEN}All done!${NO_COLOR}" -echo diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index c1257d728f..0000000000 --- a/docker-compose.yml +++ /dev/null @@ -1,28 +0,0 @@ -dnsmasq: - build: ./containers/dnsmasq - ports: - - "53:53/udp" - environment: - - DOCKER_HOST -haproxy: - build: ./containers/haproxy - environment: - - DOCKER_HOST - ports: - - "80:80" - - "443:443" -hub: - build: . - command: node --harmony ./server.js - working_dir: /opt/hub/app/.build - volumes: - - .:/opt/hub - - ./private-deps/docker-ux:/opt/node_modules/docker-ux - - ./private-deps/hub-js-sdk:/opt/node_modules/hub-js-sdk - ports: - - "7001:3000" - environment: - DEBUG: "hub:*" - HUB_API_BASE_URL: "https://hub-beta-stage.docker.com" - REGISTRY_API_BASE_URL: "https://hub-beta-stage.docker.com" - ENV: development diff --git a/docker-for-mac/docker-toolbox.md b/docker-for-mac/docker-toolbox.md deleted file mode 100644 index 1be3f5bc83..0000000000 --- a/docker-for-mac/docker-toolbox.md +++ /dev/null @@ -1,145 +0,0 @@ - - -# Docker for Mac vs. Docker Toolbox - -If you already have an installation of Docker Toolbox, please read these topics first to learn how Docker for Mac and Docker Toolbox differ, and how they can coexist. - - -## The Docker Toolbox environment - -Docker Toolbox installs `docker`, `docker-compose` and `docker-machine` in `/usr/local/bin` on your Mac. It also installs VirtualBox. At installation time, Toolbox uses `docker-machine` to provision a VirtualBox VM called `default`, running the `boot2docker` Linux distribution, with [Docker Engine](https://docs.docker.com/engine/) with certificates located on your Mac at `$HOME/.docker/machine/machines/default`. - -Before you use `docker` or `docker-compose` on your Mac, you typically use the command `eval $(docker-machine env default)` to set environment variables so that `docker` or `docker-compose` know how to talk to Docker Engine running on VirtualBox. - -This setup is shown in the following diagram. - -![Docker Toolbox Install](images/toolbox-install.png) - - -## The Docker for Mac environment - -Docker for Mac is a Mac native application, that you install in `/Applications`. At installation time, it creates symlinks in `/usr/local/bin` for `docker` and `docker-compose`, to the version of the commands inside the Mac application bundle, in `/Applications/Docker.app/Contents/Resources/bin`. - -Here are some key points to know about Docker for Mac before you get started: - -* Docker for Mac does not use VirtualBox, but rather HyperKit, a lightweight OS X virtualization solution built on top of Hypervisor.framework in OS X 10.10 Yosemite and higher. - -* Installing Docker for Mac does not affect machines you created with Docker Machine. The install offers to copy containers and images from your local `default` machine (if one exists) to the new Docker for Mac HyperKit VM. If chosen, content from `default` is copied to the new Docker for Mac HyperKit VM, and your original `default` machine is kept as is. - -* The Docker for Mac application does not use `docker-machine` to provision that VM; but rather creates and manages it directly. - -* At installation time, Docker for Mac provisions an HyperKit VM based on Alpine Linux, running Docker Engine. It exposes the docker API on a socket in `/var/tmp/docker.sock`. Since this is the default location where `docker` will look if no environment variables are set, you can start using `docker` and `docker-compose` without setting any environment variables. - -This setup is shown in the following diagram. - -![Docker for Mac Install](images/docker-for-mac-install.png) - -With Docker for Mac, you get only one VM, and you don't manage it. It is managed by the Docker for Mac application, which includes autoupdate to update the client and server versions of Docker. - -If you need several VMs and want to manage the version of the Docker client or server you are using, you can continue to use `docker-machine`, on the same machine, as described in [Docker Toolbox and Docker for Mac coexistence](#docker-toolbox-and-docker-for-mac-coexistence). - - -## Setting up to run Docker for Mac - -1. Check whether Toolbox DOCKER environment variables are set: - - $ env | grep DOCKER - DOCKER_HOST=tcp://192.168.99.100:2376 - DOCKER_MACHINE_NAME=default - DOCKER_TLS_VERIFY=1 - DOCKER_CERT_PATH=/Users/victoriabialas/.docker/machine/machines/default - - If this command returns no output, you are ready to use Docker for Mac. - - If it returns output (as shown in the example), you need to unset the `DOCKER` environment variables to make the client talk to the Docker for Mac Engine (next step). - -2. Run the `unset` command on the following `DOCKER` environment variables to unset them in the current shell. - - unset DOCKER_TLS_VERIFY - unset DOCKER_CERT_PATH - unset DOCKER_MACHINE_NAME - unset DOCKER_HOST - - Now, this command should return no output. - - $ env | grep DOCKER - - If you are using a Bash shell, you can use `unset ${!DOCKER_*}` to unset all DOCKER environment variables at once. (This will not work in other shells such as `.zsh`; you will need to unset each variable individually.) - ->**Note**: If you have a shell script as part of your profile that sets these `DOCKER` environment variables automatically each time you open a command window, then you will need to unset these each time you want to use Docker for Mac. - -> **Warning**: If you install Docker for Mac on a machine where Docker Toolbox is installed, it will replace the `docker` and `docker-compose` command lines in `/usr/local/bin` with symlinks to its own versions. - - -## Docker Toolbox and Docker for Mac coexistence - -You can use Docker for Mac and Docker Toolbox together on the same machine. When you want to use Docker for Mac, make sure all DOCKER environment variables are unset. You can do this in bash with `unset ${!DOCKER_*}`. When you want to use one of the VirtualBox VMs you have set with `docker-machine`, just run a `eval $(docker-machine env default)` (or the name of the machine you want to target). This will switch the current command shell to talk to the specified Toolbox machine. - -This setup is represented in the following diagram. - -![Docker Toolbox and Docker for Mac coexistence](images/docker-for-mac-and-toolbox.png) - - -## Using different versions of Docker tools - -The coexistence setup works as is as long as your VirtualBox VMs provisioned with `docker-machine` run the same version of Docker Engine as Docker for Mac. If you need to use VMs running older versions of Docker Engine, you can use a tool like Docker Version Manager to manage several versions of docker client. - - -### Checking component versions - -Ideally, the Docker CLI client and Docker Engine should be the same version. Mismatches between client and server, and among host machines you might have created with Docker Machine can cause problems (client can't talk to the server or host machines). - -If you already have Docker Toolbox installed, and then install Docker for Mac, you might get a newer version of the Docker client. Run `docker version` in a command shell to see client and server versions. In this example, the client installed with Docker for Mac is `Version: 1.11.1` and the server (which was installed earlier with Toolbox) is Version: 1.11.0. - - $ docker version - Client: - Version: 1.11.1 - ... - - Server: - Version: 1.11.0 - ... - -Also, if you created machines with Docker Machine (installed with Toolbox) then upgraded or installed Docker for Mac, you might have machines running different versions of Engine. Run `docker-machine ls` to view version information for the machines you created. In this example, the DOCKER column shows that each machine is running a different version of server. - - $ docker-machine ls - NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS - aws-sandbox - amazonec2 Running tcp://52.90.113.128:2376 v1.10.0 - default * virtualbox Running tcp://192.168.99.100:2376 v1.10.1 - docker-sandbox - digitalocean Running tcp://104.131.43.236:2376 v1.10.0 - -You might also run into a similar situation with Docker Universal Control Plan (UCP). - -There are a few ways to address this problem and keep using your older machines. One solution is to use a version manager like DVM. - -## How do I uninstall Docker Toolbox? - -You might decide that you do not need Toolbox now that you have Docker for Mac, -and want to uninstall it. For details on how to perform a clean uninstall of -Toolbox on the Mac, see [How to uninstall -Toolbox](/toolbox/toolbox_install_mac.md#how-to-uninstall-toolbox) in the -Toolbox Mac topics. - -
    -
      - diff --git a/docker-for-mac/examples.md b/docker-for-mac/examples.md deleted file mode 100644 index c784dd7042..0000000000 --- a/docker-for-mac/examples.md +++ /dev/null @@ -1,38 +0,0 @@ - - -# Example Applications - -Upcoming releases will include example applications especially tailored for Docker for Mac and Docker for Windows. - -Examples will highlight develop, build, and run workfows in several languages, including Node.js, Python, Ruby, and Java. - -For now, if you want get started experimenting with the Beta apps and Docker Compose (which is installed automatically with Docker Desktop Editions), have a look at these example applications in the Compose documentation. You should be able to run these with Docker for Mac and Docker for Windows. - -Quickstart: Compose and Django - -Quickstart: Compose and Rails - -Quickstart: Compose and WordPress - -See also [learn by example](/engine/tutorials/index.md) tutorials on building images, runnning containers, networking, managing data, and storing images on Docker Hub. - -
      -
        - diff --git a/docker-for-mac/faqs.md b/docker-for-mac/faqs.md deleted file mode 100644 index 191cddc350..0000000000 --- a/docker-for-mac/faqs.md +++ /dev/null @@ -1,156 +0,0 @@ - - -# Frequently Asked Questions (FAQs) - -**Looking for popular FAQs on Docker for Mac?** Check out the [Docker Knowledge Hub](http://success.docker.com/) for knowledge base articles, FAQs, technical support for various subscription levels, and more. - -### Stable and beta channels - -**Q: How do I get the stable or beta version of Docker for Mac?** - -A: Use the download links for the channels given in the topic [Download Docker for Mac](index.md#download-docker-for-mac). - -This topic also has more information about the two channels. - -**Q: What is the difference between the stable and beta versions of Docker for Mac?** - -A: Two different download channels are available for Docker for Mac: - -* The stable channel provides a general availability release-ready installer for a fully baked and tested, more reliable app. The stable version of Docker for Mac comes with the latest released version of Docker Engine. The release schedule is synched with Docker Engine releases and hotfixes. - -* The beta channel provides an installer with new features we are working on, but is not necessarily fully tested. It comes with the experimental version of Docker Engine. Bugs, crashes and issues are more likely to occur with the beta app, but you get a chance to preview new functionality, experiment, and provide feedback as the apps evolve. Releases are typically more frequent than for stable, often one or more per month. - -**Q: Can I switch back and forth between stable and beta versions of Docker for Mac?** - -A: Yes, you can switch between versions to try out the betas to see what's new, then go back to stable for other work. However, **you can have only one app installed at a time**. Switching back and forth between stable and beta apps can de-stabilize your development environment, particularly in cases where you switch from a newer (beta) channel to older (stable). - -For example, containers created with a newer beta version of Docker for Mac may not work after you switch back to stable because they may have been created leveraging beta features that aren't in stable yet. Just keep this in mind as you create and work with beta containers, perhaps in the spirit of a playground space where you are prepared to troubleshoot or start over. - -To safely switch between beta and stable versions be sure to save images and export the containers you need, then uninstall the current version before installing another. The workflow is described in more detail below.
        - -Do the following each time: - -1. Use `docker save` to save any images you want to keep. (See [save](/engine/reference/commandline/save.md) in the Docker Engine command line reference.) - -2. Use `docker export` to export containers you want to keep. (See [export](/engine/reference/commandline/export.md) in the Docker Engine command line reference.) - -3. Uninstall the current app (whether stable or beta). - -4. Install a different version of the app (stable or beta). - -### What is Docker.app? - -`Docker.app` is Docker for Mac, a bundle of Docker client, and Docker -Engine. `Docker.app` uses the OS X -Hypervisor.framework (part of MacOS X 10.10 Yosemite and higher) -to run containers, meaning that _**no separate VirtualBox is required**_. - -### What kind of feedback are we looking for? - -Everything is fair game. We'd like your impressions on the download-install process, startup, functionality available, the GUI, usefulness of the app, -command line integration, and so on. Tell us about problems, what you like, or functionality you'd like to see added. - -We are especially interested in getting feedback on the new swarm mode described in [Docker Swarm](/engine/swarm/index.md). A good place to start is the [tutorial](/engine/swarm/swarm-tutorial/index.md). - -### What if I have problems or questions? - -You can find the list of frequent issues in -[Logs and Troubleshooting](troubleshoot.md). - -If you do not find a solution in Troubleshooting, browse issues on [Docker for Mac issues on GitHub](https://github.com/docker/for-mac/issues) or create a new one. You can also create new issues based on diagnostics. To learn more, see [Diagnose problems, send feedback, and create GitHub issues](troubleshoot.md#diagnose-problems-send-feedback-and-create-github-issues). - -[Docker for Mac forum](https://forums.docker.com/c/docker-for-mac) provides discussion threads as well, and you can create discussion topics there, but we recommend using the GitHub issues over the forums for better tracking and response. - -### Can I use Docker for Mac with new swarm mode? - -Yes, you can use Docker for Mac to test single-node features of [swarm mode](/engine/swarm/index.md) introduced with Docker Engine 1.12, including -initializing a swarm with a single node, creating services, and scaling -services. Docker “Moby” on Hyperkit will serve as the single swarm node. You can -also use Docker Machine, which comes with Docker for Mac, to create and -experiment a multi-node swarm. Check out the tutorial at [Get started with swarm mode](/engine/swarm/swarm-tutorial/index.md). - -### How do I connect to the remote Docker Engine API? - -You might need to provide the location of the remote API for Docker clients and development tools. - -On Docker for Mac, clients can connect to the Docker Engine through a Unix socket: `unix:///var/run/docker.sock`. - -See also [Docker Remote API](/engine/reference/api/docker_remote_api.md) and Docker for Mac forums topic [Using pycharm Docker plugin..](https://forums.docker.com/t/using-pycharm-docker-plugin-with-docker-beta/8617). - -If you are working with applications like [Apache Maven](https://maven.apache.org/) that expect settings for `DOCKER_HOST` and `DOCKER_CERT_PATH` environment variables, specify these to connect to Docker instances through Unix sockets. For example: - - export DOCKER_HOST=unix:///var/run/docker.sock - -### How do I connect from a container to a service on the host? - -The Mac has a changing IP address (or none if you have no network access). Our current recommendation is to attach an unused IP to the `lo0` interface on the Mac so that containers can connect to this address. - -For a full explanation and examples, see [I want to connect from a container to a service on the host](networking.md#i-want-to-connect-from-a-container-to-a-service-on-the-host) under [Known Limitations, Use Cases, and Workarounds](networking.md#known-limitations-use-cases-and-workarounds) in the Networking topic. - -### How do I to connect to a container from the Mac? - -Our current recommendation is to publish a port, or to connect from another container. Note that this is what you have to do even on Linux if the container is on an overlay network, not a bridge network, as these are not routed. - -For a full explanation and examples, see [I want to connect to a container from the Mac](networking.md#i-want-to-connect-to-a-container-from-the-mac) under [Known Limitations, Use Cases, and Workarounds](networking.md#known-limitations-use-cases-and-workarounds) in the Networking topic. - -### What are system requirements for Docker for Mac? - -Note that you need a Mac that supports hardware virtualization, which is most non ancient ones; i.e., use OS X `10.10.3+` or `10.11` (OS X Yosemite or OS X El Capitan). See also "What to know before you install" in [Getting Started](index.md). - - -### Do I need to uninstall Docker Toolbox to use Docker for Mac? - -No, you can use these side by side. Docker Toolbox leverages a Docker daemon installed using `docker-machine` in a machine called `default`. Running `eval $(docker-machine env default)` in a shell sets DOCKER environment variables locally to connect to the default machine using Engine from Toolbox. To check whether Toolbox DOCKER environment variables are set, run `env | grep DOCKER`. - -To make the client talk to the Docker for Mac Engine, run the command `unset ${!DOCKER_*}` to unset all DOCKER environment variables in the current shell. (Now, `env | grep DOCKER` should return no output.) You can have multiple command line shells open, some set to talk to Engine from Toolbox and others set to talk to Docker for Mac. The same applies to `docker-compose`. - -### How do I uninstall Docker Toolbox? - -You might decide that you do not need Toolbox now that you have Docker for Mac, -and want to uninstall it. For details on how to perform a clean uninstall of -Toolbox on the Mac, see [How to uninstall -Toolbox](/toolbox/toolbox_install_mac.md#how-to-uninstall-toolbox) in the -Toolbox Mac topics. - -### What is HyperKit? - -HyperKit is a hypervisor built on top of the Hypervisor.framework in OS X 10.10 Yosemite and higher. It runs entirely in userspace and has no other dependencies. - -We use HyperKit to eliminate the need for other VM products, such as Oracle Virtualbox or VMWare Fusion. - -### What is the benefit of HyperKit? - -It is thinner than VirtualBox and VMWare fusion, and the version we include is tailor made for Docker workloads on the Mac. - -### Why is com.docker.vmnetd running after I quit the app? - -The privileged helper process `com.docker.vmnetd` is started by `launchd` and runs in the background. The process will not -consume any resources unless Docker.app connects to it, so it's safe to ignore. - -### Can I pass through a USB device to a container? - - Unfortunately it is not possible to pass through a USB device (or a serial port) to a container. For use cases requiring this, we recommend the use of [Docker Toolbox](/toolbox/overview.md). - -
        -
          - diff --git a/docker-for-mac/images/About.png b/docker-for-mac/images/About.png deleted file mode 100644 index 4fc78daf7b..0000000000 Binary files a/docker-for-mac/images/About.png and /dev/null differ diff --git a/docker-for-mac/images/changelog-placeholder.png b/docker-for-mac/images/changelog-placeholder.png deleted file mode 100644 index 87717b49cd..0000000000 Binary files a/docker-for-mac/images/changelog-placeholder.png and /dev/null differ diff --git a/docker-for-mac/images/chat.png b/docker-for-mac/images/chat.png deleted file mode 100644 index 597db5aae9..0000000000 Binary files a/docker-for-mac/images/chat.png and /dev/null differ diff --git a/docker-for-mac/images/console_logs.png b/docker-for-mac/images/console_logs.png deleted file mode 100644 index 951eac2820..0000000000 Binary files a/docker-for-mac/images/console_logs.png and /dev/null differ diff --git a/docker-for-mac/images/console_logs_search.png b/docker-for-mac/images/console_logs_search.png deleted file mode 100644 index bd3583b3cb..0000000000 Binary files a/docker-for-mac/images/console_logs_search.png and /dev/null differ diff --git a/docker-for-mac/images/diagnose-d4mac-issues-template.png b/docker-for-mac/images/diagnose-d4mac-issues-template.png deleted file mode 100644 index 328328e516..0000000000 Binary files a/docker-for-mac/images/diagnose-d4mac-issues-template.png and /dev/null differ diff --git a/docker-for-mac/images/diagnose-id-forums.png b/docker-for-mac/images/diagnose-id-forums.png deleted file mode 100644 index ae902907fb..0000000000 Binary files a/docker-for-mac/images/diagnose-id-forums.png and /dev/null differ diff --git a/docker-for-mac/images/diagnose-issue.png b/docker-for-mac/images/diagnose-issue.png deleted file mode 100644 index 4dd243a2c2..0000000000 Binary files a/docker-for-mac/images/diagnose-issue.png and /dev/null differ diff --git a/docker-for-mac/images/diagnose.png b/docker-for-mac/images/diagnose.png deleted file mode 100644 index 8c3a5945ca..0000000000 Binary files a/docker-for-mac/images/diagnose.png and /dev/null differ diff --git a/docker-for-mac/images/diagnostic-forums-topic.png b/docker-for-mac/images/diagnostic-forums-topic.png deleted file mode 100644 index 09973b0c96..0000000000 Binary files a/docker-for-mac/images/diagnostic-forums-topic.png and /dev/null differ diff --git a/docker-for-mac/images/docker-app-drag-old.png b/docker-for-mac/images/docker-app-drag-old.png deleted file mode 100644 index b05124d3b1..0000000000 Binary files a/docker-for-mac/images/docker-app-drag-old.png and /dev/null differ diff --git a/docker-for-mac/images/docker-app-drag.png b/docker-for-mac/images/docker-app-drag.png deleted file mode 100644 index b4744e47d8..0000000000 Binary files a/docker-for-mac/images/docker-app-drag.png and /dev/null differ diff --git a/docker-for-mac/images/docker-app-in-apps-no-annotation.png b/docker-for-mac/images/docker-app-in-apps-no-annotation.png deleted file mode 100644 index c1ace536af..0000000000 Binary files a/docker-for-mac/images/docker-app-in-apps-no-annotation.png and /dev/null differ diff --git a/docker-for-mac/images/docker-app-in-apps.png b/docker-for-mac/images/docker-app-in-apps.png deleted file mode 100644 index 2290320ea4..0000000000 Binary files a/docker-for-mac/images/docker-app-in-apps.png and /dev/null differ diff --git a/docker-for-mac/images/docker-app-log.png b/docker-for-mac/images/docker-app-log.png deleted file mode 100644 index 6aa36e7aef..0000000000 Binary files a/docker-for-mac/images/docker-app-log.png and /dev/null differ diff --git a/docker-for-mac/images/docker-app.png b/docker-for-mac/images/docker-app.png deleted file mode 100644 index 530fccb9ca..0000000000 Binary files a/docker-for-mac/images/docker-app.png and /dev/null differ diff --git a/docker-for-mac/images/docker-for-mac-and-toolbox.png b/docker-for-mac/images/docker-for-mac-and-toolbox.png deleted file mode 100644 index 1bbf09bd0a..0000000000 Binary files a/docker-for-mac/images/docker-for-mac-and-toolbox.png and /dev/null differ diff --git a/docker-for-mac/images/docker-for-mac-install.png b/docker-for-mac/images/docker-for-mac-install.png deleted file mode 100644 index 6a51c8b858..0000000000 Binary files a/docker-for-mac/images/docker-for-mac-install.png and /dev/null differ diff --git a/docker-for-mac/images/download.png b/docker-for-mac/images/download.png deleted file mode 100644 index bfa896d89e..0000000000 Binary files a/docker-for-mac/images/download.png and /dev/null differ diff --git a/docker-for-mac/images/hello-world-nginx.png b/docker-for-mac/images/hello-world-nginx.png deleted file mode 100644 index bf6cb20496..0000000000 Binary files a/docker-for-mac/images/hello-world-nginx.png and /dev/null differ diff --git a/docker-for-mac/images/hello-world.png b/docker-for-mac/images/hello-world.png deleted file mode 100644 index ededac6bbd..0000000000 Binary files a/docker-for-mac/images/hello-world.png and /dev/null differ diff --git a/docker-for-mac/images/hockeyapp-docker.png b/docker-for-mac/images/hockeyapp-docker.png deleted file mode 100644 index d07f85b97c..0000000000 Binary files a/docker-for-mac/images/hockeyapp-docker.png and /dev/null differ diff --git a/docker-for-mac/images/log-files-finder.png b/docker-for-mac/images/log-files-finder.png deleted file mode 100644 index a006274086..0000000000 Binary files a/docker-for-mac/images/log-files-finder.png and /dev/null differ diff --git a/docker-for-mac/images/logs.png b/docker-for-mac/images/logs.png deleted file mode 100644 index d16ff51520..0000000000 Binary files a/docker-for-mac/images/logs.png and /dev/null differ diff --git a/docker-for-mac/images/mac-activity-monitor-docker-app.png b/docker-for-mac/images/mac-activity-monitor-docker-app.png deleted file mode 100644 index 4510767cea..0000000000 Binary files a/docker-for-mac/images/mac-activity-monitor-docker-app.png and /dev/null differ diff --git a/docker-for-mac/images/mac-install-success-docker-ps.png b/docker-for-mac/images/mac-install-success-docker-ps.png deleted file mode 100644 index 62e8b9aad1..0000000000 Binary files a/docker-for-mac/images/mac-install-success-docker-ps.png and /dev/null differ diff --git a/docker-for-mac/images/mac-install-success-docker-wait.png b/docker-for-mac/images/mac-install-success-docker-wait.png deleted file mode 100644 index a6bb45f816..0000000000 Binary files a/docker-for-mac/images/mac-install-success-docker-wait.png and /dev/null differ diff --git a/docker-for-mac/images/menu.png b/docker-for-mac/images/menu.png deleted file mode 100644 index 659e329309..0000000000 Binary files a/docker-for-mac/images/menu.png and /dev/null differ diff --git a/docker-for-mac/images/privacy.png b/docker-for-mac/images/privacy.png deleted file mode 100644 index 7f0a52aaa7..0000000000 Binary files a/docker-for-mac/images/privacy.png and /dev/null differ diff --git a/docker-for-mac/images/proxy-settings.png b/docker-for-mac/images/proxy-settings.png deleted file mode 100644 index 7411df9afc..0000000000 Binary files a/docker-for-mac/images/proxy-settings.png and /dev/null differ diff --git a/docker-for-mac/images/remove-app-instances.png b/docker-for-mac/images/remove-app-instances.png deleted file mode 100644 index 5ba3588c4e..0000000000 Binary files a/docker-for-mac/images/remove-app-instances.png and /dev/null differ diff --git a/docker-for-mac/images/settings-advanced.png b/docker-for-mac/images/settings-advanced.png deleted file mode 100644 index 9d735f9555..0000000000 Binary files a/docker-for-mac/images/settings-advanced.png and /dev/null differ diff --git a/docker-for-mac/images/settings-diagnose-id.png b/docker-for-mac/images/settings-diagnose-id.png deleted file mode 100644 index f149356cd3..0000000000 Binary files a/docker-for-mac/images/settings-diagnose-id.png and /dev/null differ diff --git a/docker-for-mac/images/settings-diagnose.png b/docker-for-mac/images/settings-diagnose.png deleted file mode 100644 index 28547df813..0000000000 Binary files a/docker-for-mac/images/settings-diagnose.png and /dev/null differ diff --git a/docker-for-mac/images/settings-diagnostic-results-only.png b/docker-for-mac/images/settings-diagnostic-results-only.png deleted file mode 100644 index 82f1fd3fda..0000000000 Binary files a/docker-for-mac/images/settings-diagnostic-results-only.png and /dev/null differ diff --git a/docker-for-mac/images/settings-file-share-choose.png b/docker-for-mac/images/settings-file-share-choose.png deleted file mode 100644 index 248407e8e7..0000000000 Binary files a/docker-for-mac/images/settings-file-share-choose.png and /dev/null differ diff --git a/docker-for-mac/images/settings-file-share.png b/docker-for-mac/images/settings-file-share.png deleted file mode 100644 index 69b26c3802..0000000000 Binary files a/docker-for-mac/images/settings-file-share.png and /dev/null differ diff --git a/docker-for-mac/images/settings-uninstall.png b/docker-for-mac/images/settings-uninstall.png deleted file mode 100644 index bfb65af22c..0000000000 Binary files a/docker-for-mac/images/settings-uninstall.png and /dev/null differ diff --git a/docker-for-mac/images/settings.png b/docker-for-mac/images/settings.png deleted file mode 100644 index a9f9e95f67..0000000000 Binary files a/docker-for-mac/images/settings.png and /dev/null differ diff --git a/docker-for-mac/images/startup-help.png b/docker-for-mac/images/startup-help.png deleted file mode 100644 index 0db4aca3db..0000000000 Binary files a/docker-for-mac/images/startup-help.png and /dev/null differ diff --git a/docker-for-mac/images/toolbox-install.png b/docker-for-mac/images/toolbox-install.png deleted file mode 100644 index fa10bc28b9..0000000000 Binary files a/docker-for-mac/images/toolbox-install.png and /dev/null differ diff --git a/docker-for-mac/images/whale-in-menu-bar.png b/docker-for-mac/images/whale-in-menu-bar.png deleted file mode 100644 index 780201e127..0000000000 Binary files a/docker-for-mac/images/whale-in-menu-bar.png and /dev/null differ diff --git a/docker-for-mac/images/whale-x.png b/docker-for-mac/images/whale-x.png deleted file mode 100644 index c99e8d5898..0000000000 Binary files a/docker-for-mac/images/whale-x.png and /dev/null differ diff --git a/docker-for-mac/images/whale.png b/docker-for-mac/images/whale.png deleted file mode 100644 index 894c379349..0000000000 Binary files a/docker-for-mac/images/whale.png and /dev/null differ diff --git a/docker-for-mac/index.md b/docker-for-mac/index.md deleted file mode 100644 index 41049349f8..0000000000 --- a/docker-for-mac/index.md +++ /dev/null @@ -1,293 +0,0 @@ - - -# Getting Started with Docker for Mac - -Welcome to Docker for Mac! - -Please read through these topics on how to get started. To **give us feedback** on your experience with the app and report bugs or problems, log in to our [Docker for Mac forum](https://forums.docker.com/c/docker-for-mac). - ->**Already have Docker for Mac?** If you already have Docker for Mac installed, and are ready to get started, skip over to the [Getting Started with Docker](/engine/getstarted/index.md) tutorial. - - -## Download Docker for Mac - -If you have not already done so, please install Docker for Mac. You can download installers from the stable or beta channel. - -For more about stable and beta channels, see the [FAQs](faqs.md#stable-and-beta-channels). - - - - - - - - - - - - - - -
          Stable channelBeta channel
          This installer is fully baked and tested, and comes with the latest GA version of Docker Engine.

          This is the best channel to use if you want a reliable platform to work with.

          These releases follow a version schedule with a longer lead time than the betas, synched with Docker Engine releases and hotfixes. -
          This installer offers cutting edge features and comes with the experimental version of Docker Engine, which is described in the Docker Experimental Features README on GitHub.

          This is the best channel to use if you want to experiment with features we are working on as they become available, and can weather some instability and bugs. This channel is a continuation of the beta program, where you can provide feedback as the apps evolve. Releases are typically more frequent than for stable, often one or more per month.
          - Get Docker for Mac (stable)

          - Download checksum: Docker.dmg SHA256 -
          - Get Docker for Mac (beta)

          - Download checksum: Docker.dmg SHA256 -
          - ->**Important Notes**: -> ->* Docker for Mac requires OS X 10.10.3 Yosemite or newer running on a 2010 or newer Mac, with Intel's hardware support for MMU virtualization. Please see [What to know before you install](#what-to-know-before-you-install) for a full list of prerequisites. -> ->* You can switch between beta and stable versions, but _you must have only one app installed at a time_. Also, you will need to save images and export containers you want to keep before uninstalling the current version before installing another. For more about this, see the [FAQs about beta and stable channels](faqs.md#stable-and-beta-channels). - - -## What to know before you install - -* **README FIRST for Docker Toolbox and Docker Machine users**: If you are already running Docker on your machine, first read [Docker for Mac vs. Docker Toolbox](docker-toolbox.md) to understand the impact of this installation on your existing setup, how to set your environment for Docker for Mac, and how the two products can coexist. - -* **Relationship to Docker Machine**: Installing Docker for Mac does not affect machines you created with Docker Machine. You'll get the option to copy containers and images from your local `default` machine (if one exists) to the new Docker for Mac HyperKit VM. - -* **System Requirements**: Docker for Mac will launch only if all these requirements are met. - - - Mac must be a 2010 or newer model, with Intel's hardware support for memory management unit (MMU) virtualization; i.e., Extended Page Tables (EPT) - - - OS X 10.10.3 Yosemite or newer - - - At least 4GB of RAM - - - VirtualBox prior to version 4.3.30 must NOT be installed (it is incompatible with Docker for Mac) - - > **Note**: If your system does not satisfy these requirements, you can install [Docker Toolbox](/toolbox/overview.md), which uses Oracle Virtual Box instead of HyperKit. - -* **What the install includes**: The installation provides [Docker Engine](https://docs.docker.com/engine/userguide/intro/), Docker CLI client, [Docker Compose](https://docs.docker.com/compose/overview/), and [Docker Machine](https://docs.docker.com/machine/overview/). - - -## Step 1. Install and Run Docker for Mac - -1. Double-click `Docker.dmg` to open the installer, then drag Moby the whale to the Applications folder. - - ![Install Docker app](images/docker-app-drag.png) - - You will be asked to authorize `Docker.app` with your system password during the install process. Privileged access is needed to install networking components and links to the Docker apps. - -2. Double-click `Docker.app` to start Docker. - - ![Docker app in Hockeyapp](images/docker-app-in-apps.png) - - The whale in the top status bar indicates that Docker is running, and accessible from a terminal. - - ![Whale in menu bar](images/whale-in-menu-bar.png) - - If you just installed the app, you also get a success message with suggested next steps and a link to this documentation. Click the whale () in the status bar to dismiss this popup. - - ![Docker success](images/mac-install-success-docker-ps.png) - -3. Click the whale () to get Preferences, and other options. - - ![Docker context menu](images/menu.png) - -4. Select **About Docker** to verify that you have the latest version. - - Congratulations! You are up and running with Docker for Mac. - - -## Step 2. Check versions of Docker Engine, Compose, and Machine - -Run these commands to test if your versions of `docker`, `docker-compose`, and `docker-machine` are up-to-date and compatible with `Docker.app`. - -```shell - $ docker --version - Docker version 1.12.0, build 8eab29e - - $ docker-compose --version - docker-compose version 1.8.0, build f3628c7 - - $ docker-machine --version - docker-machine version 0.8.0, build b85aac1 -``` - ->**Note**: The above is an example. Your output will differ if you are running different (e.g., newer) versions. - - -## Step 3. Explore the application and run examples - -1. Open a command-line terminal, and run some Docker commands to verify that Docker is working as expected. - - Some good commands to try are `docker version` to check that you have the latest release installed, and `docker ps` and `docker run hello-world` to verify that Docker is running. - -2. For something more adventurous, start a Dockerized web server. - - ```shell - docker run -d -p 80:80 --name webserver nginx - ``` - - If the image is not found locally, Docker will pull it from Docker Hub. - - In a web browser, go to `http://localhost/` to bring up the home page. (Since you specified the default HTTP port, it isn't necessary to append `:80` at the end of the URL.) - - ![nginx home page](images/hello-world-nginx.png) - - >**Note:** Early beta releases used `docker` as the hostname to build the URL. Now, ports are exposed on the private IP addresses of the VM and forwarded to `localhost` with no other host name set. See also, [Release Notes](release-notes.md) for Beta 9. - > - -3. Run `docker ps` while your web server is running to see details on the webserver container. - - CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES - 56f433965490 nginx "nginx -g 'daemon off" About a minute ago Up About a minute 0.0.0.0:80->80/tcp, 443/tcp webserver - -4. Stop or remove containers and images. - - The `nginx` webserver will continue to run in the container on that port until you stop and/or remove the container. If you want to stop the webserver, type: `docker stop webserver` and start it again with `docker start webserver`. - - To stop and remove the running container with a single command, type: `docker rm -f webserver`. This will remove the container, but not the `nginx` image. You can list local images with `docker images`. You might want to keep some images around so that you don't have to pull them again from Docker Hub. To remove an image you no longer need, use `docker rmi |`. For example, `docker rmi nginx`. - -**Want more example applictions?** - For more example walkthroughs that include setting up services and databases in Docker Compose, see [Example Applications](examples.md). - -## Preferences - -Choose --> **Preferences** from the menu bar. You can set the following runtime options. - -#### General - -![Preferences](images/settings.png) - -* Docker for Mac is set to **automatically start** when you log in. Uncheck the login autostart option if you don't want Docker to start when you open your session. - -* Docker for Mac is set to **check for updates** automatically and notify you when an update is available. If an update is found, click **OK** to accept and install it (or cancel to keep the current version). If you disable the check for updates, you can still find out about updates manually by choosing -> **Check for Updates** - -* Check **Exclude VM from Time Machine backups** to prevent Time Machine from backing up the Docker for Mac virtual machine. - -* **CPUs** - By default, Docker for Mac is set to use 2 processors. You can increase processing power for the app by setting this to a higher number, or lower it to have Docker for Mac use fewer computing resources. - -* **Memory** - By default, Docker for Mac is set to use `2` GB runtime memory, allocated from the total available memory on your Mac. You can increase the RAM on the app to get faster performance by setting this number higher (for example to `3`) or lower (to `1`) if you want Docker for Mac to use less memory. - -#### Advanced - -![Advanced Preference settings-advanced](images/settings-advanced.png) - -* **Adding registries** - As an alternative to using [Docker Hub](https://hub.docker.com/) to store your public or private images or [Docker Trusted Registry](https://docs.docker.com/docker-trusted-registry/overview/), you can use Docker to set up your own insecure [registry](https://docs.docker.com/registry/introduction/). Add URLs for insecure registries and registry mirrors on which to host your images. - -* **HTTP proxy settings** - Docker for Mac will detect HTTP/HTTPS Proxy Settings and automatically propagate these to Docker and to your containers. -For example, if you set your proxy settings to `http://proxy.example.com`, Docker will use this proxy when pulling containers. - - -#### File sharing - -You can decide which directories on your Mac to share with containers. - -* **Add a Directory** - Click `+` and navigate to the directory you want to add. - - ![File Sharing](images/settings-file-share.png) - -* Click **Apply & Restart** to make the directory available to - containers using Docker's bind mount (`-v`) feature. - -There are some limitations on the directories that can be shared: - -* They cannot be a subdirectory of an already shared directory. - -* They cannot already exist inside of Docker. - -See [Namespaces](osxfs.md#namespaces) in the topic on [osxfs file system sharing](osxfs.md) for more information. - -#### Privacy - -You can set Docker for Mac to auto-send diagnostics, crash reports, and usage data. This information can help Docker improve the application and get more context for troubleshooting problems. - -Uncheck any of the options to opt out and prevent auto-send of data. Docker may prompt for more information in some cases, even with auto-send enabled. - -![Privacy](images/privacy.png) - -Also, you can enable or disable these auto-reporting settings with one click on the information popup when you first start Docker. - -![Startup information](images/mac-install-success-docker-wait.png) - -## Uninstall or reset -Choose --> **Preferences** from the menu bar, then click **Uninstall / Reset** on the Preferences dialog. - -![Uninstall or reset Docker](images/settings-uninstall.png) - -* **Uninstall** - Choose this option to remove Docker for Mac from your system. - -* **Reset to factory defaults** - Choose this option to reset all options on Docker for Mac to its initial state, the same as when it was first installed. - -You can uninstall Docker for Mac from the command line with this command: ` --uninstall`. If Docker is installed in the default location, the following command will provide a clean uninstall. - -```shell -$ /Applications/Docker.app/Contents/MacOS/Docker --uninstall -Docker is running, exiting... -Docker uninstalled successfully. You can move the Docker application to the trash. -``` - -You might want to use the command-line uninstall if, for example, you find that the app is non-functional, and you cannot uninstall it from the menu. - - -## Installing bash completion - -If you are using [bash completion](https://www.debian-administration.org/article/316/An_introduction_to_bash_completion_part_1), such as [homebrew bash-completion on Mac](http://davidalger.com/development/bash-completion-on-os-x-with-brew/), bash completion scripts for -- docker -- docker-machine -- docker-compose -may be found inside Docker.app, in the Contents/Resources/etc folder. - -To activate bash completion, these files need to be copied or symlinked to -your bash_completion.d directory. For example, if you use Homebrew: - -``` -cd /usr/local/etc/bash_completion.d -ln -s /Applications/Docker.app/Contents/Resources/etc/docker.bash-completion -ln -s /Applications/Docker.app/Contents/Resources/etc/docker-machine.bash-completion -ln -s /Applications/Docker.app/Contents/Resources/etc/docker-compose.bash-completion -``` - -## Where to go next - -* Try out the [Getting Started with Docker](/engine/getstarted/index.md) tutorial. - -* Dig in deeper with [learn by example](/engine/tutorials/index.md) tutorials on on building images, runnning containers, networking, managing data, and storing images on Docker Hub. - -* See [Example Applications](examples.md) for example applications that include setting up services and databases in Docker Compose. - -* Interested in trying out the new [swarm mode](/engine/swarm/index.md) on Docker Engine v1.12? - - See [Get started with swarm mode](/engine/swarm/swarm-tutorial/index.md), a tutorial which includes specifics on how to leverage your Docker for Mac installation to run single and multi-node swarms. - - Also, try out the Swarm examples in [docker labs](https://github.com/docker/labs/tree/master/swarm-mode/beginner-tutorial). Run the `bash script` and follow the accompanying [Docker Swarm Tutorial](https://github.com/docker/labs/blob/master/swarm-mode/beginner-tutorial/README.md). The script uses Docker Machine to create a multi-node swarm, then walks you through various Swarm tasks and commands. - -* For a summary of Docker command line interface (CLI) commands, see [Docker CLI Reference Guide](/engine/reference/index.md). - -* Check out the blog posts on Docker for Mac and Docker for Windows public betas, and earlier posts on the intial private beta. - -* Please give feedback on your experience with the app and report bugs and problems by logging into our [Docker for Mac forum](https://forums.docker.com/c/docker-for-mac). - - -
          -
            - diff --git a/docker-for-mac/menu.md b/docker-for-mac/menu.md deleted file mode 100644 index fa706b6da0..0000000000 --- a/docker-for-mac/menu.md +++ /dev/null @@ -1,14 +0,0 @@ - - -# Docker for Mac diff --git a/docker-for-mac/multi-arch.md b/docker-for-mac/multi-arch.md deleted file mode 100644 index 6bd76ff4ef..0000000000 --- a/docker-for-mac/multi-arch.md +++ /dev/null @@ -1,48 +0,0 @@ - - -# Leveraging Multi-CPU Architecture Support - -Docker for Mac provides `binfmt_misc` multi architecture support, so you can run containers for different Linux architectures, such as `arm`, `mips`, `ppc64le` and even `s390x`. - -This should just work without any configuration, but the containers you run need to have the appropriate `qemu` binary inside the container before you can do this. (See QEMU for more information.) - -So, you can run a container that already has this set up, like the resin arm builds: - -``` -$ docker run resin/armv7hf-debian uname -a - -Linux 7ed2fca7a3f0 4.1.12 #1 SMP Tue Jan 12 10:51:00 UTC 2016 armv7l GNU/Linux - -$ docker run justincormack/ppc64le-debian uname -a - -Linux edd13885f316 4.1.12 #1 SMP Tue Jan 12 10:51:00 UTC 2016 ppc64le GNU/Linux - -``` - -Running containers pre-configured with `qemu` has the advantage that you can use these to do builds `FROM`, so you can build new Multi-CPU architecture packages. - -Alternatively, you can bind mount in the `qemu` static binaries to any cross-architecture package, such as the semi-official ones using a script like this one https://github.com/justincormack/cross-docker. (See the README at the given link for details on how to use the script.) - -
            -
              - diff --git a/docker-for-mac/networking.md b/docker-for-mac/networking.md deleted file mode 100644 index 8a7b579f15..0000000000 --- a/docker-for-mac/networking.md +++ /dev/null @@ -1,121 +0,0 @@ - - -# Networking - -Docker for Mac provides several networking features to make it easier to use. - -## Features - -### VPN Passthrough - -Docker for Mac's networking can work when attached to a VPN. -To do this, Docker for Mac intercepts traffic from the `HyperKit` and injects it into OSX as if it originated from the Docker application. - -### Port Mapping - -When you run a container with the `-p` argument, for example: -``` -$ docker run -p 80:80 -d nginx -``` -Docker for Mac will make the container port available at `localhost`. - -### HTTP/HTTPS Proxy Support - -Docker for Mac will detect HTTP/HTTPS Proxy Settings from OSX and automatically propagate these to Docker and to your containers. -For example, if you set your proxy settings to `http://proxy.example.com` in OSX, Docker will use this proxy when pulling containers. - -![OSX Proxy Settings](images/proxy-settings.png) - -When you start a container, you will see that your proxy settings propagate into the containers. For example: - -``` -$ docker run -it alpine env -PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin -HOSTNAME=b7edf988b2b5 -TERM=xterm -HOME=/root -HTTP_PROXY=http://proxy.example.com:3128 -http_proxy=http://proxy.example.com:3128 -no_proxy=*.local, 169.254/16 -``` - -You can see from the above output that the `HTTP_PROXY`, `http_proxy` and `no_proxy` environment variables are set. -When your proxy configuration changes, Docker restarts automatically to pick up the new settings. -If you have containers that you wish to keep running across restarts, you should consider using [restart policies](https://docs.docker.com/engine/reference/run/#restart-policies-restart) - -## Known Limitations, Use Cases, and Workarounds - -Following is a summary of current limitations on the Docker for Mac networking stack, along with some ideas for workarounds. - -### There is no docker0 bridge on OSX - -Because of the way networking is implemented in Docker for Mac, you cannot see a `docker0` interface in OSX. -This interface is actually within `HyperKit`. - -### I cannot ping my containers - -Unfortunately, due to limtations in OSX, we're unable to route traffic to containers, and from containers back to the host. - -### Per-container IP addressing is not possible - -The docker (Linux) bridge network is not reachable from the OSX host. - -### Use cases and workarounds - -There are two scenarios that the above limitations will affect: - -#### I want to connect from a container to a service on the host - -The Mac has a changing IP address (or none if you have no network access). Our current recommendation is to attach an unused IP to the `lo0` interface on the Mac; for example: `sudo ifconfig lo0 alias 10.200.10.1/24`, and make sure that your service is listening on this address or `0.0.0.0` (ie not `127.0.0.1`). Then containers can connect to this address. - -#### I want to connect to a container from the Mac - -Port forwarding works for `localhost`; `--publish`, `-p`, or `-P` all work. Ports exposed from Linux are forwarded to the Mac. - -Our current recommendation is to publish a port, or to connect from another container. Note that this is what you have to do even on Linux if the container is on an overlay network, not a bridge network, as these are not routed. - -The command to run the `nginx` webserver shown in [Getting Started](index.md#explore) is an example of this. - -```shell -docker run -d -p 80:80 --name webserver nginx -``` - -To clarify the syntax, the following two commands both expose port `80` on the container to port `8000` on the host: - - docker run --publish 8000:80 --name webserver nginx - docker run --p 8000:80 --name webserver nginx - -To expose all ports, use the `-P` flag. For example, the following command starts a container (in detached mode) and the `-P` exposes all ports on the container to random ports on the host. - - docker run -d -P --name webserver nginx - -See the [run commmand](/engine/reference/commandline/run.md) for more details on publish options used with `docker run`. - -#### A view into implementation - -We understand that these workarounds are not ideal, but there are several problems. In particular, there is a bug in OSX that is only fixed in 10.12 and is not being backported as far as we can tell, which means that we could not support this in all supported OSX versions. In addition, this network setup would require root access which we are trying to avoid entirely in Docker for Mac (we currently have a very small root helper that we are trying to remove). - - -
              -
                - diff --git a/docker-for-mac/opensource.md b/docker-for-mac/opensource.md deleted file mode 100644 index a21338693d..0000000000 --- a/docker-for-mac/opensource.md +++ /dev/null @@ -1,34 +0,0 @@ - - -# Open Source Components and Licensing - -Docker Desktop Editions are built using open source software. For -details on the licensing, choose --> -**About Docker** from within the application, then click -**Acknowledgements**. - -Docker Desktop Editions distribute some components that are licensed under the GNU General Public License. You can download the source for these components [here](https://download.docker.com/opensource/License.tar.gz). - -The sources for `qemu-img` can be obtained [here](http://wiki.qemu-project.org/download/qemu-2.4.1.tar.bz2). -The sources for the `gettext` and `glib` libraries that `qemu-img` requires were obtained from [Homebrew](https://brew.sh) and may be retrieved using `brew install --build-from-source gettext glib`. - -
                -
                  - diff --git a/docker-for-mac/osxfs.md b/docker-for-mac/osxfs.md deleted file mode 100644 index 6d17758967..0000000000 --- a/docker-for-mac/osxfs.md +++ /dev/null @@ -1,166 +0,0 @@ - - -# File system sharing (osxfs) - -`osxfs` is a new shared file system solution, exclusive to Docker for -Mac. `osxfs` provides a close-to-native -user experience for bind mounting OS X file system trees into Docker -containers. To this end, `osxfs` features a number of unique -capabilities as well as differences from a classical Linux file system. - -- [Case sensitivity](#case-sensitivity) -- [Access control](#access-control) -- [Namespaces](#namespaces) -- [Ownership](#ownership) -- [File system events](#file-system-events) -- [Mounts](#mounts) -- [Symlinks](#symlinks) -- [File types](#file-types) -- [Extended attributes](#extended-attributes) -- [Technology](#technology) - -### Case sensitivity - -With Docker for Mac, file systems are shared from OS X into containers -in the same way as they operate in OS X. As a result, if a file system -on OS X is case-insensitive that behavior is shared by any bind mount -from OS X into a container. The default OS X file system is HFS+ and, -during installation, it is installed as case-insensitive by default. To -get case-sensitive behavior from your bind mounts, you must either -create and format a ramdisk or external volume as HFS+ with -case-sensitivity or reformat your OS root partition with HFS+ with -case-sensitivity. We do not recommend reformatting your root partition -as some Mac software dubiously relies on case-insensitivity to function. - - -### Access control - -`osxfs`, and therefore Docker, can access only those file system -resources that the Docker for Mac user has access to. `osxfs` does -not run as `root`. If the OS X user is an administrator, `osxfs` inherits -those administrator privileges. We are still evaluating which privileges -to drop in the file system process to balance security and -ease-of-use. `osxfs` performs no additional permissions checks and -enforces no extra access control on accesses made through it. All -processes in containers can access the same objects in the same way as -the Docker user who started the containers. - -### Namespaces - -Much of the OS X file system that is accessible to the user is also -available to containers using the `-v` bind mount syntax. By default, -you can share files in `/Users`, `/Volumes`, `/private`, and `/tmp` -directly. To add or remove directory trees that are exported to Docker, -use the **File sharing** tab in Docker preferences -> **Preferences** -> **File -sharing**. (See [Preferences](index.md#preferences).) All other paths -used in `-v` bind mounts are sourced from the Moby Linux VM running the -Docker containers, so arguments such as `-v -/var/run/docker.sock:/var/run/docker.sock` should work as expected. If -an OS X path is not shared and does not exist in th VM, an attempt to -bind mount it will fail rather than create it in the VM. Paths that -already exist in the VM and contain files are reserved by Docker and -cannot be exported from OS X. - -### Ownership - -Initially, any containerized process that requests ownership metadata of -an object is told that its `uid` and `gid` own the object. When any -containerized process changes the ownership of a shared file system -object, e.g. with `chown`, the new ownership information is persisted in -the `com.docker.owner` extended attribute of the object. Subsequent -requests for ownership metadata will return the previously set -values. Ownership-based permissions are only enforced at the OS X file -system level with all accessing processes behaving as the user running -Docker. If the user does not have permission to read extended attributes -on an object, e.g. when that object's permissions are `0000`, ownership -will be reported as the accessing process until the extended attribute -is again readable. - -### File system events - -Most `inotify` events are supported in bind mounts, and likely `dnotify` -and `fanotify` (though they have not been tested) are also supported. -This means that file system events from OS X are sent into containers -and trigger any listening processes there. - -The following are **supported file system events**: - -* Creation -* Modification -* Attribute changes -* Deletion -* Directory changes - -The following are **partially supported file system events**: - -* Move events trigger `IN_DELETE` on the source of the rename and - `IN_MODIFY` on the destination of the rename - -The following are **unsupported file system events**: - -* Open -* Access -* Close events -* Unmount events (see Mounts) - -Some events may be delivered multiple times. Events are not delivered for bind mounts from symlinks (notably `/tmp` will not deliver inotify events but -`/private/tmp` will). These limitations do not apply to events between -containers, only to those events originating in OS X. - - -### Mounts - -The OS X mount structure is not visible in the shared volume, but volume -contents are visible. Volume contents appear in the same file system as the -rest of the shared file system. Mounting/unmounting OS X volumes that -are also bind mounted into containers may result in unexpected behavior -in those containers. Unmount events are not supported. Mount export -support is planned but is still under development. - -### Symlinks - -Symlinks are shared unmodified. This may cause issues when symlinks -contain paths that rely on the default case-insensitivity of the -default OS X file system, HFS+. - -### File types - -Symlinks, hardlinks, socket files, named pipes, regular files, and -directories are supported. Socket files and named pipes only transmit -between containers and between OS X processes -- no transmission across -the hypervisor is supported, yet. Character and block device files are -not supported. - -### Extended attributes - -Extended attributes are not yet supported. - -### Technology - -`osxfs` does not use OSXFUSE. `osxfs` does not run under, inside, or -between OS X userspace processes and the OS X kernel. - -
                  -
                    - diff --git a/docker-for-mac/release-notes.md b/docker-for-mac/release-notes.md deleted file mode 100644 index 770049de4d..0000000000 --- a/docker-for-mac/release-notes.md +++ /dev/null @@ -1,1159 +0,0 @@ - - -# Docker for Mac Release Notes - -Here are the main improvements and issues per release, starting with the current release. The documentation is always updated for each release. - -For system requirements, please see the Getting Started topic on [What to know before you install](index.md#what-to-know-before-you-install). - -Release notes for _stable_ and _beta_ releases are listed below. You can learn about both kinds of releases, and download stable and beta product installers at [Download Docker for Mac](index.md#download-docker-for-mac). - -* [Stable Release Notes](#stable-release-notes) -* [Beta Release Notes](#beta-release-notes) - -## Stable Release Notes - -### Docker for Mac 1.12.1, 2016-09-16 (stable) - -**New** - -* Support for OSX 10.12 Sierra - -**Upgrades** - -* Docker 1.12.1 -* Docker machine 0.8.1 -* Linux kernel 4.4.20 -* aufs 20160905 - -**Bug fixes and minor changes** - -**General** - - * Fixed communications glitch when UI talks to com.docker.vmnetd - Fixes https://github.com/docker/for-mac/issues/90 - - * `docker-diagnose`: display and record the time the diagnosis was captured - - * Don't compute the container folder in `com.docker.vmnetd` - Fixes https://github.com/docker/for-mac/issues/47 - - * Warn the user if BlueStacks is installed (potential kernel panic) - - * Automatic update interval changed from 1 hour to 24 hours - - * Include Zsh completions - - * UI Fixes - -**Networking** - -* VPNKit supports search domains - -* slirp: support up to 8 external DNS servers - -* slirp: reduce the number of sockets used by UDP NAT, reduce the probability that NAT rules will time out earlier than expected - -* Entries from `/etc/hosts` should now resolve from within containers - -* Allow ports to be bound on host addresses other than `0.0.0.0` and `127.0.0.1` - Fixes issue reported in https://github.com/docker/for-mac/issues/68 - -* Use Mac System Configuration database to detect DNS - -**Filesharing (OSXFS)** - -* Fixed thread leak - -* Fixed a malfunction of new directories that have the same name as an old directory that is still open - -* Rename events now trigger DELETE and/or MODIFY `inotify` events (saving with TextEdit works now) - -* Fixed an issue that caused `inotify` failure and crashes - -* Fixed a directory file descriptor leak - -* Fixed socket `chowns` - -**Moby** - -* Use default `sysfs` settings, transparent huge pages disabled - -* `cgroup` mount to support `systemd` in containers - -* Increase Moby `fs.file-max` to 524288 - -* Fixed Moby Diagnostics and Update Kernel - -**HyperKit** - -* HyperKit updated with `dtrace` support and lock fixes - -### Docker for Mac 2016-08-11 1.12.0-a (stable) - -This bug fix release contains osxfs improvements. The fixed issues may have -been seen as failures with apt-get and npm in containers, missed inotify -events or unexpected unmounts. - -* Bug fixes - - osxfs: fixed an issue causing access to children of renamed - directories to fail (symptoms: npm failures, apt-get failures) - - osxfs: fixed an issue causing some ATTRIB and CREATE inotify - events to fail delivery and other inotify events to stop - - osxfs: fixed an issue causing all inotify events to stop when an - ancestor directory of a mounted directory was mounted - - osxfs: fixed an issue causing volumes mounted under other mounts - to spontaneously unmount - -### Docker for Mac 1.12.0-a, 2016-08-03 (stable) - -This bug fix release contains osxfs improvements. The fixed issues may have -been seen as failures with apt-get and npm in containers, missed `inotify` -events or unexpected unmounts. - -**Hotfixes** - -* osxfs: fixed an issue causing access to children of renamed directories to fail (symptoms: npm failures, apt-get failures) (docker/for-mac) - -* osxfs: fixed an issue causing some ATTRIB and CREATE `inotify` events to fail delivery and other `inotify` events to stop - -* osxfs: fixed an issue causing all `inotify` events to stop when an ancestor directory of a mounted directory was mounted - -* osxfs: fixed an issue causing volumes mounted under other mounts to spontaneously unmount - -### Docker for Mac 1.12.0, 2016-07-28 (stable) - -* First stable release - -**Components** - -* Docker 1.12.0 -* Docker Machine 0.8.0 -* Docker Compose 1.8.0 - -## Beta Release Notes - -### Beta 27 Release Notes (2016-09-28 1.12.2-rc1-beta27) - -**Upgrades** - -* Docker 1.12.2-rc1 -* Docker Machine 0.8.2 -* Docker compose 1.8.1 -* Kernel vsock driver v7 -* Kernel 4.4.21 -* aufs 20160912 - -**Bug fixes and minor changes** - -* Fix an issue where some windows did not claim focus correctly -* Add UI when switching channel to prevent user losing containers and settings -* Check disk capacity before Toolbox import -* Import certificates in `etc/ssl/certs/ca-certificates.crt` -* DNS: reduce the number of UDP sockets consumed on the host -* VPNkit: improve the connection-limiting code to avoid running out of sockets on the host -* UDP: handle diagrams bigger than 2035, up to the configured macOS kernel limit -* UDP: make the forwarding more robust; drop packets and continue rather than stopping -* disk: make the "flush" behaviour configurable for database-like workloads. This works around a performance regression in `v1.12.1`. - -### Beta 26 Release Notes (2016-09-14 1.12.1-beta26) - -**New** - -* Improved support for macOS 10.12 Sierra - -**Upgrades** - -* Linux kernel 4.4.20 -* aufs 20160905 - -**Bug fixes and minor changes** - -* Fixed communications glitch when UI talks to `com.docker.vmnetd`. Fixes https://github.com/docker/for-mac/issues/90 - -* UI fix for macOs 10.12 - -* Windows open on top of full screen app are available in all spaces - -* Reporting a bug, while not previously logged into GitHub now works - -* When a diagnostic upload fails, the error is properly reported - -* `docker-diagnose` displays and records the time the diagnosis was captured - -* Ports are allowed to bind to host addresses other than `0.0.0.0` and `127.0.0.1`. Fixes issue reported in https://github.com/docker/for-mac/issues/68. - -* We no longer compute the container folder in `com.docker.vmnetd`. Fixes https://github.com/docker/for-mac/issues/47. - -**Known Issues** - -* `Docker.app` sometimes uses 200% CPU after OS X wakes up from sleep mode. The -issue is being investigated. The workaround is to restart Docker.app. - -* There are a number of issues with the performance of directories bind-mounted with `osxfs`. In particular, writes of small blocks and -traversals of large directories are currently slow. Additionally, containers -that perform large numbers of directory operations, such as repeated scans of -large directory trees, may suffer from poor performance. More information is -available in [Known Issues](troubleshoot.md#known-issues) in Troubleshooting. - -* Under some unhandled error conditions, `inotify` event delivery can fail and become permanently disabled. The workaround is to restart `Docker.app`. - -### Beta 25 Release Notes (2016-09-07 1.12.1-beta25) - -**Upgrades** - -* Experimental support for OSX 10.12 Sierra (beta) - -**Bug fixes and minor changes** - -* VPNKit supports search domains -* Entries from `/etc/hosts` should now resolve from within containers -* osxfs: fix thread leak - -**Known issues** - -* Several problems have been reported on macOS 10.12 Sierra and are being -investigated. This includes failure to launch the app and being unable to -upgrade to a new version. - -* Docker.app sometimes uses 200% CPU after OS X wakes up from sleep mode. The -issue is being investigated. The workaround is to restart Docker.app - -* There are a number of issues with the performance of directories bind-mounted -with `osxfs`. In particular, writes of small blocks and traversals of large -directories are currently slow. Additionally, containers that perform large -numbers of directory operations, such as repeated scans of large directory -trees, may suffer from poor performance. More information is available in [Known -Issues](troubleshoot.md#known-issues) in Troubleshooting. - -* Under some unhandled error conditions, `inotify` event delivery can fail and become permanently disabled. The workaround is to restart Docker.app. - -### Beta 24 Release Notes (2016-08-23 1.12.1-beta24) - -**Upgrades** - -* Docker 1.12.1 -* Docker Machine 0.8.1 -* Linux kernel 4.4.19 -* aufs 20160822 - -**Bug fixes and minor changes** - -* osxfs: fixed a malfunction of new directories that have the same name as an old directory that is still open - -* osxfs: rename events now trigger DELETE and/or MODIFY `inotify` events (saving with TextEdit works now) - -* slirp: support up to 8 external DNS servers - -* slirp: reduce the number of sockets used by UDP NAT, reduce the probability that NAT rules will time out earlier than expected - -* The app warns user if BlueStacks is installed (potential kernel panic) - -**Known issues** - -* Several problems have been reported on macOS 10.12 Sierra and are being investigated. This includes failure to launch the app and being unable to -upgrade to a new version. - -* `Docker.app` sometimes uses 200% CPU after OS X wakes up from sleep mode. The issue is being investigated. The workaround is to restart `Docker.app`. - -* There are a number of issues with the performance of directories bind-mounted with `osxfs`. In particular, writes of small blocks and traversals of large -directories are currently slow. Additionally, containers that perform large -numbers of directory operations, such as repeated scans of large directory -trees, may suffer from poor performance. For more information and workarounds, see the bullet on [performance of bind-mounted directories](troubleshoot.md#bind-mounted-dirs) in [Known Issues](troubleshoot.md#known-issues) in Troubleshooting. - -* Under some unhandled error conditions, `inotify` event delivery can fail and become permanently disabled. The workaround is to restart `Docker.app`. - -### Beta 23 Release Notes (2016-08-16 1.12.1-rc1-beta23) - -**Upgrades** - -* Docker 1.12.1-rc1 -* Linux kernel 4.4.17 -* aufs 20160808 - -**Bug fixes and minor changes** - -* Moby: use default sysfs settings, transparent huge pages disabled -* Moby: cgroup mount to support systemd in containers -* osxfs: fixed an issue that caused `inotify` failure and crashes -* osxfs: fixed a directory fd leak -* Zsh completions - -**Known issues** - -* Docker for Mac is not supported on OSX 10.12 Sierra - -* Docker.app sometimes uses 200% CPU after OS X wakes up from sleep mode. The issue is being investigated. The workaround is to restart Docker.app - -* There are a number of issues with the performance of directories bind-mounted with `osxfs`. In particular, writes of small blocks and traversals of large directories are currently slow. Additionally, containers that perform large numbers of directory operations, such as repeated scans of large directory trees, may suffer from poor performance. For more information and workarounds, see the bullet on [performance of bind-mounted directories](troubleshoot.md#bind-mounted-dirs) in [Known Issues](troubleshoot.md#known-issues) in Troubleshooting. - -* Under some unhandled error conditions, `inotify` event delivery can fail and become permanently disabled. The workaround is to restart Docker.app - -### Beta 22 Release Notes (2016-08-11 1.12.0-beta22) - -**Upgrades** - -* Linux kernel to 4.4.16 - -**Bug fixes and minor changes** - -* Increase Moby fs.file-max to 524288 -* Use Mac System Configuration database to detect DNS -* HyperKit updated with dtrace support and lock fixes -* Fix Moby Diagnostics and Update Kernel -* UI Fixes -* osxfs: fix socket chowns - -**Known issues** - -* Docker.app sometimes uses 200% CPU after OS X wakes up from sleep mode. The issue is being investigated. The workaround is to restart Docker.app - -* There are a number of issues with the performance of directories bind-mounted with `osxfs`. In particular, writes of small blocks and traversals of large directories are currently slow. Additionally, containers that perform large numbers of directory operations, such as repeated scans of large directory trees, may suffer from poor performance. More information is available in [Known Issues](troubleshoot.md#known-issues) in [Troubleshooting](troubleshoot.md) - -* Under some unhandled error conditions, `inotify` event delivery can fail and become permanently disabled. The workaround is to restart Docker.app - -### Beta 21.1 Release Notes (2016-08-03 1.12.0-beta21.1) - -This bug fix release contains osxfs improvements. The fixed issues may have -been seen as failures with apt-get and npm in containers, missed `inotify` -events or unexpected unmounts. - -**Hotfixes** - -* osxfs: fixed an issue causing access to children of renamed directories to fail (symptoms: npm failures, apt-get failures) (docker/for-mac) - -* osxfs: fixed an issue causing some ATTRIB and CREATE `inotify` events to fail delivery and other `inotify` events to stop - -* osxfs: fixed an issue causing all `inotify` events to stop when an ancestor directory of a mounted directory was mounted - -* osxfs: fixed an issue causing volumes mounted under other mounts to spontaneously unmount (docker/docker#24503) - -#### Docker for Mac 1.12.0 (2016-07-28 1.12.0-beta21) - -**New** - -* Docker for Mac is now available from 2 channels: **stable** and **beta**. New features and bug fixes will go out first in auto-updates to users in the beta channel. Updates to the stable channel are much less frequent and happen in sync with major and minor releases of the Docker engine. Only features that are well-tested and ready for production are added to the stable channel releases. For downloads of both and more information, see the [Getting Started](index.md#download-docker-for-mac). - -**Upgrades** - -* Docker 1.12.0 with experimental features -* Docker Machine 0.8.0 -* Docker Compose 1.8.0 - -**Bug fixes and minor changes** - -* Check for updates, auto-update and diagnose can be run by non-admin users -* osxfs: fixed an issue causing occasional incorrect short reads -* osxfs: fixed an issue causing occasional EIO errors -* osxfs: fixed an issue causing `inotify` creation events to fail -* osxfs: increased the `fs.inotify.max_user_watches` limit in Moby to 524288 -* The UI shows documentation link for sharing volumes -* Clearer error message when running with outdated Virtualbox version -* Added link to sources for qemu-img - -**Known issues** - -* Docker.app sometimes uses 200% CPU after OS X wakes up from sleep mode. The issue is being investigated. The workaround is to restart Docker.app - -* There are a number of issues with the performance of directories bind-mounted with `osxfs`. In particular, writes of small blocks, and traversals of large directories are currently slow. Additionally, containers that perform large numbers of directory operations, such as repeated scans of large directory trees, may suffer from poor performance. For more information and workarounds, see [Known Issues](troubleshoot.md#known-issues) in [Logs and Troubleshooting](troubleshoot.md). - -* Under some unhandled error conditions, `inotify` event delivery can fail and become permanently disabled. The workaround is to restart Docker.app - -### Beta 20 Release Notes (2016-07-19 1.12.0-rc4-beta20) - -**Bug fixes and minor changes** - -* Fixed `docker.sock` permission issues -* Don't check for update when the settings panel opens -* Removed obsolete DNS workaround -* Use the secondary DNS server in more circumstances -* Limit the number of concurrent port forwards to avoid running out of resources -* Store the database as a "bare" git repo to avoid corruption problems - -**Known issues** - -* `Docker.app` sometimes uses 200% CPU after OS X wakes up from sleep mode. The issue is being investigated. The workaround is to restart Docker for Mac (`Docker.app`). - -### Beta 19 Release Notes (2016-07-14 1.12.0-rc4-beta19) - -**New** - -* Added privacy tab in settings -* Allow the definition of HTTP proxy overrides in the UI - -**Upgrades** - -* Docker 1.12.0 RC4 -* Docker Compose 1.8.0 RC2 -* Docker Machine 0.8.0 RC2 -* Linux kernel 4.4.15 - -**Bug fixes and minor changes** - -* Filesystem sharing permissions can only be configured in the UI (no more `/Mac` in moby) -* `com.docker.osx.xhyve.hyperkit`: increased max number of fds to 10240 -* Improved Moby syslog facilities -* Improved file-sharing tab -* `com.docker.slirp`: included the DNS TCP fallback fix, required when UDP responses are truncated -* `docker build/events/logs/stats... ` won't leak when iterrupted with Ctrl-C - -**Known issues** - -* See [Known Issues](troubleshoot.md#known-issues) in [Troubleshooting](troubleshoot.md) - -### Beta 18.1 Release Notes (2016-07-07 1.12.0-rc3-beta18.1) - ->**Note**: Docker 1.12.0 RC3 release introduces a backward incompatible change from RC2. You can fix this by [recreating or updating your containers](troubleshoot.md#recreate-or-update-your-containers-after-beta-18-upgrade) as described in Troubleshooting. - -**Hotfix** - -* Fixed issue resulting in error "Hijack is incompatible with use of CloseNotifier", reverts previous fix for `Ctrl-C` during build. - -**New** - -* New host/container file sharing UI -* `/Mac` bind mount prefix is deprecated and will be removed soon - -**Upgrades** - -* Docker 1.12.0 RC3 - -**Bug fixes and minor changes** - -* VPNKit: Improved scalability as number of network connections increases -* The docker API proxy was failing to deal with some 1.12 features (e.g. health check) - -**Known issues** - -* See [Known Issues](troubleshoot.md#known-issues) in [Troubleshooting](troubleshoot.md) - -### Beta 18 Release Notes (2016-07-06 1.12.0-rc3-beta18) - -**New** - -* New host/container file sharing UI -* `/Mac` bind mount prefix is deprecated and will be removed soon - -**Upgrades** - -* Docker 1.12.0 RC3 - -**Bug fixes and minor changes** - -* VPNKit: Improved scalability as number of network connections increases -* Interrupting a `docker build` with Ctrl-C will actually stop the build -* The docker API proxy was failing to deal with some 1.12 features (e.g. health check) - -**Known issues** - -* See [Known Issues](troubleshoot.md#known-issues) in [Troubleshooting](troubleshoot.md) - -### Beta 17 Release Notes (2016-06-29 1.12.0-rc2-beta17) - -**Upgrades** - -* Linux kernel 4.4.14, aufs 20160627 - -**Bug fixes and minor changes** - -* Documentation moved to https://docs.docker.com/docker-for-mac/ -* Allow non-admin users to launch the app for the first time (using admin creds) -* Prompt non-admin users for admin password when needed in Preferences -* Fixed download links, documentation links -* Fixed "failure: No error" message in diagnostic panel -* Improved diagnostics for networking and logs for the service port openers - -**Known issues** - -* See [Known Issues](troubleshoot.md#known-issues) in [Troubleshooting](troubleshoot.md) - -### Beta 16 Release Notes (2016-06-17 1.12.0-rc2-beta16) - -**Upgrades** - -* Docker 1.12.0 RC2 -* docker-compose 1.8.0 RC1 -* docker-machine 0.8.0 RC1 -* notary 0.3 -* Alpine 3.4 - -**Bug fixes and minor changes** - -* VPNKit: Fixed a regressed error message when a port is in use -* Fixed UI crashing with `NSInternalInconsistencyException` / fixed leak -* HyperKit API: Improved error reporting -* osxfs: fix sporadic EBADF due to fd access/release races (#3683) - - -**Known issues** - -* See [Known Issues](troubleshoot.md#known-issues) in [Troubleshooting](troubleshoot.md) - -### Beta 15 Release Notes (2016-06-10 1.11.2-beta15) - -**New** - -* Registry mirror and insecure registries can now be configured from Preferences -* VM can now be restarted from Preferences -* `sysctl.conf` can be edited from Preferences - -**Upgrades** - -* Docker 1.11.2 -* Linux 4.4.12, `aufs` 20160530 - -**Bug fixes and minor changes** - -* Timekeeping in Moby VM improved -* Number of concurrent TCP/UDP connections increased in VPNKit -* Hyperkit: `vsock` stability improvements -* Fixed crash when user is admin - -**Known issues** - -* See [Known Issues](troubleshoot.md#known-issues) in [Troubleshooting](troubleshoot.md) - -### Beta 14 Release Notes (2016-06-02 1.11.1-beta14) - -**New** - -* New settings menu item, **Diagnose & Feedback**, is available to run diagnostics and upload logs to Docker. - -**Known issues** - -* `Docker.app` sometimes uses 200% CPU after OS X wakes up from sleep mode with OSX 10.10. The issue is being investigated. The workaround is to restart `Docker.app`. - -**Bug fixes and minor changes** - -* `osxfs`: now support `statfs` -* **Preferences**: updated toolbar icons -* Fall back to secondary DNS server if primary fails. -* Added a link to the documentation from menu. - -### Beta 13.1 Release Notes (2016-05-28 1.11.1-beta13.1) - -**Hotfixes** - -* `osxfs`: - - Fixed sporadic EBADF errors and End_of_file crashes due to a race corrupting node table invariants - - Fixed a crash after accessing a sibling of a file moved to another directory caused by a node table invariant violation -* Fixed issue where Proxy settings were applied on network change, causing docker daemon to restart too often -* Fixed issue where log file sizes doubled on docker daemon restart - -### Beta 13 Release Notes (2016-05-25 1.11.1-beta13) - -**New** - -* `osxfs`: Enabled 10ms dcache for 3x speedup on a `go list ./...` test against docker/machine. Workloads heavy in file system path resolution (common among dynamic languages and build systems) will have those resolutions performed in amortized constant time rather than time linear in the depth of the path so speedups of 2-10x will be common. - -* Support multiple users on the same machine, non-admin users can use the app as long as `vmnetd` has been installed. Currently, only one user can be logged in at the same time. - -* Basic support for using system HTTP/HTTPS proxy in docker daemon - -**Known issues** - -* Docker.app sometimes uses 200% CPU after OS X wakes up from sleep mode. The issue is being investigated. The workaround is to restart Docker.app. - -**Bug fixes and minor changes** - -* `osxfs`: - - setting `atime` and `mtime` of nodes is now supported - - Fixed major regression in Beta 12 with ENOENT, ENOTEMPY, and other spurious errors after a directory rename. This manifested as `npm install` failure and other directory traversal issues. - - Fixed temporary file ENOENT errors - - Fixed in-place editing file truncation error (e.g. `perl -i`)w -* improved time synchronisation after sleep - -### Beta 12 Release (2016-05-17 1.11.1-beta12) - -**Upgrades** - -* FUSE 7.23 for [osxfs](osxfs.md) - -**Known issues** - -* Docker.app sometimes uses 200% CPU after OS X wakes up from sleep mode. The issue is being investigated. The workaround is to restart Docker.app. - -**Bug fixes and minor changes** - -* UI improvements -* Fixed a problem in [osxfs](osxfs.md) where`mkdir` returned EBUSY but directory was created. - -### Beta 11 Release (2016-05-10 1.11.1-beta11) - -**New** - -The `osxfs` file system now persists ownership changes in an extended attribute. (See the topic on [ownership](osxfs.md#ownership) in [Sharing the OS X file system with Docker containers](osxfs.md).) - -**Upgrades** - -* docker-compose 1.7.1 (see changelog) -* Linux kernel 4.4.9 - -**Bug fixes and minor changes** - -* Desktop notifications after successful update -* No "update available" popup during install process -* Fixed repeated bind of privileged ports -* `osxfs`: Fixed the block count reported by stat -* Moby (Backend) fixes: - - Fixed `vsock` half closed issue - - Added NFS support - - Hostname is now Moby, not Docker - - Fixes to disk formatting scripts - - Linux kernel upgrade to 4.4.9 - -## Beta 10 Release (2016-05-03 1.11.0-beta10) - -**New** - -* Token validation is now done over an actual SSL tunnel (HTTPS). (This should fix issues with antivirus applictions.) - -**Upgrades** - -* Docker 1.11.1 - -**Bug fixes and minor changes** - -* UCP now starts again -* Include debugging symbols in HyperKit -* vsock stability improvements -* Addressed glitches in **Preferences** panel -* Fixed issues impacting the “whale menu” -* Fixed uninstall process -* HyperKit vcpu state machine improvements, may improve suspend/resume - - -### Beta 9 Release (2016-04-26 1.11.0-beta9) - -**New** - -* New Preferences window - memory and vCPUs now adjustable -* `localhost` is now used for port forwarding by default.`docker.local` will no longer work as of Beta 9. - -**Known issues** - -* Docker.app sometimes uses 200% CPU after OS X wakes up from sleep mode. The issue is being investigated. The workaround is to restart Docker.app. - -**Bug fixes and minor changes** - -* Fix loopback device naming -* Improved docker socket download and osxfs sequential write by 20% -* `com.docker.osxfs` - - improved sequential read throughput by up to 20% - - improved `readdir` performance by up to 6x - - log all fatal exceptions -* More reliable DNS forwarding over UDP and TCP -* UDP ports can be proxied over vsock -* Fixed EADDRINUSE (manifesting as errno 526) when ports are re-used -* Send ICMP when asked to not fragment and we can’t guarantee it -* Fixed parsing of UDP datagrams with IP socket options -* Drop abnormally large ethernet frames -* Improved HyperKit logging -* Record VM start and stop events - -### Beta 8 Release (2016-04-20 1.11.0-beta8) - -**New** - -* Networking mode switched to VPN compatible by default, and as part of this change the overall experience has been improved: - - `docker.local` now works in VPN compatibility mode - - exposing ports on the Mac is available in both networking modes - - port forwarding of privileged ports now works in both networking modes - - traffic to external DNS servers is no longer dropped in VPN mode - - -* `osxfs` now uses `AF_VSOCK` for transport giving ~1.8x speedup for large sequential read/write workloads but increasing latency by ~1.3x. `osxfs` performance engineering work continues. - - -**Known issues** - -* Docker.app sometimes uses 200% CPU after OS X wakes up from sleep mode. The issue is being investigated. The workaround is to restart `Docker.app` - -**Bug fixes and minor changes** - -* Apple System Log now used for most logs instead of direct filesystem logging -* `docker_proxy` fixes -* Merged HyperKit upstream patches -* Improved error reporting in `nat` network mode -* `osxfs` `transfused` client now logs over `AF_VSOCK` -* Fixed a `com.docker.osx.HyperKit.linux` supervisor deadlock if processes exit during a controlled shutdown -* Fixed VPN mode malformed DNS query bug preventing some resolutions - - -### Beta 7 Release (2016-04-12 1.11.0-beta7) - -**New** - -* Docs are updated per the Beta 7 release -* Use AF_VSOCK for docker socket transport - -**Upgrades** - -* docker 1.11.0-rc5 -* docker-machine 0.7.0-rc3 -* docker-compose 1.7.0rc2 - - -**Known issues** - -* Docker.app sometimes uses 200% CPU after OS X wakes up from sleep mode. The issue is being investigated. The workaround is to restart Docker.app - -* If VPN mode is enabled and then disabled and then re-enabled again, `docker ps` will block for 90s - -**Bug fixes and minor changes** - -* Logging improvements -* Improve process management - -## Beta 6 Release (2016-04-05 1.11.0-beta6) - -**New** - -* Docs are updated per the Beta 6 release -* Added uninstall option in user interface - -**Upgrades** - -* docker 1.11.0-rc5 -* docker-machine 0.7.0-rc3 -* docker-compose 1.7.0rc2 - -**Known issues** - -* `Docker.app` sometimes uses 200% CPU after OS X wakes up from sleep mode. -The issue is being investigated. The workaround is to restart -`Docker.app`. - -* If VPN mode is enabled, then disabled and re-enabled again, -`docker ps` will block for 90 seconds. - -**Bug fixes and minor changes** - -* Fixed osxfs multiple same directory bind mounts stopping inotify -* Fixed osxfs `setattr` on mode 0 files (`sed` failures) -* Fixed osxfs blocking all operations during `readdir` -* Fixed osxfs mishandled errors which crashed the file system and VM -* Removed outdated `lofs`/`9p` support -* Added more debugging info to logs uploaded by `pinata diagnose` -* Improved diagnostics from within the virtual machine -* VirtualBox version check now also works without VBoxManage in path -* VPN mode now uses same IP range as NAT mode -* Tokens are now verified on port 443 -* Removed outdated uninstall scripts -* Increased default ulimits -* Port forwarding with `-p` and `-P` should work in VPN mode -* Fixed a memory leak in `com.docker.db` -* Fixed a race condition on startup between Docker and networking which can -lead to `Docker.app` not starting on reboot - -### Beta 5 Release (2016-03-29 1.10.3-beta5) - -**New** - -- Docs are updated per the Beta 5 release! - -**Known issues** - -- There is a race on startup between docker and networking which can lead to Docker.app not starting on reboot. The workaround is to restart the application manually. - -- Docker.app sometimes uses 200% CPU after OS X wakes up from sleep mode. The issue is being investigated. The workaround is to restart Docker.app. - -- In VPN mode, the `-p` option needs to be explicitly of the form `-p :`. `-p ` and `-P` will not work yet. - -**Bug fixes and minor changes** - -- Updated DMG background image -- Show correct VM memory in Preferences -- Feedback opens forum, not email -- Fixed RAM amount error message -- Fixed wording of CPU error dialog -- Removed status from Preferences -- Check for incompatible versions of Virtualbox - -### Beta 4 Release (2016-03-22 1.10.3-beta4) - -**New Features and Upgrades** - - - - - - - - - - - - - - - - - - - -
                    ComponentDescription
                    File System/SharingSupport `inotify` events so that file system events on the - Mac will trigger file system activations inside Linux containers
                    Docker MachineInstall Docker Machine as a part of Docker for Mac install in `/usr/local`
                    Getting Started and About- Added animated popover window to help first-time users get started
                    - Added a Beta icon to About box
                    - -**Known issues** - - - - - - - - - - - - - - - - - - - -
                    ComponentDescription
                    Starting DockerThere is a race on startup between Docker and networking that can lead to `Docker.app` not starting on reboot.

                    The workaround is to restart the application manually. -
                    OS X version support`Docker.app` sometimes uses 200% CPU after OS X wakes up from sleep mode. - The issue is being investigated.

                    The workaround is to restart - `Docker.app`.
                    -
                    VPN/HostnetIn VPN mode, the `-p` option needs to be explicitly of the form - `-p :`. `-p ` and `-P` will not - work yet. -
                    - -**Bug fixes and minor changes** - - - - - - - - - - - - - - - - - - - - - - - -
                    ComponentDescription
                    Hostnet/VPN modeFixed Moby DNS resolver failures by proxying the "Recursion Available" flag.
                    -
                    IP addresses`docker ps` shows IP address rather than `docker.local`. -
                    OS X version support- Re-enabled support for OS X Yosemite version 10.10
                    - Ensured binaries are built for 10.10 rather than 10.11. -
                    Application startup- Fixed "Notification Center"-related crash on startup
                    - Fixed watchdog crash on startup
                    - -### Beta 3 Release (2016-03-15 1.10.3-beta3) - -**New Features and Upgrades** - - - - - - - - - - - - - - - - - - - - - - - -
                    ComponentDescription
                    File SystemImproved file sharing write speed in OSXFS
                    User space networkingRenamed `bridged` mode to `nat` mode
                    DebuggingDocker runs in debug mode by default for new installs -
                    Docker EngineUpgraded to 1.10.3
                    - -**Bug fixes and minor changes** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    ComponentDescription
                    GUIAuto update automatically checks for new versions again
                    -
                    File System- Fixed OSXFS chmod on sockets
                    - - FixED OSXFS EINVAL from `open` using O_NOFOLLOW
                    HypervisorHypervisor stability fixes, resynced with upstream repository
                    Hostnet/VPN mode- Fixed get/set VPN mode in Preferences (GUI)
                    - - Added more verbose logging on errors in `nat` mode
                    - - Show correct forwarding details in `docker ps/inspect/port` in `nat` mode
                    -
                    TokensNew lines ignored in token entry field
                    FeedbackFeedback mail has app version in subject field
                    LicensingClarified open source licenses
                    Crash reporting and error handling- Fixed HockeyApp crash reporting
                    - - Fatal GUI errors now correctly terminate the app again
                    - - Fix proxy panics on EOF when decoding JSON
                    - - Fix long delay/crash when switching from `hostnet` to `nat` mode -
                    Logging- Moby logs included in diagnose upload
                    - - App version included in logs on startup -
                    - - -### Beta 2 Release (2016-03-08 1.10.2-beta2) - -**New Features and Upgrades** - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    ComponentDescription
                    GUIAdd VPN mode/`hostnet` to Preferences
                    Add disable Time Machine backups of VM disk image to Preferences
                    CLIAdded `pinata` configuration tool for experimental Preferences
                    File SystemAdd guest-to-guest FIFO and socket file support
                    NotaryUpgraded to version 0.2
                    - -**Bug fixes** - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    ComponentDescription
                    File SystemFixed data corruption bug during cp (use of sendfile/splice)
                    GUIFixed About box to contain correct version string
                    Hostnet/VPN mode- Stability fixes and tests
                    - Fixed DNS issues when changing networks
                    MobyCleaned up Docker startup code
                    Linking and dependenciesFixed various problems
                    LoggingVarious improvements
                    - -

                     

                    - -### Beta 1 Release (2016-03-01 1.10.2-b1) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    ComponentDescription
                    GUIAdded dialog to explain why we need admin rights
                    Removed shutdown/quit window
                    Improved machine migration
                    Added "Help" option in menu to open documentation web pages
                    Added license agreement
                    Added MixPanel support
                    Crash ReportsAdd HockeyApp crash reporting
                    Task ManagerImprove signal handling
                    LoggingUse ISO timestamps with microsecond precision
                    Clean up logging format
                    PackagingCreate /usr/local if it doesn't exist
                    docker-uninstall improvements
                    Remove docker-select as it's no longer used
                    HypervisorAdd PID file
                    Networking reliability improvements
                    HostnetFixed port forwarding issue
                    Stability fixes
                    Fixed setting hostname
                    SymlinksFixed permissions on `usr/local` symbolic links
                    - -
                    -
                      - diff --git a/docker-for-mac/troubleshoot.md b/docker-for-mac/troubleshoot.md deleted file mode 100644 index 874478122c..0000000000 --- a/docker-for-mac/troubleshoot.md +++ /dev/null @@ -1,332 +0,0 @@ - - -# Logs and Troubleshooting - -Here is information about how to diagnose and troubleshoot problems, send logs and communicate with the Docker for Mac team, use our forums and Knowledge Hub, browse and log issues on GitHub, and find workarounds for known problems. - -## Docker Knowledge Hub - -**Looking for help with Docker for Mac?** Check out the [Docker Knowledge Hub](http://success.docker.com/) for knowledge base articles, FAQs, and technical support for various subscription levels. - -## Diagnose problems, send feedback, and create GitHub issues - -If you encounter problems for which you do not find solutions in this documentation, [Docker for Mac issues on GitHub](https://github.com/docker/for-mac/issues) already filed by other users, or on the [Docker for Mac forum](https://forums.docker.com/c/docker-for-mac), we can help you troubleshoot the log data. - -Choose --> **Diagnose & Feedback** from the menu bar. - -![Diagnose problems](images/settings-diagnose.png) - -You can choose to run diagnostics only, or diagnose and send the results to the Docker Team: - -* **Diagnose Only** - Runs diagnostics, and shows results locally. (Results are not sent to Docker, and no ID is generated.) - -![Diagnostic results only](images/settings-diagnostic-results-only.png) - -* **Diagnose & Upload** - Runs diagnostics, shows results, and auto-uploads the diagnostic results to Docker. A diagnostic ID is auto-generated. You can refer to this ID when communicating with the Docker Team. Optionally, you can open an issue on GitHub using the uploaded results and ID as a basis. - -![Diagnostics & Feedback](images/settings-diagnose-id.png) - -If you click **Open Issues**, this opens [Docker for Mac issues on GitHub](https://github.com/docker/for-mac/issues/) in your web browser in a “create new issue” template prepopulated with the following: - -* ID and summary of the diagnostic you just ran - -* System and version details - -* Sections where you can fill in a description of expected and actual behavior, and steps to reproduce the issue - -![Create issue on GitHub](images/diagnose-issue.png) - -You can also create a new issue directly on GitHub at https://github.com/docker/for-mac/issues. (The README for the repository is [here](https://github.com/docker/for-mac).) - -Click [New Issue](https://github.com/docker/for-mac/issues/new) on that page (or right here ☺) to get a "create new issue" template prepopulated with sections for the ID and summary of your diagnostics, system and version details, description of expected and actual behavior, and steps to reproduce the issue. - -![issue template](images/diagnose-d4mac-issues-template.png) - - -## Checking the logs - -In addition to using the diagnose and feedback option to submit logs, you can browse the logs yourself. - -#### Use the command line to view logs - -To view Docker for Mac logs at the command line, type this command in a terminal window or your favorite shell. - - $ syslog -k Sender Docker - -Alternatively, you can send the output of this command to a file. The following command redirects the log output to a file called `my_docker_logs.txt`. - - $ syslog -k Sender Docker > ~/Desktop/my_docker_logs.txt - -#### Use the Mac Console for log queries - -Macs provide a built-in log viewer. You can use the Mac Console System Log Query to check Docker app logs. - -The Console lives on your Mac hard drive in `Applications` > `Utilities`. You can bring it up quickly by just searching for it with Spotlight Search. - -To find all Docker app log messages, do the following. - -1. From the Console menu, choose **File** > **New System Log Query...** - - ![Mac Console search for Docker app](images/console_logs_search.png) - - * Name your search (for example `Docker`) - * Set the **Sender** to **Docker** - -2. Click **OK** to run the log query. - - ![Mac Console display of Docker app search results](images/console_logs.png) - -You can use the Console Log Query to search logs, filter the results in various ways, and create reports. - -For example, you could construct a search for log messages sent by Docker that contain the word `hypervisor` then filter the results by time (earlier, later, now). - -The diagnostics and usage information to the left of the results provide auto-generated reports on packages. - - -## Troubleshooting - -#### Recreate or update your containers after Beta 18 upgrade - -Docker 1.12.0 RC3 release introduces a backward incompatible change from RC2 to RC3. (For more information, see https://github.com/docker/docker/issues/24343#issuecomment-230623542.) - -You may get the following error when you try to start a container created with pre-Beta 18 Docker for Mac applications. - - Error response from daemon: Unknown runtime specified default - -You can fix this by either [recreating](#recreate-your-containers) or [updating](#update-your-containers) your containers. - -If you get the error message shown above, we recommend recreating them. - -##### Recreate your containers - -To recreate your containers, use Docker Compose. - - docker-compose down && docker-compose up - -##### Update your containers - -To fix existing containers, follow these steps. - -1. Run this command. - - $ docker run --rm -v /var/lib/docker:/docker cpuguy83/docker112rc3-runtimefix:rc3 - - Unable to find image 'cpuguy83/docker112rc3-runtimefix:rc3' locally - rc3: Pulling from cpuguy83/docker112rc3-runtimefix - 91e7f9981d55: Pull complete - Digest: sha256:96abed3f7a7a574774400ff20c6808aac37d37d787d1164d332675392675005c - Status: Downloaded newer image for cpuguy83/docker112rc3-runtimefix:rc3 - proccessed 1648f773f92e8a4aad508a45088ca9137c3103457b48be1afb3fd8b4369e5140 - skipping container '433ba7ead89ba645efe9b5fff578e674aabba95d6dcb3910c9ad7f1a5c6b4538': already fixed - proccessed 43df7f2ac8fc912046dfc48cf5d599018af8f60fee50eb7b09c1e10147758f06 - proccessed 65204cfa00b1b6679536c6ac72cdde1dbb43049af208973030b6d91356166958 - proccessed 66a72622e306450fd07f2b3a833355379884b7a6165b7527c10390c36536d82d - proccessed 9d196e78390eeb44d3b354d24e25225d045f33f1666243466b3ed42fe670245c - proccessed b9a0ecfe2ed9d561463251aa90fd1442299bcd9ea191a17055b01c6a00533b05 - proccessed c129a775c3fa3b6337e13b50aea84e4977c1774994be1f50ff13cbe60de9ac76 - proccessed dea73dc21126434f14c58b83140bf6470aa67e622daa85603a13bc48af7f8b04 - proccessed dfa8f9278642ab0f3e82ee8e4ad029587aafef9571ff50190e83757c03b4216c - proccessed ee5bf706b6600a46e5d26327b13c3c1c5f7b261313438d47318702ff6ed8b30b - -2. Quit Docker. - -3. Start Docker. - - > **Note:** Be sure to quit and then restart Docker for Mac before attempting to start containers. - -4. Try to start the container again: - - $ docker start old-container - old-container - -#### Incompatible CPU detected - -Docker for Mac requires a processor (CPU) that supports virtualization and, more specifically, the [Apple Hypervisor framework](https://developer.apple.com/library/mac/documentation/DriversKernelHardware/Reference/Hypervisor/). Docker for Mac is only compatible with Macs that have a CPU that supports the Hypervisor framework. Most Macs built in 2010 and later support it, as described in the Apple Hypervisor Framework documentation about supported hardware: - -*Generally, machines with an Intel VT-x feature set that includes Extended Page Tables (EPT) and Unrestricted Mode are supported.* - -To check if your Mac supports the Hypervisor framework, run this command in a terminal window. - -``` -sysctl kern.hv_support -``` -If your Mac supports the Hypervisor Framework, the command will print `kern.hv_support: 1`. - -If not, the command will print `kern.hv_support: 0`. - -See also, [Hypervisor Framework Reference](https://developer.apple.com/library/mac/documentation/DriversKernelHardware/Reference/Hypervisor/) in the Apple documentation, and Docker for Mac system requirements in [What to know before you install](index.md#what-to-know-before-you-install). - - -#### Workarounds for common problems - -* IPv6 workaround to auto-filter DNS addresses - IPv6 is not yet supported on Docker for Mac, which typically manifests as a network timeout when running `docker` commands that need access to external network servers (e.g., `docker pull busybox`). - - ``` - $ docker pull busybox - Using default tag: latest - Pulling repository docker.io/library/busybox - Network timed out while trying to connect to https://index.docker.io/v1/repositories/library/busybox/images. You may want to check your internet connection or if you are behind a proxy. - ``` - - Starting with v1.12.1, 2016-09016 on the stable channel, and Beta 24 on the beta channel, a workaround is provided that auto-filters out the IPv6 addresses in DNS server lists and enables successful network accesss. For example, `2001:4860:4860::8888` would become `8.8.8.8`. So, the only workaround action needed for users is to [upgrade to Docker for Mac stable v1.12.1 or newer, or Beta 24 or newer](index.md#download-docker-for-mac). - - On releases with the workaround included to filter out / truncate IPv6 addresses from the DNS list, the above command should run properly: - - ``` - $ docker pull busybox - Using default tag: latest - latest: Pulling from library/busybox - Digest: sha256:a59906e33509d14c036c8678d687bd4eec81ed7c4b8ce907b888c607f6a1e0e6 - Status: Image is up to date for busy box:latest - ``` - - To learn more, see these issues on GitHub and Docker for Mac forums: - - * [Network timeout when top two DNS servers in /etc/resolv.conf are IPv6 addresses](https://github.com/docker/for-mac/issues/9) - - * [ERROR: Network timed out while trying to connect to index.docker.io](https://forums.docker.com/t/error-network-timed-out-while-trying-to-connect-to-index-docker-io/17206) - -* If Docker for Mac fails to install or start properly: - * Make sure you quit Docker for Mac before installing a new version of the application ( --> **Quit Docker**). Otherwise, you will get an "application in use" error when you try to copy the new app from the `.dmg` to `/Applications`. - - * Restart your Mac to stop / discard any vestige of the daemon running from the previously installed version. - - * Run the the uninstall commands from the menu. - -

                      - -* If `docker` commands aren't working properly or as expected: - - Make sure you are not using the legacy Docker Machine environment in your shell -or command window. You do not need `DOCKER_HOST` set, so unset it as it may be -pointing at another Docker (e.g. VirtualBox). If you use bash, `unset -${!DOCKER_*}` will unset existing `DOCKER` environment variables you have set. -For other shells, unset each environment variable individually as described in -[Setting up to run Docker for -Mac](docker-toolbox.md#setting-up-to-run-docker-for-mac) in [Docker for Mac vs. -Docker Toolbox](docker-toolbox.md). - -

                      - -* Note that network connections will fail if the OS X Firewall is set to -"Block all incoming connections". You can enable the firewall, but `bootpd` must be allowed incoming connections so that the VM can get an IP address. - -

                      - -* For the `hello-world-nginx` example, Docker for Mac must be running in order to get to the webserver on `http://localhost/`. Make sure that the Docker whale -is showing in the menu bar, and that you run the Docker commands in a shell that -is connected to the Docker for Mac Engine (not Engine from Toolbox). Otherwise, -you might start the webserver container but get a "web page not available" error -when you go to `localhost`. For more on distinguishing between the two -environments, see [Docker for Mac vs. Docker Toolbox](docker-toolbox.md). - -

                      - -* If you see errors like `Bind for 0.0.0.0:8080 failed: port is already allocated` or - `listen tcp:0.0.0.0:8080: bind: address is already in use`: - - These errors are often caused by some other software on the Mac using those ports. - Run `lsof -i tcp:8080` to discover the name and pid of the other process and - decide whether to shut the other process down, or to use a different port in - your docker app. - -See also [Known Issues](#known-issues) on this page, and the [FAQs](faqs.md) topic. - - -## Known issues - -* IPv6 is not yet supported on Docker for Mac. If you are using IPv6, and haven't upgraded to Beta 24 or v1.12.1 stable or newer, you will see a network -timeout when you run `docker` commands that need access to external network -servers. The aforementioned releases include a workaround for this because -Docker for Mac does not yet support IPv6. See "IPv6 workaround to auto-filter DNS addresses" in -[Workarounds for common problems](#workarounds-for-common-problems). - -* You might encounter errors when using `docker-compose up` with Docker for Mac (`ValueError: Extra Data`). We've identified this is likely related to data and/or events being passed all at once rather than one by one, so sometimes the data comes back as 2+ objects concatenated and causes an error. - -

                      - -* Force-ejecting the `.dmg` after running `Docker.app` from it results in an unresponsive whale in the menu bar, Docker tasks "not responding" in activity monitor, helper processes running, and supporting technologies consuming large percentages of CPU. Please reboot, and then re-start Docker for Mac. If needed,`force quit` any Docker related applications as part of the reboot. - -

                      - -* Docker does not auto-start on login even when it is enabled in --> **Preferences**. This is related to a set of issues with Docker helper, registration, and versioning. - -

                      - -* Docker for Mac uses the `HyperKit` hypervisor (https://github.com/docker/hyperkit) in Mac OS X 10.10 Yosemite and higher. If you are developing with tools that have conflicts with `HyperKit`, such as [Intel Hardware Accelerated Execution Manager (HAXM)](https://software.intel.com/en-us/android/articles/intel-hardware-accelerated-execution-manager/), the current workaround is not to run them at the same time. You can pause `HyperKit` by quitting Docker for Mac temporarily while you work with HAXM. This will allow you to continue work with the other tools and prevent `HyperKit` from interfering. - -

                      - -* If you are working with applications like [Apache Maven](https://maven.apache.org/) that expect settings for `DOCKER_HOST` and `DOCKER_CERT_PATH` environment variables, specify these to connect to Docker instances through Unix sockets. For example: - - export DOCKER_HOST=unix:///var/run/docker.sock - -* `docker-compose` 1.7.1 performs DNS unnecessary lookups for `localunixsocket.local` which can take 5s to timeout on some networks. If `docker-compose` commands seem very slow but seem to speed up when the network is disabled (e.g. when disconnected from wifi), try appending `127.0.0.1 localunixsocket.local` to the file `/etc/hosts`. -Alternatively you could create a plain-text TCP proxy on localhost:1234 using: - - docker run -d -v /var/run/docker.sock:/var/run/docker.sock -p 127.0.0.1:1234:1234 bobrik/socat TCP-LISTEN:1234,fork UNIX-CONNECT:/var/run/docker.sock - - and then `export DOCKER_HOST=tcp://localhost:1234`. - -

                      - - - -* There are a number of issues with the performance of directories - bind-mounted with `osxfs`. In particular, writes of small blocks, and - traversals of large directories are currently slow. Additionally, - containers that perform large numbers of directory operations, such as - repeated scans of large directory trees, may suffer from poor - performance. Applications that behave in this way include: - - - `rake` - - `ember build` - - Symfony - - Magento - - As a work-around for this behavior, you can put vendor or third-party library directories in Docker volumes, perform temporary file system - operations outside of `osxfs` mounts, and use third-party tools like - Unison or `rsync` to synchronize between container directories and - bind-mounted directories. We are actively working on `osxfs` - performance using a number of different techniques and we look forward - to sharing improvements with you soon. - -

                      - -* If your system does not have access to an NTP server, then after a hibernate the time seen by Docker for Mac may be considerably out of sync with the host. Furthermore, the time may slowly drift out of sync during use. To manually reset the time after hibernation, run: - - docker run --rm --privileged alpine hwclock -s - - Or, to resolve both issues, you can add the local clock as a low-priority (high stratum) fallback NTP time source for the host. To do this, edit the host's `/etc/ntp-restrict.conf` to add: - - server 127.127.1.1 # LCL, local clock - fudge 127.127.1.1 stratum 12 # increase stratum - - Then restart the NTP service with: - - sudo launchctl unload /System/Library/LaunchDaemons/org.ntp.ntpd.plist - sudo launchctl load /System/Library/LaunchDaemons/org.ntp.ntpd.plist - -
                      -
                        - diff --git a/docker-for-windows/examples.md b/docker-for-windows/examples.md deleted file mode 100644 index f3c41c7ee8..0000000000 --- a/docker-for-windows/examples.md +++ /dev/null @@ -1,38 +0,0 @@ - - -# Example Applications - -Upcoming releases will include example applications especially tailored for Docker for Mac and Docker for Windows. - -Examples will highlight develop, build, and run workfows in several languages, including Node.js, Python, Ruby, and Java. - -For now, if you want get started experimenting with the Beta apps and Docker Compose (which is installed automatically with Docker Desktop Editions), have a look at these example applications in the Compose documentation. You should be able to run these with Docker for Mac and Docker for Windows. - -Quickstart: Compose and Django - -Quickstart: Compose and Rails - -Quickstart: Compose and WordPress - -See also [learn by example](/engine/tutorials/index.md) tutorials on building images, runnning containers, networking, managing data, and storing images on Docker Hub. - -
                        -
                          - diff --git a/docker-for-windows/faqs.md b/docker-for-windows/faqs.md deleted file mode 100644 index 3ecfc94172..0000000000 --- a/docker-for-windows/faqs.md +++ /dev/null @@ -1,153 +0,0 @@ - - -# Frequently Asked Questions (FAQs) - - ->**Looking for popular FAQs on Docker for Windows?** Check out the [Docker -Knowledge Hub](http://success.docker.com/) for knowledge base articles, FAQs, -technical support for various subscription levels, and more. - -### Questions about stable and beta channels - -**Q: How do I get the stable or beta version of Docker for Windows?** - -A: Use the download links for the channels given in the topic [Download Docker -for Windows](index.md#download-docker-for-windows). - -This topic also has more information about the two channels. - -**Q: What is the difference between the stable and beta versions of Docker for Windows?** - -A: Two different download channels are available for Docker for Windows: - -* The stable channel provides a general availability release-ready installer for a fully baked and tested, more reliable app. The stable version of Docker for Windows comes with the latest released version of Docker Engine. The release schedule is synched with Docker Engine releases and hotfixes. - -* The beta channel provides an installer with new features we are working on, but is not necessarily fully tested. It comes with the experimental version of Docker Engine. Bugs, crashes and issues are more likely to occur with the beta app, but you get a chance to preview new functionality, experiment, and provide feedback as the apps evolve. Releases are typically more frequent than for stable, often one or more per month. - -**Q: Can I switch back and forth between stable and beta versions of Docker for Windows?** - -A: Yes, you can switch between versions to try out the betas to see what's new, -then go back to stable for other work. However, **you can have only one app -installed at a time**. Switching back and forth between stable and beta apps can -de-stabilize your development environment, particularly in cases where you -switch from a newer (beta) channel to older (stable). - -For example, containers created with a newer beta version of Docker for Windows -may not work after you switch back to stable because they may have been created -leveraging beta features that aren't in stable yet. Just keep this in mind as -you create and work with beta containers, perhaps in the spirit of a playground -space where you are prepared to troubleshoot or start over. - -To safely switch between beta and stable versions be sure -to save images and export the containers you need, then uninstall the current -version before installing another. The workflow is described in more detail -below.
                          - -Do the following each time: - -1. Use `docker save` to save any images you want to keep. (See -[save](/engine/reference/commandline/save.md) in the Docker Engine command line -reference.) - -2. Use `docker export` to export containers you want to keep. (See -[export](/engine/reference/commandline/export.md) in the Docker Engine command -line reference.) - -3. Uninstall the current app (whether stable or beta). - -4. Install a different version of the app (stable or beta). - -### What kind of feedback are we looking for? - -Everything is fair game. We'd like your impressions on the download-install -process, startup, functionality available, the GUI, usefulness of the app, -command line integration, and so on. Tell us about problems, what you like, or -functionality you'd like to see added. - -We are especially interested in getting feedback on the new swarm mode described -in [Docker Swarm](/engine/swarm/index.md). A good place to start is the -[tutorial](/engine/swarm/swarm-tutorial/index.md). - -### What if I have problems or questions? - -You can find the list of frequent issues in -[Logs and Troubleshooting](troubleshoot.md). - -If you do not find a solution in Troubleshooting, browse issues on [Docker for Windows issues on GitHub](https://github.com/docker/for-win/issues) or create a new one. You can also create new issues based on diagnostics. To learn more about running diagnostics and about Docker for Windows GitHub issues, see [Diagnose and Feedback](index.md#diagnose-and-feedback). - -[Docker for Windows forum](https://forums.docker.com/c/docker-for-windows) provides discussion threads as well, and you can create discussion topics there, but we recommend using the GitHub issues over the forums for better tracking and response. - -### Can I use Docker for Windows with new swarm mode? - -Yes! You can use Docker for Windows to test single-node features of [swarm mode](/engine/swarm/index.md) introduced with Docker Engine 1.12, including initializing a swarm with a single node, creating services, and scaling services. Docker “Moby” on Hyper-V will serve as the single swarm node. You can also use Docker Machine, which comes with Docker for Windows, to create and experiment with a multi-node swarm. Check out the tutorial at [Get started with swarm mode](/engine/swarm/swarm-tutorial/index.md). - -### How do I connect to the remote Docker Engine API? - -You might need to provide the location of the remote API for Docker clients and development tools. - -On Docker for Windows, clients can connect to the Docker Engine through a **named pipe**: `npipe:////./pipe/docker_engine`, or **TCP socket** at this URL: `http://localhost:2375`. - -This sets `DOCKER_HOST` and `DOCKER_CERT_PATH` environment variables to the given values (for the named pipe or TCP socket, whichever you use). - -See also [Docker Remote API](/engine/reference/api/docker_remote_api.md) and the Docker for Windows forums topic [How to find the remote API](https://forums.docker.com/t/how-to-find-the-remote-api/20988). - -### Why doesn't `nodemon` pick up file changes in a container mounted on a shared drive? - -Currently, `inotify` does not work on Docker for Windows. This is a known issue. -For more information and a temporary workaround, see [inotify on shared drives -does not work](troubleshoot.md#inotify-on-shared-drives-does-not-work) in -[Troubleshooting](troubleshoot.md). - -### Why does Docker for Windows sometimes lose network connectivity (e.g., `push`/`pull` doesn't work)? - -Networking is not yet fully stable across network changes and system sleep -cycles. Exit and start Docker to restore connectivity. - -### Can I use VirtualBox alongside Docker 4 Windows? - -Unfortunately, VirtualBox (and other hypervisors like VMWare) cannot run when -Hyper-V is enabled on Windows. - -### Why is Windows 10 Home not supported? - -Docker for Windows requires the Hyper-V Windows feature which is not -available on Home-edition. - -### Why is Windows 10 required? - -Docker for Windows uses Windows Hyper-V. While older Windows versions have -Hyper-V, their Hyper-V implementations lack features critical for Docker for -Windows to work. - -### Why does Docker for Windows fail to start when firewalls or anti-virus software is installed? - -Comodo Firewall currently is incompatible with Hyper-V and some Windows 10 builds (possibly, the Anniversary Update), which impacts Docker for Windows. Other firewalls and anti-virus software might also be incompatible with these Microsoft Windows 10 buids. See details and workarounds in [Docker fails to start when Comodo Firewall is installed](troubleshoot.md#docker-fails-to-start-when-comodo-firewall-is-installed) in [Troubleshooting](troubleshoot.md). - - -### How do I uninstall Docker Toolbox? - -You might decide that you do not need Toolbox now that you have Docker for Windows, and want to uninstall it. For -details on how to perform a clean uninstall of Toolbox on Windows, see [How to -uninstall Toolbox](/toolbox/toolbox_install_windows.md#how-to-uninstall-toolbox) -in the Toolbox Windows topics. - -
                          -
                            - diff --git a/docker-for-windows/images/Config-popup.png b/docker-for-windows/images/Config-popup.png deleted file mode 100644 index 0ad3186996..0000000000 Binary files a/docker-for-windows/images/Config-popup.png and /dev/null differ diff --git a/docker-for-windows/images/Docker-win-settings.png b/docker-for-windows/images/Docker-win-settings.png deleted file mode 100755 index 626956187f..0000000000 Binary files a/docker-for-windows/images/Docker-win-settings.png and /dev/null differ diff --git a/docker-for-windows/images/Start-Authorize.png b/docker-for-windows/images/Start-Authorize.png deleted file mode 100644 index 292c3cc8f3..0000000000 Binary files a/docker-for-windows/images/Start-Authorize.png and /dev/null differ diff --git a/docker-for-windows/images/Start-init.png b/docker-for-windows/images/Start-init.png deleted file mode 100644 index fb2e93dc62..0000000000 Binary files a/docker-for-windows/images/Start-init.png and /dev/null differ diff --git a/docker-for-windows/images/about-docker-win.png b/docker-for-windows/images/about-docker-win.png deleted file mode 100644 index a7495e933c..0000000000 Binary files a/docker-for-windows/images/about-docker-win.png and /dev/null differ diff --git a/docker-for-windows/images/chat.png b/docker-for-windows/images/chat.png deleted file mode 100644 index 597db5aae9..0000000000 Binary files a/docker-for-windows/images/chat.png and /dev/null differ diff --git a/docker-for-windows/images/config-popup-menu-win-switch-containers.png b/docker-for-windows/images/config-popup-menu-win-switch-containers.png deleted file mode 100644 index 8a7a0ed12f..0000000000 Binary files a/docker-for-windows/images/config-popup-menu-win-switch-containers.png and /dev/null differ diff --git a/docker-for-windows/images/config-popup-menu-win.png b/docker-for-windows/images/config-popup-menu-win.png deleted file mode 100644 index 99a3461cd9..0000000000 Binary files a/docker-for-windows/images/config-popup-menu-win.png and /dev/null differ diff --git a/docker-for-windows/images/desktop-whale-icon.png b/docker-for-windows/images/desktop-whale-icon.png deleted file mode 100644 index 7781fe1770..0000000000 Binary files a/docker-for-windows/images/desktop-whale-icon.png and /dev/null differ diff --git a/docker-for-windows/images/diagnose-d4win-issues-template.png b/docker-for-windows/images/diagnose-d4win-issues-template.png deleted file mode 100644 index c0715a37c5..0000000000 Binary files a/docker-for-windows/images/diagnose-d4win-issues-template.png and /dev/null differ diff --git a/docker-for-windows/images/diagnose-feedback-id-win.png b/docker-for-windows/images/diagnose-feedback-id-win.png deleted file mode 100644 index 6f76d516f6..0000000000 Binary files a/docker-for-windows/images/diagnose-feedback-id-win.png and /dev/null differ diff --git a/docker-for-windows/images/diagnose-feedback-win.png b/docker-for-windows/images/diagnose-feedback-win.png deleted file mode 100644 index d4e68f2dde..0000000000 Binary files a/docker-for-windows/images/diagnose-feedback-win.png and /dev/null differ diff --git a/docker-for-windows/images/docker-daemon.png b/docker-for-windows/images/docker-daemon.png deleted file mode 100644 index 2ca6ab3c62..0000000000 Binary files a/docker-for-windows/images/docker-daemon.png and /dev/null differ diff --git a/docker-for-windows/images/docker-is-running.png b/docker-for-windows/images/docker-is-running.png deleted file mode 100644 index 06b2557ada..0000000000 Binary files a/docker-for-windows/images/docker-is-running.png and /dev/null differ diff --git a/docker-for-windows/images/download.png b/docker-for-windows/images/download.png deleted file mode 100644 index bfa896d89e..0000000000 Binary files a/docker-for-windows/images/download.png and /dev/null differ diff --git a/docker-for-windows/images/hyper-v-message.png b/docker-for-windows/images/hyper-v-message.png deleted file mode 100644 index cd3c557814..0000000000 Binary files a/docker-for-windows/images/hyper-v-message.png and /dev/null differ diff --git a/docker-for-windows/images/import-docker-content.png b/docker-for-windows/images/import-docker-content.png deleted file mode 100644 index 9b5fce2cbc..0000000000 Binary files a/docker-for-windows/images/import-docker-content.png and /dev/null differ diff --git a/docker-for-windows/images/installer-allow.png b/docker-for-windows/images/installer-allow.png deleted file mode 100644 index 4fd2d4dcc3..0000000000 Binary files a/docker-for-windows/images/installer-allow.png and /dev/null differ diff --git a/docker-for-windows/images/installer-finishes.png b/docker-for-windows/images/installer-finishes.png deleted file mode 100644 index daa793b35d..0000000000 Binary files a/docker-for-windows/images/installer-finishes.png and /dev/null differ diff --git a/docker-for-windows/images/installer-in-downloads.png b/docker-for-windows/images/installer-in-downloads.png deleted file mode 100644 index f246d47911..0000000000 Binary files a/docker-for-windows/images/installer-in-downloads.png and /dev/null differ diff --git a/docker-for-windows/images/installer-license-ok.png b/docker-for-windows/images/installer-license-ok.png deleted file mode 100644 index 49a3fe9b6f..0000000000 Binary files a/docker-for-windows/images/installer-license-ok.png and /dev/null differ diff --git a/docker-for-windows/images/installer-license-show.png b/docker-for-windows/images/installer-license-show.png deleted file mode 100644 index 11e075a60e..0000000000 Binary files a/docker-for-windows/images/installer-license-show.png and /dev/null differ diff --git a/docker-for-windows/images/installer-progress-bar.png b/docker-for-windows/images/installer-progress-bar.png deleted file mode 100644 index d56cbff463..0000000000 Binary files a/docker-for-windows/images/installer-progress-bar.png and /dev/null differ diff --git a/docker-for-windows/images/proxies.png b/docker-for-windows/images/proxies.png deleted file mode 100644 index 1e2c2b125a..0000000000 Binary files a/docker-for-windows/images/proxies.png and /dev/null differ diff --git a/docker-for-windows/images/run-nginx.png b/docker-for-windows/images/run-nginx.png deleted file mode 100644 index 01f5fa66e5..0000000000 Binary files a/docker-for-windows/images/run-nginx.png and /dev/null differ diff --git a/docker-for-windows/images/settings-cpu-ram.png b/docker-for-windows/images/settings-cpu-ram.png deleted file mode 100644 index 6eb39d3c46..0000000000 Binary files a/docker-for-windows/images/settings-cpu-ram.png and /dev/null differ diff --git a/docker-for-windows/images/settings-docker-win.png b/docker-for-windows/images/settings-docker-win.png deleted file mode 100644 index 9847392c71..0000000000 Binary files a/docker-for-windows/images/settings-docker-win.png and /dev/null differ diff --git a/docker-for-windows/images/settings-general.png b/docker-for-windows/images/settings-general.png deleted file mode 100644 index c92b672e0a..0000000000 Binary files a/docker-for-windows/images/settings-general.png and /dev/null differ diff --git a/docker-for-windows/images/settings-kernel.png b/docker-for-windows/images/settings-kernel.png deleted file mode 100644 index 69e47658d9..0000000000 Binary files a/docker-for-windows/images/settings-kernel.png and /dev/null differ diff --git a/docker-for-windows/images/settings-network.png b/docker-for-windows/images/settings-network.png deleted file mode 100644 index 52896a8e56..0000000000 Binary files a/docker-for-windows/images/settings-network.png and /dev/null differ diff --git a/docker-for-windows/images/settings-reset.png b/docker-for-windows/images/settings-reset.png deleted file mode 100644 index 3dd220ec84..0000000000 Binary files a/docker-for-windows/images/settings-reset.png and /dev/null differ diff --git a/docker-for-windows/images/settings-shared-drives.png b/docker-for-windows/images/settings-shared-drives.png deleted file mode 100644 index 4b81036d9b..0000000000 Binary files a/docker-for-windows/images/settings-shared-drives.png and /dev/null differ diff --git a/docker-for-windows/images/settings-toolbox-import.png b/docker-for-windows/images/settings-toolbox-import.png deleted file mode 100644 index 60fc6398b2..0000000000 Binary files a/docker-for-windows/images/settings-toolbox-import.png and /dev/null differ diff --git a/docker-for-windows/images/submit-token.png b/docker-for-windows/images/submit-token.png deleted file mode 100644 index 538460e9ce..0000000000 Binary files a/docker-for-windows/images/submit-token.png and /dev/null differ diff --git a/docker-for-windows/images/whale-systray.png b/docker-for-windows/images/whale-systray.png deleted file mode 100644 index ba6f8f1a8b..0000000000 Binary files a/docker-for-windows/images/whale-systray.png and /dev/null differ diff --git a/docker-for-windows/images/whale-x.png b/docker-for-windows/images/whale-x.png deleted file mode 100644 index c99e8d5898..0000000000 Binary files a/docker-for-windows/images/whale-x.png and /dev/null differ diff --git a/docker-for-windows/images/win-file-and-printer-sharing.png b/docker-for-windows/images/win-file-and-printer-sharing.png deleted file mode 100644 index 7f53c8bba9..0000000000 Binary files a/docker-for-windows/images/win-file-and-printer-sharing.png and /dev/null differ diff --git a/docker-for-windows/images/win-install-success-hello-world.png b/docker-for-windows/images/win-install-success-hello-world.png deleted file mode 100644 index d269096013..0000000000 Binary files a/docker-for-windows/images/win-install-success-hello-world.png and /dev/null differ diff --git a/docker-for-windows/images/win-install-success-popup.png b/docker-for-windows/images/win-install-success-popup.png deleted file mode 100644 index 69159c7fdf..0000000000 Binary files a/docker-for-windows/images/win-install-success-popup.png and /dev/null differ diff --git a/docker-for-windows/images/win-install-success.png b/docker-for-windows/images/win-install-success.png deleted file mode 100644 index a170536a37..0000000000 Binary files a/docker-for-windows/images/win-install-success.png and /dev/null differ diff --git a/docker-for-windows/index.md b/docker-for-windows/index.md deleted file mode 100644 index 9e64fc4cb9..0000000000 --- a/docker-for-windows/index.md +++ /dev/null @@ -1,429 +0,0 @@ - - -# Getting Started with Docker for Windows - -Welcome to Docker for Windows! - -Please read through these topics on how to get started. To **give us your feedback** on your experience with the app and report bugs or problems, log in to our [Docker for Windows forum](https://forums.docker.com/c/docker-for-windows). - ->**Already have Docker for Windows?** If you already have Docker for Windows installed, and are ready to get started, skip over to the [Getting Started with Docker](/engine/getstarted/index.md) tutorial. - - -## Download Docker for Windows - -If you have not already done so, please install Docker for Windows. You can download installers from the stable or beta channel. For more about stable and beta channels, see the [FAQs](faqs.md#questions-about-stable-and-beta-channels). - - - - - - - - - - - - - - -
                            Stable channelBeta channel
                            This installer is fully baked and tested, and comes with the latest GA version of Docker Engine.

                            This is the best channel to use if you want a reliable platform to work with.

                            These releases follow a version schedule with a longer lead time than the betas, synched with Docker Engine releases and hotfixes. -
                            This installer offers cutting edge features and comes with the experimental version of Docker Engine, which is described in the Docker Experimental Features README on GitHub.

                            This is the best channel to use if you want to experiment with features we are working on as they become available, and can weather some instability and bugs. This channel is a continuation of the beta program, where you can provide feedback as the apps evolve. Releases are typically more frequent than for stable, often one or more per month.
                            - Get Docker for Windows (stable)

                            - Download checksum: InstallDocker.msi SHA256 -
                            - Get Docker for Windows (beta)

                            - Download checksum: InstallDocker.msi SHA256 -
                            - ->**Important Notes**: -> ->* Docker for Windows requires 64bit Windows 10 Pro, Enterprise and Education (1511 November update, Build 10586 or later) and Microsoft Hyper-V. Please see [What to know before you install](#what-to-know-before-you-install) for a full list of prerequisites. -> ->* You can switch between beta and stable versions, but _you must have only one app installed at a time_. Also, you will need to save images and export containers you want to keep before uninstalling the current version before installing another. For more about this, see the [FAQs about beta and stable channels](faqs.md#questions-about-stable-and-beta-channels). - -## What to know before you install - -* **README FIRST for Docker Toolbox and Docker Machine users**: Docker for Windows requires Microsoft Hyper-V to run. After Hyper-V is enabled, VirtualBox will no longer work, but any VirtualBox VM images will remain. VirtualBox VMs created with `docker-machine` (including the `default` one typically created during Toolbox install) will no longer start. These VMs cannot be used side-by-side with Docker for Windows. However, you can still use `docker-machine` to manage remote VMs. - -* You can import a `default` VirtualBox VM after installing Docker for Windows by using the **Settings** menu in the System Tray. - -* The current version of Docker for Windows runs on 64bit Windows 10 Pro, Enterprise and Education (1511 November update, Build 10586 or later). In the future we will support more versions of Windows 10. - -* Containers and images created with Docker for Windows are shared between all user accounts on machines where it is installed. This is because all Windows accounts will use the same VM to build and run containers. In the future, Docker for Windows will better isolate user content. - -* The Hyper-V package must be enabled for Docker for Windows to work. The Docker for Windows installer will enable it for you, if needed. (This requires a reboot). - - >**Note**: If your system does not satisfy these requirements, you can install [Docker Toolbox](/toolbox/overview.md), which uses Oracle Virtual Box instead of Hyper-V. - -* **What the install includes**: The installation provides [Docker Engine](https://docs.docker.com/engine/userguide/intro/), Docker CLI client, [Docker Compose](https://docs.docker.com/compose/overview/), and [Docker Machine](https://docs.docker.com/machine/overview/). - -## Step 1. Install Docker for Windows - -1. Double-click `InstallDocker.msi` to run the installer. - - If you haven't already downloaded the installer (`InstallDocker.msi`), you can get it [**here**](https://download.docker.com/win/stable/InstallDocker.msi). It typically downloads to your `Downloads folder`, or you can run it from the recent downloads bar at the bottom of your web browser. - -2. Follow the install wizard to accept the license, authorize the installer, and proceed with the install. - - You will be asked to authorize `Docker.app` with your system password during the install process. Privileged access is needed to install networking components, links to the Docker apps, and manage the Hyper-V VMs. - -3. Click **Finish** on the setup complete dialog to launch Docker. - - ![Install complete>](images/installer-finishes.png) - -## Step 2. Start Docker for Windows - -When the installation finishes, Docker starts automatically. - -The whale in the status bar indicates that Docker is running, and accessible from a terminal. - -If you just installed the app, you also get a popup success message with suggested next steps, and a link to this documentation. - -![Install success](images/win-install-success-popup.png) - -When initialization is complete, select **About Docker** from the notification area icon to verify that you have the latest version. - -Congratulations! You are up and running with Docker for Windows. - -## Step 3. Check versions of Docker Engine, Compose, and Machine - -Start your favorite shell (`cmd.exe`, PowerShell, or other) to check your versions of `docker` and `docker-compose`, and verify the installation. - - PS C:\Users\samstevens> docker --version - Docker version 1.12.0, build 8eab29e, experimental - - PS C:\Users\samstevens> docker-compose --version - docker-compose version 1.8.0, build d988a55 - - PS C:\Users\samstevens> docker-machine --version - docker-machine version 0.8.0, build b85aac1 - -## Step 4. Explore the application and run examples - -The next few steps take you through some examples. These are just suggestions for ways to experiment with Docker on your system, check version information, and make sure `docker` commands are working properly. - -1. Open a shell (`cmd.exe`, PowerShell, or other). - -2. Run some Docker commands, such as `docker ps`, `docker version`, and `docker info`. - - Here is the output of `docker ps` run in a powershell. (In this example, no containers are running yet.) - - PS C:\Users\samstevens> docker ps - CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES - - Here is an example of command output for `docker version`. - - PS C:\Users\Vicky> docker version - Client: - Version: 1.12.0 - API version: 1.24 - Go version: go1.6.3 - Git commit: 8eab29e - Built: Thu Jul 28 21:04:48 2016 - OS/Arch: windows/amd64 - Experimental: true - - Server: - Version: 1.12.0 - API version: 1.24 - Go version: go1.6.3 - Git commit: 8eab29e - Built: Thu Jul 28 21:04:48 2016 - OS/Arch: linux/amd64 - Experimental: true - - Here is an example of command output for `docker info`. - - PS C:\Users\Vicky> docker info - Containers: 0 - Running: 0 - Paused: 0 - Stopped: 0 - Images: 0 - Server Version: 1.12.0 - Storage Driver: aufs - Root Dir: /var/lib/docker/aufs - Backing Filesystem: extfs - Dirs: 0 - Dirperm1 Supported: true - Logging Driver: json-file - Cgroup Driver: cgroupfs - Plugins: - Volume: local - Network: host bridge null overlay - Swarm: inactive - Runtimes: runc - Default Runtime: runc - Security Options: seccomp - Kernel Version: 4.4.16-moby - Operating System: Alpine Linux v3.4 - OSType: linux - Architecture: x86_64 - CPUs: 2 - Total Memory: 1.95 GiB - Name: moby - ID: BG6O:2VMH:OLNV:DDLF:SCSV:URRH:BW6M:INBW:OLAC:J7PX:XZVL:ADNB - Docker Root Dir: /var/lib/docker - Debug Mode (client): false - Debug Mode (server): false - Registry: https://index.docker.io/v1/ - Experimental: true - Insecure Registries: - 127.0.0.0/8 - - >**Note:** The outputs above are examples. Your output for commands like `docker version` and `docker info` will vary depending on your product versions (e.g., as you install newer versions). - -3. Run `docker run hello-world` to test pulling an image from Docker Hub and starting a container. - - PS C:\Users\samstevens> docker run hello-world - - Hello from Docker. - This message shows that your installation appears to be working correctly. - - To generate this message, Docker took the following steps: - 1. The Docker client contacted the Docker daemon. - 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. - 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. - 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. - -4. Try something more ambitious, and run an Ubuntu container in a Bash shell. - - $ docker run -it ubuntu bash - - PS C:\Users\samstevens> docker run -it ubuntu bash - Unable to find image 'ubuntu:latest' locally - latest: Pulling from library/ubuntu - 5a132a7e7af1: Pull complete - fd2731e4c50c: Pull complete - 28a2f68d1120: Pull complete - a3ed95caeb02: Pull complete - Digest: sha256:4e85ebe01d056b43955250bbac22bdb8734271122e3c78d21e55ee235fc6802d - Status: Downloaded newer image for ubuntu:latest - - Type `exit` to stop the container and close the Bash shell. - -5. For the pièce de résistance, start a Dockerized webserver with this command: - - docker run -d -p 80:80 --name webserver nginx - - This will download the `nginx` container image and start it. Here is the output of running this command in a powershell. - - PS C:\Users\samstevens> docker run -d -p 80:80 --name webserver nginx - Unable to find image 'nginx:latest' locally - latest: Pulling from library/nginx - - fdd5d7827f33: Pull complete - a3ed95caeb02: Pull complete - 716f7a5f3082: Pull complete - 7b10f03a0309: Pull complete - Digest: sha256:f6a001272d5d324c4c9f3f183e1b69e9e0ff12debeb7a092730d638c33e0de3e - Status: Downloaded newer image for nginx:latest - dfe13c68b3b86f01951af617df02be4897184cbf7a8b4d5caf1c3c5bd3fc267f - -6. Point your web browser at `http://localhost` to display the start page. - - (Since you specified the default HTTP port, it isn't necessary to append `:80` at the end of the URL.) - - ![Run nginx edge>](images/run-nginx.png) - -7. Run `docker ps` while your webserver is running to see details on the container. - - PS C:\Users\samstevens> docker ps - CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS - NAMES - dfe13c68b3b8 nginx "nginx -g 'daemon off" 3 days ago Up 45 seconds 0.0.0.0:80->80/tcp, 443/tc - p webserver - -8. Stop or remove containers and images. - - The `nginx` webserver will continue to run in the container on that port until you stop and/or remove the container. If you want to stop the webserver, type: `docker stop webserver` and start it again with `docker start webserver`. - - To stop and remove the running container with a single command, type: `docker rm -f webserver`. This will remove the container, but not the `nginx` image. You can list local images with `docker images`. You might want to keep some images around so that you don't have to pull them again from Docker Hub. To remove an image you no longer need, use `docker rmi |`. For example, `docker rmi nginx`. - -**Want more example applications?** - For more example walkthroughs that include setting up services and databases with Docker Compose, see [Example Applications](examples.md). - -## Docker Settings - -When Docker is running, the Docker whale is displayed in the system tray. If it is hidden, click the up arrow in the tray to show it. - -![Showing hidden apps in the system tray](images/whale-systray.png) - -To get a popup menu with application options, right-click the whale: - -![Docker for Windows popup menu](images/config-popup-menu-win.png) - -The **Settings** dialogs provide options to allow Docker auto-start, automatically check for updates, share local drives with Docker containers, enable VPN compatibilty, manage CPUs and memory Docker uses, restart Docker, or perform a factory reset. - -**Beta 26** includes an option to switch between Windows and Linux conatiners. See [Switch between Windows and Linux containers (Beta 26)](#switch-between-windows-and-linux-containers-beta-26). This is not yet available on stable builds. - -![Beta 26 popup with switch for Windows or Linux containers](images/config-popup-menu-win-switch-containers.png) - - -### General - -![Settings](images/settings-general.png) - -* **Start Docker when you log in** - Automatically start the Docker for Windows application upon Windows system login. - -* **Check for updates when the application starts** - Docker for Windows is set to automatically check for updates and notify you when an update is available. If an update is found, click **OK** to accept and install it (or cancel to keep the current version). Uncheck this option if you do not want notifications of version upgrades. You can still find out about updates manually by choosing **Check for Updates** from the menu. - -* **Send usage statistics** - You can set Docker for Windows to auto-send diagnostics, crash reports, and usage data. This information can help Docker improve the application and get more context for troubleshooting problems. - - Uncheck any of the options to opt out and prevent auto-send of data. Docker may prompt for more information in some cases, even with auto-send enabled. Also, you can enable or disable these auto-reporting settings with one click on the information popup when you first start Docker. - - ![Startup information](images/win-install-success-popup.png) - -### Shared Drives - -Share your local drives (volumes) with Docker for Windows, so that they are available to your containers. - -![Shared Drives](images/settings-shared-drives.png) - -You will be asked to provide your Windows system username and password (domain user) to apply shared drives. You can select an option to have Docker store the credentials so that you don't have to re-enter them every time. - -Permissions to access shared drives are tied to the credentials you provide here. If you run `docker` commands and tasks under a different username than the one used here to set up sharing, your containers will not have permissions to access the mounted volumes. - -See also [Verify domain user has permissions for shared drives](troubleshoot.md#verify-domain-user-has-permissions-for-shared-drives-volumes) in Troubleshooting. - -### Advanced - -![CPU and Memory settings](images/settings-cpu-ram.png) - -* **CPUs** - Change the number of processors assigned to the Linux VM. - -* **Memory** - Change the amount of memory the Docker for Windows Linux VM uses. - -Please note, updating these settings requires a reconfiguration and reboot of the Linux VM. This will take a few seconds. - -### Network - -You can configure Docker for Windows networking to work on a virtual private network (VPN). - -* **Internal Virtual Switch** - You can specify a network address translation (NAT) prefix and subnet mask to enable internet connectivity. - -* **DNS Server** - You can configure the DNS server to use dynamic or static IP addressing. - -![Network settings](images/settings-network.png) - ->**Note:** Some users reported problems connecting to Docker Hub on Docker for Windows stable version. This would manifest as an error when trying to run `docker` commands that pull images from Docker Hub that are not alredy downloaded, such as a first time run of `docker run hello-world`. If you encounter this, reset the DNS server to use the Google DNS fixed address: `8.8.8.8`. For more information, see [Networking issues](troubleshoot.md#networking-issues) in Troubleshooting. - -Note that updating these settings requires a reconfiguration and reboot of the Linux VM. - -### Proxies - -Docker for Windows lets you configure HTTP/HTTPS Proxy Settings and automatically propagate these to Docker and to your containers. -For example, if you set your proxy settings to `http://proxy.example.com`, Docker will use this proxy when pulling containers. - -![Proxies](images/proxies.png) - -When you start a container, you will see that your proxy settings propagate into the containers. For example: - -``` -$ docker run -it alpine env -PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin -HOSTNAME=b7edf988b2b5 -TERM=xterm -HOME=/root -HTTP_PROXY=http://proxy.example.com:3128 -http_proxy=http://proxy.example.com:3128 -no_proxy=*.local, 169.254/16 -``` - -You can see from the above output that the `HTTP_PROXY`, `http_proxy` and `no_proxy` environment variables are set. -When your proxy configuration changes, Docker restarts automatically to pick up the new settings. -If you have containers that you wish to keep running across restarts, you should consider using [restart policies](https://docs.docker.com/engine/reference/run/#restart-policies-restart) - -### Docker daemon -You can configure options on the Docker daemon in the given JSON configuration file, and determine how your containers will run. - -For a full list of options on the Docker daemon, see daemon in the Docker Engine command line reference. - -![Docker Daemon](images/docker-daemon.png) - -Note that updating these settings requires a reconfiguration and reboot of the Linux VM. - -### Switch between Windows and Linux containers (Beta 26) - -Starting with Beta 26, you can select which daemon (Linux or Windows) the Docker CLI talks to. Select **Switch to Windows containers** to toggle to Windows containers. Select **Switch to Linux containers**. - -Microsoft Developer Network has preliminary/draft information on Windows containers [here](https://msdn.microsoft.com/en-us/virtualization/windowscontainers/about/about_overview). - -This feature is not yet available on stable builds. - -### Diagnose and Feedback - -If you encounter problems for which you do not find solutions in this documentation, searching [Docker for Windows issues on GitHub](https://github.com/docker/for-win/issues) already filed by other users, or on the [Docker for Windows forum](https://forums.docker.com/c/docker-for-windows), we can help you troubleshoot the log data. - -Select **Upload a diagnostic**. - -This uploads (sends) the logs to Docker. - -![Diagnose problems and Feedback](images/diagnose-feedback-id-win.png) - -To create a new issue directly on GitHub, open [Docker for Windows issues on GitHub](https://github.com/docker/for-win/issues) in your web browser and follow the instructions in the README. Click [New Issue](https://github.com/docker/for-win/issues/new) on that page (or right here ☺) to get a "create new issue" template prepopulated with sections for the ID and summary of your diagnostics, system and version details, description of expected and actual behavior, and steps to reproduce the issue. - -![issue template](images/diagnose-d4win-issues-template.png) - -### Reset - -![Reset](images/settings-reset.png) - -* **Restart Docker** - Shuts down and restarts the Docker application. - -* **Reset to Toolbox default machine content** - Imports containers and images from the existing Docker Toolbox machine named `default`. (This option is enabled only if you have Toolbox installed.) The VirtualBox VM will not be removed. - -* **Reset to factory defaults** - Resets Docker to factory defaults. This is useful in cases where Docker stops working or becomes unresponsive. - - - -## Where to go next - -* Try out the [Getting Started with Docker](/engine/getstarted/index.md) tutorial. - -* Dig in deeper with [learn by example](/engine/tutorials/index.md) tutorials on building images, runnning containers, networking, managing data, and storing images on Docker Hub. - -* See [Example Applications](examples.md) for example applications that include setting up services and databases in Docker Compose. - -* Interested in trying out the new [swarm mode](/engine/swarm/index.md) on Docker Engine v1.12? - - See [Get started with swarm mode](/engine/swarm/swarm-tutorial/index.md), a tutorial which includes specifics on how to leverage your Docker for Windows installation to run single and multi-node swarms. - - Also, try out the Swarm examples in [docker labs](https://github.com/docker/labs/tree/master/swarm-mode/beginner-tutorial). Run the `bash script` and follow the accompanying [Docker Swarm Tutorial](https://github.com/docker/labs/blob/master/swarm-mode/beginner-tutorial/README.md). The script uses Docker Machine to create a multi-node swarm, then walks you through various Swarm tasks and commands. - -* For a summary of Docker command line interface (CLI) commands, see [Docker CLI Reference Guide](/engine/reference/index.md). - -* Check out the blog posts on Docker for Mac and Docker for Windows public betas, and earlier posts on the intial private beta. - -* Please give feedback on your experience with the app and report bugs and problems by logging into our [Docker for Windows forum](https://forums.docker.com/c/docker-for-windows). - -
                            -
                              - diff --git a/docker-for-windows/menu.md b/docker-for-windows/menu.md deleted file mode 100644 index 8274d96f76..0000000000 --- a/docker-for-windows/menu.md +++ /dev/null @@ -1,14 +0,0 @@ - - -# Docker for Mac and Docker for Windows diff --git a/docker-for-windows/opensource.md b/docker-for-windows/opensource.md deleted file mode 100644 index 3809964332..0000000000 --- a/docker-for-windows/opensource.md +++ /dev/null @@ -1,28 +0,0 @@ - - -# Open Source Components and Licensing - -Docker Desktop Editions are built using open source software software. For details on the licensing, choose --> **About** from within the application, then click **Acknowlegdements**. - -Docker Desktop Editions distribute some components that are licensed under the GNU General Public License. You can download the source for these components [here](https://download.docker.com/opensource/License.tar.gz). - -
                              -
                                - diff --git a/docker-for-windows/release-notes.md b/docker-for-windows/release-notes.md deleted file mode 100644 index 62f846a701..0000000000 --- a/docker-for-windows/release-notes.md +++ /dev/null @@ -1,929 +0,0 @@ - - -# Docker for Windows Release Notes - -Here are the main improvements and issues per release, starting with the current release. The documentation is always updated for each release. - -For system requirements, please see the Getting Started topic on [What to know before you install](index.md#what-to-know-before-you-install). - -Release notes for _stable_ and _beta_ releases are listed below. You can learn about both kinds of releases, and download stable and beta product installers at [Download Docker for Windows](index.md#download-docker-for-windows). - -* [Stable Release Notes](#stable-release-notes) -* [Beta Release Notes](#beta-release-notes) -* [Alpha Release Notes](#alpha-release-notes) - -## Stable Release Notes - -### Docker for Windows 1.12.1, 2016-09-16 (stable) - ->**Important Note**: -> -> The auto-update function in Beta 21 will not be able to install this update. To install the latest beta manually if you are still on Beta 21, please download the installer here: - -> https://download.docker.com/win/beta/InstallDocker.msi - -> This problem is fixed as of Beta 23 for subsequent auto-updates. - -**New** - -* To support trusted registry transparently, all trusted CAs (root or intermediate) on the Windows host are automatically copied to Moby - -* `Reset Credentials` will also unshare the shared drives - -* Logs are now rotated every day - -* Support multiple DNS servers - -* Added `mfsymlinks` SMB option to support symlinks on bind mounted folder - -* Added `nobrl` SMB option to support `sqlite` on bind mounted folders - -* Detect outdated versions of Kitematic - -**Upgrades** - -* Docker 1.12.1 -* Docker machine 0.8.1 -* Linux kernel 4.4.20 -* aufs 20160905 - -**Bug fixes and minor changes** - -**General** - -* Uploading a diagnostic now shows a proper status message in the Settings - -* Docker will stop asking to import from Toolbox after an upgrade - -* Docker can now import from Toolbox just after HyperV is activated - -* Added more debug information to the diagnostics - -* Sending anonymous statistics shouldn't hang anymore when Mixpanel is not available - -* Support newlines in release notes - -* Improve error message when Docker daemon is not responding - -* The configuration database is now stored in-memory - -* Preserve the stacktrace of PowerShell errors - -* Display service stacktrace in error windows - -**Networking** - -* Improve name servers discovery -* VpnKit supports search domains -* VpnKit is now compiled with OCaml 4.03 rather than 4.02.3 - -**Filesharing** - -* Set `cifs` version to 3.02 - -* VnpKit: reduce the number of sockets used by UDP NAT, reduce the probability - -* `slirp`: reduce the number of sockets used by UDP NAT, reduce the probability that NAT rules will time out earlier than expected - -* Fixed password handling for host file system sharing - -**Hyper-V** - -* Automatically disable lingering net adapters that prevent Docker from starting or using the network - -* Automatically delete duplicated MobyLinuxVMs on a `reset to factory defaults` - -* Improved the HyperV detection and activation mechanism - -**Moby** - -* Fixed Moby Diagnostics and Update Kernel - -* Use default `sysfs` settings, transparent huge pages disabled - -* `Cgroup` mount to support `systemd` in containers - -**Known issues** - -* Docker will automatically disable lingering net adapters. The only way to remove them is manually using `devmgmt.msc` as documented in [Remove stale network adapters](troubleshoot.md#4-remove-stale-network-adapters) under [Networking issues](troubleshoot.md#networking-issues) in Troubleshooting. - -### Docker for Windows 1.12.0, 2016-07-28 (stable) - -* First stable release - -**Components** - -* Docker 1.12.0 -* Docker Machine 0.8.0 -* Docker Compose 1.8.0 - - -## Beta Release Notes - -### Beta 27 Release Notes (2016-09-28 1.12.2-rc1-beta27) - ->**Important Note**: -> -> The auto-update function in Beta 21 will not be able to install this update. To install the latest beta manually if you are still on Beta 21, please download the installer here: - -> https://download.docker.com/win/beta/InstallDocker.msi - -> This problem is fixed as of Beta 23 for subsequent auto-updates. - -**New** - -* Reworked the File Sharing dialog and underlying mechanism -* Pre-fill username -* Faster and more reliable feedback when the user/password is not valid -* Better support for domain users -* Error message in Logs when File Sharing failed for other reasons - -**Upgrades** - -* Docker 1.12.2-rc1 -* Docker Machine 0.8.2 -* Docker Compose 1.8.1 -* kernel 4.4.21 -* aufs 20160912 - -**Bug fixes and minor changes** - -* Improve the switching between Linux and Windows containers: better errors, more reliable, deal with more edge cases -* Kill lingering dockerd that users might have still around because they played with Windows Containers before -* Don't recreate the VM if only the DNS server is set -* The uninstaller now kills the service if it failed to stop it properly -* Restart VpnKit and DataKit when the processes die -* VpnKit: impose a connection limit to avoid exhausting file descriptors -* VpnKit: handle UDP datagrams larger than 2035 bytes -* VpnKit: reduce the number of file descriptors consumed by DNS -* Improve debug information - -### Beta 26 Release Notes (2016-09-14 1.12.1-beta26) - ->**Important Note**: -> -> The auto-update function in Beta 21 will not be able to install this update. To install the latest beta manually if you are still on Beta 21, please download the installer here: - -> https://download.docker.com/win/beta/InstallDocker.msi - -> This problem is fixed as of Beta 23 for subsequent auto-updates. - -**New** - -* Basic support for Windows containers. On Windows 10 build >= 14372, a switch in the `systray` icon will change which daemon (Linux or Windows) the Docker CLI talks to - -* To support trusted registry transparently, all trusted CAs (root or intermediate) on the Windows host are automatically copied to Moby - -* `Reset Credentials` will also unshare the shared drives - -* Logs are now rotated every day - -**Upgrades** - -* Linux kernel 4.4.20 -* aufs 20160905 - -**Bug fixes and minor changes** - -* We no longer send the same DNS settings twice to the daemon - -* Fixed the lingering net adapters removal on Windows 10 Anniversary Update - -* Uploading a diagnostic now shows a proper status message in the Settings - -### Beta 25 Release (2016-09-07 1.12.1-beta25) - ->**Important Note**: -> -> The auto-update function in Beta 21 will not be able to install this update. To install the latest beta manually if you are still on Beta 21, please download the installer here: - -> https://download.docker.com/win/beta/InstallDocker.msi - -> This problem is fixed as of Beta 23 for subsequent auto-updates. - -**New** - -* Support multiple DNS servers - -**Bug fixes and minor changes** - -* Improved name servers discovery -* VpnKit supports search domains -* Set CIFS (common internet file system) version to 3.02 - -**Known issues** - -* Only UTF-8 passwords are supported for host filesystem sharing - -* Docker will automatically disable lingering net adapters. The only way to remove them is manually using `devmgmt.msc` as documented in [Remove stale network adapters](troubleshoot.md#4-remove-stale-network-adapters) under [Networking issues](troubleshoot.md#networking-issues) in Troubleshooting. - -### Beta 24 Release (2016-08-23 1.12.1-beta24) - ->**Important Note**: -> -> The auto-update function in Beta 21 will not be able to install this update. To install the latest beta manually if you are still on Beta 21, please download the installer here: - -> https://download.docker.com/win/beta/InstallDocker.msi - -> This problem is fixed as of Beta 23 for subsequent auto-updates. - -**Upgrades** - -* Docker 1.12.1 -* Docker Machine 0.8.1 -* Linux kernel 4.4.19 -* aufs 20160822 - -**Bug fixes and minor changes** - -* `slirp`: reduce the number of sockets used by UDP NAT, reduce the probability that NAT rules will time out earlier than expected - -**Known issues** - -* Only UTF-8 passwords are supported for host filesystem sharing. - -* Docker will automatically disable lingering net adapters. The only way to remove them is manually using `devmgmt.msc` as documented in [Remove stale network adapters](troubleshoot.md#4-remove-stale-network-adapters) under [Networking issues](troubleshoot.md#networking-issues) in Troubleshooting. - -### Beta 23 Release (2016-08-16 1.12.1-rc1-beta23) - ->**Important Note**: -> -> The auto-update function in Beta 21 will not be able to install this update. To install the latest beta manually if you are still on Beta 21, please download the installer here: - -> https://download.docker.com/win/beta/InstallDocker.msi - -> This problem is fixed as of Beta 23 for subsequent auto-updates. - -**New** - -* Added `mfsymlinks` smb option to support symlinks on bind mounted folder -* Added `nobrl` smb option to support sqlite on bind mounted folders -* Detect outdated versions of Kitematic - -**Upgrades** - -* Docker 1.12.1-rc1 -* Linux kernel 4.4.17 -* aufs 20160808 - -**Bug fixes and minor changes** - -* Fixed password handling for host file system sharing -* Automatically disable lingering net adapters that prevent Docker from starting or using the network -* Automatically delete duplicated MobyLinuxVMs on a `reset to factory defaults` -* Docker will stop asking to import from toolbox after an upgrade -* Docker can now import from toolbox just after hyperV is activated -* Fixed Moby Diagnostics and Update Kernel -* Added more debug information to the diagnostics -* Sending anonymous statistics shouldn't hang anymore when Mixpanel is not available -* Improved the HyperV detection and activation mechanism -* VpnKit is now compiled with OCaml 4.03 rather than 4.02.3 -* Support newlines in release notes -* Improved error message when docker daemon is not responding -* The configuration database is now stored in-memory -* Preserve the stacktrace of PowerShell errors -* Display service stacktrace in error windows -* Moby: use default sysfs settings, transparent huge pages disabled -* Moby: cgroup mount to support systemd in containers - -**Known issues** - -* Only UTF-8 passwords are supported for host filesystem sharing -* Docker will automatically disable lingering net adapters. The only way to remove them is manually using `devmgmt.msc` as documented in [Troubleshooting](troubleshoot.md#networking-issues). - -### Beta 22 Release (2016-08-11 1.12.0-beta22) - -Unreleased. See Beta 23 for changes. - -**Known issues** - -* Docker will automatically disable lingering net adapters. The only way to remove them is manually using `devmgmt.msc` as documented in [Troubleshooting](troubleshoot.md#networking-issues). - -### Beta 21 Release (2016-07-28 1.12.0-beta21) - -**New** - -* Docker for Windows is now available from 2 channels: **stable** and **beta**. New features and bug fixes will go out first in auto-updates to users in the beta channel. Updates to the stable channel are much less frequent and happen in sync with major and minor releases of the Docker engine. Only features that are well-tested and ready for production are added to the stable channel releases. For downloads of both and more information, see the [Getting Started](index.md#download-docker-for-windows). - -* Removed the docker host name. Containers with exported ports are reachable via localhost. - -* The UI shows whether the user is on beta or stable channel - -**Upgrades** - -* Docker 1.12.0 with experimental features -* Docker Machine 0.8.0 -* Docker Compose 1.8.0 - -**Bug fixes and minor changes** - -* Fixed networking issue when transmitting data to a container via an exposed port. -* Include the sources for qemu-img -* Fixed the migration from toolbox when the user has a space in its login -* Disable the migration from toolbox when hyperV is not yet activated -* More windows can be closed with ESC -* Added the channel to crash reports -* Fixed a path rewriting bug that happens on Windows insider build 14367 -* Simplified the MobyLinux.ps1 script - -**Known issues** - -* Older Kitematic versions are not compatible with Docker for Windows. You need to manually delete the `C:\Program Files\Docker\Kitematic` folder before you click **Open Kitematic...** systray link. - -### Beta 20 Release (2016-07-19 1.12.0-rc4-beta20) - -**New** - -* The UI option to disable port forwarding to `localhost` has been removed - -**Bug fixes and minor changes** - -* Fixed `docker.sock` permission issues -* Don't check for update when the settings panel opens -* Removed obsolete DNS workaround -* Use the secondary DNS server in more circumstances -* Limit the number of concurrent port forwards to avoid running out of resources -* Store the database as a "bare" git repo to avoid corruption problems - -### Beta 19 Release (2016-07-14 1.12.0-rc4-beta19) - -**New** - -* Added an option to opt-out from sending usage statistics (will be available on the future stable channel) -* New error dialog box to upload crash reports - -**Upgrades** - -* Docker 1.12.0 RC4 -* Docker Compose 1.8.0 RC2 -* Docker Machine 0.8.0 RC2 -* Linux kernel 4.4.15 - -**Bug fixes and minor changes** - -* `com.docker.slirp`: included the DNS TCP fallback fix, required when UDP responses are truncated -* `docker build/events/logs/stats...` won't leak when interrupted with Ctrl-C -* Disable all buttons on Update Window when a version is downloading - -### Beta 18.1 Release (2016-07-07 1.12.0-rc3-beta18.1) - ->**Note**: Docker 1.12.0 RC3 release introduces a backward incompatible change from RC2. You can fix this by [recreating or updating your containers](troubleshoot.md#recreate-or-update-your-containers-after-beta-18-upgrade) as described in Troubleshooting. - -**Hotfix** - -* Fixed issue resulting in error "Hijack is incompatible with use of CloseNotifier", reverts previous fix for `Ctrl-C` during build. - -**New** - -* Forwarding the ports to localhost is now the default -* Added `http`/`https` proxy configuration to the settings -* The toolbox default machine can be imported on first launch -* Added UI when a crash report is collected and uploaded -* The check for update runs every 6 hours - -**Upgrades** - -* Docker 1.12.0 RC3 - -**Bug fixes and minor changes** - -* The docker API proxy was failing to deal with 1.12 features (health check for, for example) -* When killing the VM process, ignore when the process is already stopped -* When stopping the VM, always stop the docker proxy -* Prevent the update windows from downloading the `.msi` into `C:\Program Files\Docker` -* All settings should be disabled when Docker is starting. (This regression was introduced in Beta 17) -* VPNKit: Improved scalability as number of network connections increases -* Improve the connection to the database -* Ignore when the shutdown service is not available - -### Beta 18 Release (2016-07-06 1.12.0-rc3-beta18) - -**New** - -* Forwarding the ports to localhost is now the default -* Added `http`/`https` proxy configuration to the settings -* The toolbox default machine can be imported on first launch -* Added UI when a crash report is collected and uploaded -* The check for update runs every 6 hours - -**Upgrades** - -* Docker 1.12.0 RC3 - -**Bug fixes and minor changes** - -* Interrupting a `docker build` with Ctrl-C will actually stop the build -* The docker API proxy was failing to deal with 1.12 features (health check for, for example) -* When killing the VM process, ignore when the process is already stopped -* When stopping the VM, always stop the docker proxy -* Prevent the update windows from downloading the `.msi` into `C:\Program Files\Docker` -* All settings should be disabled when Docker is starting. (This regression was introduced in Beta 17) -* VPNKit: Improved scalability as number of network connections increases -* Improve the connection to the database -* Ignore when the shutdown service is not available - -### Beta 17 Release (2016-06-29 1.12.0-rc2-beta17) - -**Upgrades** - -* Linux kernel 4.4.14, aufs 20160627 - -**Bug fixes and minor changes** - -* Support users with spaces in their login -* Fix some cases where `dotnet restore` could hang -* Fixed `docker inspect` on an image -* Removed the console from hyper-v manager -* Improved diagnostic for VPN connection and add logs for the service port openers -* Improve Moby's boot sequence to adapt to longer boot time when swarm services are running -* Forcefully turn off a VM that won't shut down -* Clicking on a link from the changelog opens a browser -* Fix links to the documentation -* Fix the url to download Kitematic -* Renewed the signing certificates -* Fixed errors with the firewall and the network switch -* Fixed parsing errors in the Powershell script - -### Beta 16 Release (2016-06-17 1.12.0-rc2-beta16) - -**Upgrades** - -* Docker 1.12.0 RC2 -* docker-compose 1.8.0 RC1 -* docker-machine 0.8.0 RC1 -* Alpine 3.4 - -**Bug fixes and minor changes** - -* Fixes to the VPN mode -* Fixed the localhost port forwarding performance issue -* Auto-detect mounted/unmounted drive in the list of shares - - Changed the name of the application from "DockerforWindows" to "Docker for Windows" - - Avoid multiple update windows being displayed at the same time - -### Beta 15 Release (2016-06-10 1.11.2-beta15) - -**New** - -* New experimental networking mode, exposing container ports on `localhost` -* New Settings menu to configure sysctl.conf -* New Settings menu to configure http proxies -* The VPN mode setting is removed (VPN mode is now the only supported mode) -* The vSwitch NAT configuration has been removed - -**Upgrades** - -* Docker 1.11.2 -* Linux 4.4.12, aufs 20160530 - -**Bug fixes and minor changes** - -* Moved `Import from toolbox` option to the General Settings -* Increased the timeout to write to the configuration database -* Fixed an issue where sending anonynous stats to Mixpanel made the application stop -* Faster boot time -* All named pipes are now prefixed with the word `docker` -* Full version number is now displayed in the update window -* Default daemon config does not have debug enabled anymore -* More responsive Settings Panel, with new whales also :-) -* Improved logs and debug information - -### Beta 14 Release(2016-06-02 1.11.1-beta14) - -**New** - -* Enabled configuration of the docker daemon (edit `config.json`) -* The VPN mode is enabled by default -* Removed DHCP for VM network configuration -* User configurable NAT prefix and DNS server -* New feedback window to upload diagnostics dialog -* New status indicator in **Settings** window -* VM logs are uploaded with a crash report -* Animated welcome whale - -**Bug fixes and minor changes** - -* Support non-ASCII characters in passwords -* Fixed unshare a drive operation -* Fixed deserialized of exceptions sent from the service -* If the backend service is not running, the GUI now starts it -* The app no longer complains if the backend service is not running and the user just wants to shut down. - - -**Known issues** - -* Due to limitation in the Windows NAT implementation, co-existence with other NAT prefixes needs to be carefully managed. See [NAT Configuration](troubleshoot.md#nat-configuration) in [Troubleshooting](troubleshoot.md) for more details. - -### Beta 13 Release (2016-05-25 1.11.1-beta13) - -**New** - -This Beta release includes some significant changes: - -* Docker communication is over Hyper-V sockets instead of the network -* Experimental VPN mode, also known as `vpnkit` -* Initial support for `datakit` for configuration -* Redesigned Settings panel -* Docker can now be restarted - -**Bug fixes and minor changes** - -* Support Net adapters with a different name than "vEthernet (DockerNAT)" -* Sharing now has a better support for domain users -* Fixed Toolbox migration (was broken in Beta12) -* Enabling HyperV (was broken in Beta12) -* Fixed error message when invalid labels are passed to `docker run` -* Mixpanel no longer uses roaming App Data -* UI improvements -* Support was added for VMs with other IP addresses out of the `10.0.75.0/24` range -* Improved FAQ - -**Known issues** - -* Due to limitation in the Windows NAT implementation, co-existence with other NAT prefixes needs to be carefully managed. See [NAT Configuration](troubleshoot.md#nat-configuration) in [Troubleshooting](troubleshoot.md) for more details. - -### Beta 12 Release (2016-17-10 1.11.1-beta12) - -**New** - -* The application is now separated in two parts. A back-end service and a front-end GUI.The front-end GUI no longer asks for elevated access. - -**Bug fixes and minor changes** - -* Excluded the network drives from the shares list -* Removed the notification when closing the application -* Minor GUI improvements - -**Known issues** - -* Due to limitation in the Windows NAT implementation, co-existence with other NAT prefixes needs to be carefully managed. See [NAT Configuration](troubleshoot.md#nat-configuration) in [Troubleshooting](troubleshoot.md) for more details. - - -### Beta 11b Hot Fix Release (2016-05-11 1.11.1-beta11b) - -**Hot fixes** - -* Fixed an issue with named pipe permisions that prevented Docker from starting - -### Beta 11 Release (2016-05-10 1.11.1-beta11) - -**New** - -* The GUI now runs in non-elevated mode and connects to an elevated Windows service -* Allocate VM memory by 256 MB increments, instead of 1 GB -* Show a meaningful error when the user has an empty password -* Improved [Troubleshooting](troubleshoot.md) page - -**Upgrades** - -* docker-compose 1.7.1 (see changelog) -* Kernel 4.4.9 - -**Bug fixes and minor changes** - -* Report the VM's IP in `docker port` -* Handle passwords with spaces -* Show a clear error message when trying to install on Home editions -* Slower whale animation in the System Tray -* Proxy is restarting itself when it crashes -* DHCP process handles exceptions gracefully -* Moby (Backend) fixes: - - Fixed `vsock` half closed issue - - Added NFS support - - Hostname is now Moby, not Docker - - Fixes to disk formatting scripts - - Kernel upgrade to 4.4.9 - -**Known issues** - -* Due to limitation in the Windows NAT implementation, co-existence with other NAT prefixes needs to be carefully managed. See [Troubleshooting](troubleshoot.md) for more details. - -* Logs for the windows service are not aggregated with logs from the GUI. This will be fixed in future versions. - - -## Beta 10 Release (2016-05-03 1.11.0-beta10) - -**New** - -* Improved Settings panel, allow to configure the VM’s memory and CPUs -* Co-exist with multiple internal Hyper-V switches and improved DHCP handling -* Token validation is now done over HTTPS. This should fix issues with some firewalls and antiviros software. - -**Upgrades** - -* Docker 1.11.1 - -**Bug fixes and minor changes** - -* Fixed Desktop shortcut name and updated icons -* Preparation to run the backend as service -* Improved logging and Mixpanel events -* Improved code quality -* Improved the build -* New icons - -**Known issues** - -* Due to limitation in the Windows NAT implementation, co-existence with other NAT prefixes needs to be carefully managed. See [Troubleshooting](troubleshoot.md) for more details. - - -### Beta 9 Release (2016-04-26 1.11.0-beta9) - -**New** - -* Provide one-click dialog to enable Hyper-V -* Report clear underlying Hyper-V errors - -**Bug fixes and minor changes** - -* Better handling of some networking issues -* Fixed help menu and start menu getting started URLs -* Restored “Docker is Initializing” notification on first run -* Better error messages during authentication -* Improved logging on error conditions -* Improved build and tests - -**Known issues** - -* If multiple internal Hyper-V switches exist the Moby VM -may not start correctly. We have identified the issue and -are working on a solution. - -### Beta 8 Release (2016-04-20 1.11.0-beta8) - -**New** - -* Auto-update is installed silently, and relaunches the application when it completes -* Uninstaller can be found in Windows menu -* Kitematic can be downloaded from the Dashboard menu - -**Bug fixes and minor changes** - -* Better UI in the ShareDrive window -* The firewall alert dialog will not come up as often as it was -* Configured MobyLinux VM with a fixed memory of 2GB -* User password is no longer stored on the host-side KVP -* Uninstall shortcut is available in registry - -### Beta 7 Release (2016-04-12 1.11.0-beta7) - -**New** - - - Multiple drives can be shared - - New update window - - Welcome whale - -**Upgrades** - -* docker 1.11.0-rc5 -* docker-machine 0.7.0-rc3 -* docker-compose 1.7.0-rc2 - -**Bug fixes and minor changes** - -* Improved networking configuration and error detection: fixed DHCP renewal and rebind issues -* Allow DNS/DHCP processes to restart on bind error -* Less destructive migration from Docker Toolbox -* Improved documentation -* Better error handling: Moby will restart itself if start takes too long. -* Kill proxy and exit docker before a new version is installed -* The application cannot start twice now -* The proxy will stop automatically when the GUI is not running -* Removed existing proxy firewall rules before starting Moby -* The application now collects more and better information on crashes and other issues -* Improved all dialogs and windows -* Added the version to installer's first screen -* Better reset to defaults -* New regression test framework -* The installation MSI is now timestamped -* The Hyper-V install mentions Docker Toolbox only if it is present -* Improved Bugsnag reports: fixed a dependency bug, and added a unique ID to each new report -* Improved the build -* Improved code quality - -**Known issues** - -- Settings are now serialized in JSON. This install will lose the current settings. - -- Docker needs to open ports on the firewall. Sometimes, the user will see a firewall alert dialog. The user should allow the ports to be opened. - -- The application was upgraded to 64 bits. The installation path changed to `C:\Program Files\Docker\Docker`. Users might have to close any Powershell/Cmd windows that were already open before the update to get the new `PATH`. In some cases, users may need to log off and on again. - -**Bug Fixes** - - - Fixed DHCP renewal and rebind - - Only mention toolbox on Hyper-V install if it's present - - The application does not start twice now - - DNS/DHCP processes are allowed to restart on bind error now - - Removed the window that opens quickly during bugsnag reports - - Fixed OS reported by Bugsnag - - Improved the build - - Improved code quality - -### Beta 6 Release (2016-04-05 1.11.0.1288) - -**Enhancements** - -- Docs are updated for Beta 6! -- Support roaming: DNS queries are forwarded to the host -- Improved startup times by running a DHCP server on the host -- New settings dialog design -- Support windows paths with -v -- Updated docker CLI and deamon to 1.11.0-rc3 -- Updated docker-machine to 0.7.0-rc2 -- Updated docker-compose to 1.7.0-rc1 -- Now install docker-credential-wincred -- Allow non-root users in containers to create files on volume mounts -- Automatically install HyperV -- The application is now 64bits -- Improved wording in all dialog boxes and error messages -- Removed exit confirmation -- Show clickable URL in the Install HyperV message box -- Dashboard link to Kitematic (as on Mac) -- Moby Kernel updated to 4.4.6 -- The registry key was changed to HKLM\SOFTWARE\Docker Inc.\Docker\1.0 - -**Known issues** - -- Migration from Docker Toolbox can fail sometimes. If this happens, the workaround is to restart the application. - -- Docker needs to open ports on the firewall, which can activate a firewall alert dialog. Users should allow the ports to be opened. - -- The application was upgraded to 64 bits. The installation path changed to `C:\Program Files\Docker\Docker`. If users have Powershell/Cmd windows already open before the update, they might have to close them to catch the new PATH. In some cases, users will need to log off and on again. - -**Bug Fixes** - -- Kill VMs that cannot be shutdown properly - -- Improved the diagnostic information sent with bugsnag reports - -- Settings window shows when the drive is shared or not -`C:` drive can be bind mounted with `//c` or `/c`. Used to be `//c/` - -- Don't try to submit empty tokens - -- Fixed the version shown in the About box - -- Fixed a race condition on the logs - -- Fixed a race condition on the settings - -- Fixed broken links in the documentation - -- Replaced `sha1` with actual version in the assemblies - -- Don't start the unused agent process - -### Beta 5 Release (2016-03-29 1.10.6) - -**Enhancements** - -* Remove debug console -* Open browser with hyper-v installation instructions -* Add Cloudfront for downloads from Europe -* Capture qemu logs during toolbox upgrades -* Rename alpha distribution channel to beta - -**Bug Fixes** - -* Fix diagnose section in bugsnag report -* Fix msi version -* Don't truncate Toolbox link - ->**Note**: Docker for Windows skipped from Beta 1 to Beta 5 at this point to synch up the version numbering with Docker for Mac, which went into beta cycles a little earlier. - -### Beta 1 Release (2016-03-24 1.10.6) - -**Enhancements** - -- Display the third party licenses -- Display the license agreement -- The application will refuse to start if Hyper-v is not enabled -- Rename `console` to `debug console` -- Remove `machine` from notification -- Open the feedback forum -- Use same MixPanel project for Windows and OSX -- Align MixPanel events with OSX -- Added a script to diagnose problems -- Submit diagnostic with bugsnag reports -- MixPanel heartbeat every hour - -**Bug Fixes** - -- Accept all versions of Enterprise 10, Pro 10 and Education 10 during installation (Eval, N, ...) -- Fix Linux kernel crashes with certain applications or somesuch -- Fix notifications that are not shown -- Animate the systray whale on reset -- Shorten the enrollment process timeout -- Properly unmount shares when the user un-selects the setting -- Don't install on unsupported builds - -## Alpha Release Notes - -### Alpha 4 Release (A2016-03-10 1.10.4.0) - -- Faster Startup & Shutdown -- Use host DNS parameters -- Enrollment System -- Recreating manually removed vm -- More MixPanel Events -- Various Bug Fixes - -### Alpha 3 Release (2016-03-03 1.10.2.14) - -**File sharing** - - - Create network share automatically - - Improve Credentials management - - Support paths with c and C drive - -**Crashes and Analytics** - - - Report crashes with Bugsnag - - Send analytics through MixPanel - -**GUI** - - - Improve layout of About and Settings dialog - - Improve Updater - - Link to *Help* - - Link to *Send Feeback* - -**General** - - - Bug fixes - -### Alpha 2 Release (2016-02-26 1.10.2.12) - -**Installer** - - - Enhancements - - Auto-update - - License agreement - -**General** - - - Bug fixes - -### Alpha 1 Release (2016-02-22 1.10.1.42-1) - -**Hypervisor** - - - significant performance improvements - -**Security** - - - retrieving Credentials from user - -**Filesystem** - - - hot-mounting host filesystem with credential - -**General** - - - state management - - stability, logging - - bugfixes, eye candies - -### Alpha 0 Release (2016-02-09 1.10.0.0-0) - -**Hypervision** - - - hyper-v backed virtual machines - - boots moby in a few seconds - - installs CLI in `PATH` - - proxies docker commands to moby - -**Filesystem** - - - mounts host filesystem to support `--volume` - - samba client with a hardcoded password - - allows live reload - -**Networking** - - - live debugging Node.js application - -
                                -
                                  - diff --git a/docker-for-windows/troubleshoot.md b/docker-for-windows/troubleshoot.md deleted file mode 100644 index 0efe9ef327..0000000000 --- a/docker-for-windows/troubleshoot.md +++ /dev/null @@ -1,300 +0,0 @@ - - -# Logs and Troubleshooting - -Here is information about how to diagnose and troubleshoot problems, send logs and communicate with the Docker for Windows team, use our forums and Knowledge Hub, browse and log issues on GitHub, and find workarounds for known problems. - -## Docker Knowledge Hub - -**Looking for help with Docker for Windows?** Check out the [Docker Knowledge Hub](http://success.docker.com/) for knowledge base articles, FAQs, and technical support for various subscription levels. - -## Submitting diagnostics, feedback, and GitHub issues - -If you encounter problems for which you do not find solutions in this documentation or on the [Docker for Windows forum](https://forums.docker.com/c/docker-for-windows), we can help you troubleshoot the log data. See [Diagnose and Feedback](index.md#diagnose-and-feedback) in the Getting Started topic. - - -## Checking the Logs - -In addition to using the diagnose and feedback option to submit logs, you can browse the logs yourself. - -### Use the systray menu to view logs - -To view Docker for Windows latest log, click on the `Diagnose & Feedback` menu entry in the systray and then on the `Log file` link. You can see the full history of logs in your `AppData\Local` folder. - -### Use the systray menu to report and issue - -If you encounter an issue and the suggested troubleshoot procedures outlined below don't fix it you can generate a diagnostics report. Click on the `Diagnose & Feedback` menu entry in the systray and then on the `Upload diagnostic...` link. This will upload diagnostics to our server and provide you with a unique ID you can use in email or the forum to reference the upload. - - - -## Troubleshooting - -### inotify on shared drives does not work - -Currently, `inotify` does not work on Docker for Windows. This will become evident, for example, when when an application needs to read/write to a container across a mounted drive. This is a known issue that the team is working on. Below is a temporary workaround, and a link to the issue. - -* **Workaround for nodemon and Node.js** - If you are using [nodemon](https://github.com/remy/nodemon) with `Node.js`, try the fallback polling mode described here: [nodemon isn't restarting node applications](https://github.com/remy/nodemon#application-isnt-restarting) - -* **Docker for Windows issue on GitHub** - See the issue [Inotify on shared drives does not work](https://github.com/docker/for-win/issues/56#issuecomment-242135705) - - -### Verify domain user has permissions for shared drives (volumes) - -Permissions to access shared drives are tied to the username and password you use to set up shared drives. (See [Shared Drives](index.md#shared-drives).) If you run `docker` commands and tasks under a different username than the one used to set up shared drives, your containers will not have permissions to access the mounted volumes. The volumes will show as empty. - -The solution to this is to switch to the domain user account and reset credentials on shared drives. - -Here is an example of how to de-bug this problem, given a scenario where you shared the `C` drive as a local user instead of as the domain user. Assume the local user is `samstevens` and the domain user is `merlin`. - -1. Make sure you are logged in as the Windows domain user (for our example, `merlin`). - -2. Run `net share c` to view user permissions for `\, FULL`. - - PS C:\WINDOWS\system32> net share c - Share name C - Path C:\ - Remark - Maximum users No limit - Users SAMSTEVENS - Caching Caching disabled - Permission windowsbox\samstevens, FULL - -3. Run the following command to remove the share. - - net share c /delete - -4. Re-share the drive via the [Shared Drives dialog](index.md#shared-drives), and provide the Windows domain user account credentials. - -5. Re-run `net share c`. - - PS C:\WINDOWS\system32> net share c - Share name C - Path C:\ - Remark - Maximum users No limit - Users MERLIN - Caching Caching disabled - Permission windowsbox\merlin, FULL - -See also, the related issue on GitHub, [Mounted volumes are empty in the container](https://github.com/docker/for-win/issues/25). - -### Avoid unexpected syntax errors, use Unix style line endings for files in containers - -Any file destined to run inside a container must use Unix style `\n` line endings. This includes files referenced at the command line for builds and in RUN commands in Docker files. - -Docker containers and `docker build` run in a Unix environment, so files in containers must use Unix style line endings `\n`, _not_ Windows style: `\r\n`. Keep this in mind when authoring files such as shell scripts using Windows tools, where the default is likely to be Windows style line endings. These commands ultimately get passed to Unix commands inside a Unix based container (for example, a shell script passed to `/bin/sh`). If Windows style line endings are used, `docker run` will fail with syntax errors. - -For an example of this issue and the resolution, see this issue on GitHub: Docker RUN fails to execute shell script (https://github.com/docker/docker/issues/24388). - -### Recreate or update your containers after Beta 18 upgrade - -Docker 1.12.0 RC3 release introduces a backward incompatible change from RC2 to RC3. (For more information, see https://github.com/docker/docker/issues/24343#issuecomment-230623542.) - -You may get the following error when you try to start a container created with pre-Beta 18 Docker for Windows applications. - - Error response from daemon: Unknown runtime specified default - -You can fix this by either [recreating](#recreate-your-containers) or [updating](#update-your-containers) your containers. - -If you get the error message shown above, we recommend recreating them. - -#### Recreate your containers - -To recreate your containers, use Docker Compose. - - docker-compose down && docker-compose up - -#### Update your containers - -To fix existing containers, follow these steps. - -1. Run this command. - - $ docker run --rm -v /var/lib/docker:/docker cpuguy83/docker112rc3-runtimefix:rc3 - - Unable to find image 'cpuguy83/docker112rc3-runtimefix:rc3' locally - rc3: Pulling from cpuguy83/docker112rc3-runtimefix - 91e7f9981d55: Pull complete - Digest: sha256:96abed3f7a7a574774400ff20c6808aac37d37d787d1164d332675392675005c - Status: Downloaded newer image for cpuguy83/docker112rc3-runtimefix:rc3 - proccessed 1648f773f92e8a4aad508a45088ca9137c3103457b48be1afb3fd8b4369e5140 - skipping container '433ba7ead89ba645efe9b5fff578e674aabba95d6dcb3910c9ad7f1a5c6b4538': already fixed - proccessed 43df7f2ac8fc912046dfc48cf5d599018af8f60fee50eb7b09c1e10147758f06 - proccessed 65204cfa00b1b6679536c6ac72cdde1dbb43049af208973030b6d91356166958 - proccessed 66a72622e306450fd07f2b3a833355379884b7a6165b7527c10390c36536d82d - proccessed 9d196e78390eeb44d3b354d24e25225d045f33f1666243466b3ed42fe670245c - proccessed b9a0ecfe2ed9d561463251aa90fd1442299bcd9ea191a17055b01c6a00533b05 - proccessed c129a775c3fa3b6337e13b50aea84e4977c1774994be1f50ff13cbe60de9ac76 - proccessed dea73dc21126434f14c58b83140bf6470aa67e622daa85603a13bc48af7f8b04 - proccessed dfa8f9278642ab0f3e82ee8e4ad029587aafef9571ff50190e83757c03b4216c - proccessed ee5bf706b6600a46e5d26327b13c3c1c5f7b261313438d47318702ff6ed8b30b - -2. Quit Docker. - -3. Start Docker. - - > **Note:** Be sure to quit and then restart Docker for Windows before attempting to start containers. - -4. Try to start the container again: - - $ docker start old-container - old-container - -### Hyper-V -Docker for Windows requires a Hyper-V as well as the Hyper-V Module for Windows Powershell to be installed and enabled. See [these instructions](https://msdn.microsoft.com/en-us/virtualization/hyperv_on_windows/quick_start/walkthrough_install) to install Hyper-V manually. A reboot is *required*. If you install Hyper-V without the reboot, Docker for Windows will not work correctly. On some systems, Virtualization needs to be enabled in the BIOS. The steps to do so are Vendor specific, but typically the BIOS option is called `Virtualization Technology (VTx)` or similar. - -### Networking issues - -Some users have reported problems connecting to Docker Hub on the Docker for Windows stable version. (See GitHub issue [22567](https://github.com/docker/docker/issues/22567).) - -Here is an example command and error message: - - PS C:\WINDOWS\system32> docker run hello-world - Unable to find image 'hello-world:latest' locally - Pulling repository docker.io/library/hello-world - C:\Program Files\Docker\Docker\Resources\bin\docker.exe: Error while pulling image: Get https://index.docker.io/v1/repositories/library/hello-world/images: dial tcp: lookup index.docker.io on 10.0.75.1:53: no such host. - See 'C:\Program Files\Docker\Docker\Resources\bin\docker.exe run --help'. - -As an immediate workaround to this problem, reset the DNS server to use the Google DNS fixed address: `8.8.8.8`. You can configure this via the **Settings** -> **Network** dialog, as described in the topic [Network](index.md#network). Docker will automatically restart when you apply this setting, which could take some time. - -We are currently investigating this issue. - -#### Networking issues on pre Beta 10 versions -Docker for Windows Beta 10 and later fixed a number of issues around the networking setup. If you still experience networking issue, this may be related to previous Docker for Windows installations. In this case, please quit Docker for Windows and perform the following steps: - -##### 1. Remove multiple `DockerNAT` VMswitches -You might have multiple Internal VMSwitches called `DockerNAT`. You can view all VMSwitches either via the `Hyper-V Manager` sub-menu `Virtual Switch Manager` or from an elevated Powershell (run as Administrator) prompt by typing `Get-VMSwitch`. Simply delete all VMSwitches with `DockerNAT` in the name, either via the `Virtual Switch Manager` or by using `Remove-VMSwitch` powershell cmdlet. - -##### 2. Remove lingering IP addresses - -You might have lingering IP addresses on the system. They are supposed to get removed when you remove the associated VMSwitches, but sometimes this fails. Using `Remove-NetIPAddress 10.0.75.1` in an elevated Powershell prompt should remove them. - -##### 3. Remove stale NAT configurations - -You might have stale NAT configurations on the system. You should remove them with `Remove-NetNat DockerNAT` on an elevated Powershell prompt. - -##### 4. Remove stale network adapters - -You might have stale Network Adapters on the system. You should remove them with the following commands on an elevated Powershell prompt: - - $vmNetAdapter = Get-VMNetworkAdapter -ManagementOS -SwitchName DockerNAT - Get-NetAdapter "vEthernet (DockerNAT)" | ? { $_.DeviceID -ne $vmNetAdapter.DeviceID } | Disable-NetAdapter -Confirm:$False -PassThru | Rename-NetAdapter -NewName "Broken Docker Adapter" - -Then you can remove them manually via the `devmgmt.msc` (aka Device Manager). You should see them as disabled Hyper-V Virtual Ethernet Adapter under the Network Adapter section. A right-click and selecting **uninstall** should remove the adapter. - -### NAT/IP configuration - -By default, Docker for Windows uses an internal network prefix of `10.0.75.0/24`. Should this clash with your normal network setup, you can change the prefix from the **Settings** menu. See the [Network](index.md#network) topic under [Settings](index.md#docker-settings). - -#### NAT/IP configuration issues on pre Beta 15 versions - -As of Beta 15, Docker for Windows is no longer using a switch with a NAT configuration. The notes below are left here only for older Beta versions. - -As of Beta14, networking for Docker for Windows is configurable through the UI. See the [Network](index.md#network) topic under [Settings](index.md#docker-settings). - -By default, Docker for Windows uses an internal Hyper-V switch with a NAT configuration with a `10.0.75.0/24` prefix. You can change the prefix used (as well as the DNS server) via the **Settings** menu as described in the [Network](index.md#network) topic. - -If you have additional Hyper-V VMs and they are attached to their own NAT prefixes, the prefixes need to be managed carefully, due to limitation of the Windows NAT implementation. Specifically, Windows currently only allows a single internal NAT prefix. If you need additional prefixes for your other VMs, you can create a larger NAT prefix. - -To create a larger NAT prefix, do the following. - -1. Stop Docker for Windows and remove all NAT prefixes with `Remove-NetNAT`. - -2. Create a new shorter NAT prefix which covers the Docker for Windows NAT prefix but allows room for additional NAT prefixes. For example: - - New-NetNat -Name DockerNAT -InternalIPInterfaceAddressPrefix 10.0.0.0/16 - - The next time Docker for Windows starts, it will use the new, wider prefix. - -Alternatively, you can use a different NAT name and NAT prefix and adjust the NAT prefix Docker for Windows uses accordingly via the `Settings` panel. - ->**Note**: You also need to adjust your existing VMs to use IP addresses from within the new NAT prefix. - - -### Host filesystem Sharing - -The Linux VM used for Docker for Windows uses SMB/CIFS mounting of the host filesystem. In order to use this feature you must explicitly enable it via the `Settings` menu. You will get prompted for your Username and Password. - -Unfortunately, this setup does not support passwords which contain Unicode characters, so your password must be 8-bit ASCII only. - -The setup also does not support empty password, so you should set a password if you want to use the host filesystem sharing feature. Beta 11 and newer of Docker for Windows will display a warning, but versions earlier will not. - -Note, releases of Docker for Windows prior to Beta 11 also did not support spaces in the password and username, but this has been fixed with Beta 11. - -Please make sure that "File and printer sharing" is enabled in `Control Panel\Network and Internet\Network and Sharing Center\Advanced sharing settings`. - -![Sharing settings](images/win-file-and-printer-sharing.png) - -## Workarounds - -### `inotify` currently does not work on Docker for Windows - -If you are using `Node.js` with `nodemon`, a temporary workaround is to try the fallback polling mode described here: [nodemon isn't restarting node applications](https://github.com/remy/nodemon#application-isnt-restarting). See also this issue on GitHub [Inotify on shared drives does not work](https://github.com/docker/for-win/issues/56#issuecomment-242135705). - -### Reboot - -Restart your PC to stop / discard any vestige of the daemon running from the previously installed version. - -### Unset `DOCKER_HOST` - -You do not need `DOCKER_HOST` set, so unset as it may be pointing at -another Docker (e.g. VirtualBox). If you use bash, `unset ${!DOCKER_*}` -will unset existing `DOCKER` environment variables you have set. For other shells, unset each environment variable individually. - -### Make sure Docker is running for webserver examples - -For the `hello-world-nginx` example and others, Docker for Windows must be running in order to get to the webserver on `http://localhost/`. Make sure that the Docker whale is showing in the menu bar, and that you run the Docker commands in a shell that is connected to the Docker for Windows Engine (not Engine from Toolbox). Otherwise, you might start the webserver container but get a "web page not available" error when you go to `docker`. For more on distinguishing between the two environments, see "Running Docker for Windows and Docker Toolbox" in [Getting Started](index.md). - -### How to solve `port already allocated` errors - -If you see errors like `Bind for 0.0.0.0:8080 failed: port is already allocated` or - `listen tcp:0.0.0.0:8080: bind: address is already in use` ... - -These errors are often caused by some other software on Windows using those -ports. To discover the identity of this software, either use the `resmon.exe` -GUI and click "Network" and then "Listening Ports" or in a powershell use -`netstat -aon | find /i "listening "` to discover the PID of the process -currently using the port (the PID is the number in the rightmost column). Decide -whether to shut the other process down, or to use a different port in your -docker app. - -### Docker fails to start when firewall or anti-virus software is installed - -The **Comodo Firewall currently is incompatible with Hyper-V and some Windows 10 -builds** (possibly, Windows 10 Anniversary Update), which impacts Docker for -Windows. **Other firewalls and anti-virus software might also be incompatible with these Microsoft Windows 10 buids**. The conflict typically occurs after a Windows update or new install of the firewall, and manifests as an error response from the Docker daemon and a **Docker for Windows start failure**. - -See the Comodo forums topics [Comodo Firewall conflict with -Hyper-V](https://forums.comodo.com/bug-reports-cis/comodo-firewall-began-conflict-with-hyperv-t116351.0.html) -and [Windows 10 Anniversary build doesn't allow Comodo drivers to be -installed](https://forums.comodo.com/install-setup-configuration-help-cis/windows-10-aniversary-build-doesnt-allow-comodo-drivers-to-be-installed-t116322.0.html). -A Docker for Windows user-created issue describes the problem specifically as it -relates to Docker: [Docker fails to start on Windows -10](https://github.com/docker/for-win/issues/27). - -For a temporary workaround, uninstall the Comodo Firewall, or explore other -workarounds suggested on the forum. - -
                                  -
                                    - diff --git a/docker-hub/builds.md b/docker-hub/builds.md index 1c663fcf9e..199c437342 100644 --- a/docker-hub/builds.md +++ b/docker-hub/builds.md @@ -51,13 +51,11 @@ settings, log in to Docker Hub and choose /dev/null || 1) && \ - make install && \ - paxctl -cm /usr/bin/${CMD} && \ - cd / && \ - if [ -x /usr/bin/npm -a -z "$NO_NPM_UPDATE" ]; then \ - npm install -g npm && \ - find /usr/lib/node_modules/npm -name test -o -name .bin -type d | xargs rm -rf; \ - fi && \ - apk del curl make gcc g++ python linux-headers paxctl ${DEL_PKGS} && \ - rm -rf /etc/ssl /${CMD}-${VERSION} ${RM_DIRS} \ - /usr/share/man /tmp/* /root/.npm /root/.node-gyp \ - /usr/lib/node_modules/npm/man /usr/lib/node_modules/npm/doc /usr/lib/node_modules/npm/html diff --git a/dockerfiles/Dockerfile-prod-build b/dockerfiles/Dockerfile-prod-build deleted file mode 100644 index 98c39b856f..0000000000 --- a/dockerfiles/Dockerfile-prod-build +++ /dev/null @@ -1,22 +0,0 @@ -FROM bagel/universe:337f873f4f23f4b2603972229ae3519c5f61f6d7 - -ENV ENV production -ENV NODE_ENV production - -COPY ./app /opt/hub/app -COPY ./Makefile /opt/hub/Makefile -COPY ./_webpack /opt/hub/_webpack -COPY ./gulpfile.js /opt/hub/gulpfile.js -COPY ./gulp-tasks /opt/hub/gulp-tasks -COPY ./app-server /opt/hub/app-server -COPY ./.eslintrc /opt/hub/.eslintrc - -RUN make server-prod-target -RUN make server-extras -RUN make js-prod -RUN make images-prod -RUN make docker-font-prod -RUN gulp images::prod -RUN make styles-base-prod -RUN make stats-dir -RUN make css-stats diff --git a/dockerfiles/Dockerfile-stage-build b/dockerfiles/Dockerfile-stage-build deleted file mode 100644 index 113fe30cd3..0000000000 --- a/dockerfiles/Dockerfile-stage-build +++ /dev/null @@ -1,22 +0,0 @@ -FROM bagel/universe:337f873f4f23f4b2603972229ae3519c5f61f6d7 - -ENV ENV staging -ENV NODE_ENV staging - -COPY ./app /opt/hub/app -COPY ./Makefile /opt/hub/Makefile -COPY ./_webpack /opt/hub/_webpack -COPY ./gulpfile.js /opt/hub/gulpfile.js -COPY ./gulp-tasks /opt/hub/gulp-tasks -COPY ./app-server /opt/hub/app-server -COPY ./.eslintrc /opt/hub/.eslintrc - -RUN make server-prod-target -RUN make server-extras -RUN make js-stage -RUN make images-prod -RUN make docker-font-prod -RUN gulp images::prod -RUN make styles-base-prod -RUN make stats-dir -RUN make css-stats diff --git a/dockerfiles/milky-way b/dockerfiles/milky-way deleted file mode 100644 index 2dc5b9c516..0000000000 --- a/dockerfiles/milky-way +++ /dev/null @@ -1,10 +0,0 @@ -FROM node:4.1.2 - -WORKDIR /opt/hub -ENV PATH /opt/hub/node_modules/.bin/:$PATH - -RUN apt-get update -COPY ./private-deps /opt/hub/private-deps -COPY ./package.json /opt/hub/ -ADD ./node_modules /opt/hub/node_modules -#RUN npm install --production diff --git a/dockerfiles/milky-way-no-bin b/dockerfiles/milky-way-no-bin deleted file mode 100644 index 38a9898e44..0000000000 --- a/dockerfiles/milky-way-no-bin +++ /dev/null @@ -1,7 +0,0 @@ -FROM bagel/milky-way:337f873f4f23f4b2603972229ae3519c5f61f6d7 - -RUN rm -rf /opt/hub/node_modules/.bin && \ - ls && \ - tar -czf modules.tar ./node_modules/* - -CMD ["cat", "/opt/hub/modules.tar"] diff --git a/dockerfiles/saas-config b/dockerfiles/saas-config deleted file mode 100644 index c8db476d11..0000000000 --- a/dockerfiles/saas-config +++ /dev/null @@ -1,29 +0,0 @@ -FROM bagel/universe:337f873f4f23f4b2603972229ae3519c5f61f6d7 - -# Source -COPY ./app /opt/hub/app -# Webpack -COPY ./webpack.config.js /opt/hub/webpack.config.js -COPY ./_webpack /opt/hub/_webpack -# Make -COPY ./Makefile /opt/hub/Makefile -# Gulp -COPY ./gulpfile.js /opt/hub/gulpfile.js -COPY ./gulp-tasks /opt/hub/gulp-tasks -# ESLint -COPY ./.eslintrc /opt/hub/.eslintrc -# Flow -ENV LOGNAME bagels -COPY ./flow-libs /opt/hub/flow-libs -COPY .flowconfig /opt/hub/.flowconfig -ENV PATH /opt/flow/:$PATH - -RUN npm install -RUN DEBUG=* ENV=local webpack -d -RUN make server-target -RUN make styles-base -RUN gulp images::dev -RUN make images -RUN make docker-font-dev -# favicon -COPY ./app/favicon.ico /opt/hub/app/.build/ diff --git a/dockerfiles/universe b/dockerfiles/universe deleted file mode 100644 index 638098c2c4..0000000000 --- a/dockerfiles/universe +++ /dev/null @@ -1,13 +0,0 @@ -FROM bagel/milky-way:337f873f4f23f4b2603972229ae3519c5f61f6d7 - -ENV NODE_ENV development - -RUN apt-get install libelf-dev unzip -y - -RUN cd /opt && wget http://flowtype.org/downloads/flow-linux64-latest.zip && unzip flow-linux64-latest.zip && rm flow-linux64-latest.zip - -# npm global deps -RUN npm install -g gulp jest-cli - -# npm deps -RUN cd /opt/hub && npm install diff --git a/docs/Dockerfile b/docs/Dockerfile deleted file mode 100644 index ca1208d173..0000000000 --- a/docs/Dockerfile +++ /dev/null @@ -1,8 +0,0 @@ -FROM docs/base:oss -MAINTAINER Docker Docs - -ENV PROJECT=docker-hub - -COPY . /src -RUN rm -rf /docs/content/$PROJECT/ -COPY . /docs/content/$PROJECT/ diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index d05c6a9cf9..0000000000 --- a/docs/Makefile +++ /dev/null @@ -1,119 +0,0 @@ -.PHONY: all binary build cross default docs docs-build docs-shell shell test test-unit test-integration test-integration-cli test-docker-py validate - -# env vars passed through directly to Docker's build scripts -# to allow things like `make DOCKER_CLIENTONLY=1 binary` easily -# `docs/sources/contributing/devenvironment.md ` and `project/PACKAGERS.md` have some limited documentation of some of these -DOCKER_ENVS := \ - -e BUILDFLAGS \ - -e DOCKER_CLIENTONLY \ - -e DOCKER_EXECDRIVER \ - -e DOCKER_GRAPHDRIVER \ - -e TESTDIRS \ - -e TESTFLAGS \ - -e TIMEOUT -# note: we _cannot_ add "-e DOCKER_BUILDTAGS" here because even if it's unset in the shell, that would shadow the "ENV DOCKER_BUILDTAGS" set in our Dockerfile, which is very important for our official builds - -# to allow `make DOCSDIR=docs docs-shell` (to create a bind mount in docs) -DOCS_MOUNT := $(if $(DOCSDIR),-v $(CURDIR):/docs/content/docker-hub/) - -# to allow `make DOCSPORT=9000 docs` -DOCSPORT := 8000 - -# Get the IP ADDRESS -DOCKER_IP=$(shell python -c "import urlparse ; print urlparse.urlparse('$(DOCKER_HOST)').hostname or ''") -HUGO_BASE_URL=$(shell test -z "$(DOCKER_IP)" && echo localhost || echo "$(DOCKER_IP)") -HUGO_BIND_IP=0.0.0.0 - -GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD 2>/dev/null) -DOCKER_IMAGE := docker$(if $(GIT_BRANCH),:$(GIT_BRANCH)) -DOCKER_DOCS_IMAGE := docs-base$(if $(GIT_BRANCH),:$(GIT_BRANCH)) - - -DOCKER_RUN_DOCS := docker run --rm -it $(DOCS_MOUNT) -e AWS_S3_BUCKET -e NOCACHE - -# for some docs workarounds (see below in "docs-build" target) -GITCOMMIT := $(shell git rev-parse --short HEAD 2>/dev/null) - -default: docs - -test: docs-build - $(DOCKER_RUN_DOCS) -p $(if $(DOCSPORT),$(DOCSPORT):)8000 \ - -v $(CURDIR):/docs/content/docker-hub/ \ - -e DOCKERHOST "$(DOCKER_DOCS_IMAGE)" \ - hugo server \ - --log=true --watch=true \ - --port=$(DOCSPORT) --baseUrl=$(HUGO_BASE_URL) --bind=$(HUGO_BIND_IP) - - -docs: docs-build - $(DOCKER_RUN_DOCS) -p $(if $(DOCSPORT),$(DOCSPORT):)8000 -e DOCKERHOST "$(DOCKER_DOCS_IMAGE)" hugo server --port=$(DOCSPORT) --baseUrl=$(HUGO_BASE_URL) --bind=$(HUGO_BIND_IP) - -docs-draft: docs-build - $(DOCKER_RUN_DOCS) -p $(if $(DOCSPORT),$(DOCSPORT):)8000 -e DOCKERHOST "$(DOCKER_DOCS_IMAGE)" hugo server --buildDrafts="true" --port=$(DOCSPORT) --baseUrl=$(HUGO_BASE_URL) --bind=$(HUGO_BIND_IP) - - -docs-shell: docs-build - $(DOCKER_RUN_DOCS) -p $(if $(DOCSPORT),$(DOCSPORT):)8000 "$(DOCKER_DOCS_IMAGE)" bash - - -docs-build: -# ( git remote | grep -v upstream ) || git diff --name-status upstream/release..upstream/docs ./ > ./changed-files -# echo "$(GIT_BRANCH)" > GIT_BRANCH -# echo "$(AWS_S3_BUCKET)" > AWS_S3_BUCKET -# echo "$(GITCOMMIT)" > GITCOMMIT - docker build -t "$(DOCKER_DOCS_IMAGE)" . - -# use screenshot container to update screenshots -NOAUTHSCREENSHOT := docker run -it --rm --name screen -v $(CURDIR):/srv --env-file=noauthpasswords.env svendowideit/screenshot -SCREENSHOT := docker run -it --rm --name screen -v $(CURDIR):/srv --env-file=passwords.env svendowideit/screenshot -NOLINKS := docker run -it --rm --name screen -v $(CURDIR):/srv --env-file=passwords.env --env-file=nolinks.env svendowideit/screenshot -GITHUB_DOCSUSER := docker run -it --rm --name screen -v $(CURDIR):/srv --env-file=passwords.env --env-file=githubdocs.env svendowideit/screenshot - -# testing -testimage: - #$(NOAUTHSCREENSHOT) https://hub-beta.docker.com/ images/register-web.png 1280px - #$(SCREENSHOT) https://hub-beta.docker.com/explore/ images/dashboard.png 1280px - $(SCREENSHOT) https://hub-beta.docker.com/organizations/ orgs.png 1280px - -t2: - $(NOAUTHSCREENSHOT) https://hub-beta.docker.com/ images/register-web.png 1280px - -docs-images: - # non-authenticated - $(NOAUTHSCREENSHOT) https://hub-beta.docker.com/ images/register-web.png 1280px - $(NOAUTHSCREENSHOT) https://hub-beta.docker.com/login/ images/login-web.png 1280px - # authenticated - $(SCREENSHOT) https://hub-beta.docker.com/explore/ images/dashboard.png 1280px - $(SCREENSHOT) https://hub-beta.docker.com/organizations/ images/orgs.png 1280px - # $(SCREENSHOT) https://hub-beta.docker.com/ images/deploy_key.png 1280px - $(SCREENSHOT) https://hub-beta.docker.com/r/docsorg/private/~/settings/collaborators/ images/org-repo-collaborators.png 1280px - $(SCREENSHOT) https://hub-beta.docker.com/ images/repos.png 1280px - # $(SCREENSHOT) https://hub-beta.docker.com/ images/invite.png 1280px - # $(SCREENSHOT) https://hub-beta.docker.com/ images/build-trigger.png 1280px - $(SCREENSHOT) https://hub-beta.docker.com/ images/hub.png 1280px - $(SCREENSHOT) https://hub-beta.docker.com/u/docsorg/dashboard/teams/boomteam/ images/groups.png 1280px - $(SCREENSHOT) https://hub-beta.docker.com/r/library/busybox/tags/# images/busybox-image-tags.png 1280px*600px - # docs/images/getting-started.png (needs a new empty account) - -nolinks: - # bitbucket.md, github.md - # uses the `nolinks` user: an account that has no accounts linked - $(NOLINKS) https://hub-beta.docker.com/account/authorized-services/ images/authorized-services.png 1280px - $(NOLINKS) https://hub-beta.docker.com/account/authorized-services/github-permissions/ add-authorized-github-service.png 1280px - -# BROKEN -github: - $(GITHUB_DOCSUSER) https://github.com/docsuser/private/settings/hooks github-side-hook.png 1280px - -# BROKEN, wrong URL and needs hand editing to capture the specific UI elements -broken-gitimages: - $(SCREENSHOT) https://hub-beta.docker.com/ images/gh_settings.png - $(SCREENSHOT) https://hub-beta.docker.com/ images/gh_menu.png - $(SCREENSHOT) https://hub-beta.docker.com/ images/gh_add_ssh_user_key.png - $(SCREENSHOT) https://hub-beta.docker.com/ images/gh_team_members.png - $(SCREENSHOT) https://hub-beta.docker.com/ images/gh-check-user-org-dh-app-access.png - $(SCREENSHOT) https://hub-beta.docker.com/ images/gh_service_hook.png - $(SCREENSHOT) https://hub-beta.docker.com/ images/gh-check-admin-org-dh-app-access.png - $(SCREENSHOT) https://hub-beta.docker.com/ images/gh_org_members.png - $(SCREENSHOT) https://hub-beta.docker.com/ images/gh_docker-service.png - $(SCREENSHOT) https://hub-beta.docker.com/ images/gh_repo_deploy_key.png diff --git a/docs/accounts.md b/docs/accounts.md deleted file mode 100644 index f58acdef80..0000000000 --- a/docs/accounts.md +++ /dev/null @@ -1,57 +0,0 @@ -+++ -title = "Your Docker ID" -description = "Your Docker ID" -keywords = ["Docker, docker, trusted, sign-up, registry, accounts, plans, Dockerfile, Docker Hub, docs, documentation"] -[menu.main] -parent="mn_pubhub" -weight=-90 -+++ - -# Your Docker ID - -You can `search` for Docker images and `pull` them from [Docker -Hub](https://hub.docker.com) without signing in or even having an -account. However, to `push` images, leave comments, or to *star* -a repository, you need a free [Docker ID](https://hub.docker.com) to log in to Docker Hub. - -Once you have a personal Docker ID, you can also create or join -Docker Hub [Organizations and Teams](orgs.md). - -## Register for a Docker ID - -If you're not already logged in, go to [Docker Hub](https://hub.docker.com) -to use the sign up page. -A valid email address is required to register. A verification email is sent to this address to activate your account. - -You cannot log in to your Docker ID until you verify the email address. - -#### Confirm your email - -Once you've filled in the registration form, check your email for a welcome message asking for -confirmation so we can activate your account. - -## Login - -After you complete the account creation process, you can log in any time using the web console with your Docker ID: - -![Login using the web console](images/login-web.png) - -Or via the command line with the `docker login` command: - - $ docker login - -Your Docker ID is now active and ready to use. - -> **Note:** -> Your authentication credentials will be stored in the `.dockercfg` -> authentication file in your home directory. - -### Upgrading your account - -Free Hub accounts include one private registry. If you need more private registries, you can [upgrade your account](https://hub.docker.com/account/billing-plans/) to a paid plan directly from the Hub. - -## Password reset process - -If you can't access your account for some reason, you can reset your password -from the [*Password Reset*](https://hub.docker.com/reset-password/) -page. diff --git a/docs/bitbucket.md b/docs/bitbucket.md deleted file mode 100644 index 7bd6d8ec27..0000000000 --- a/docs/bitbucket.md +++ /dev/null @@ -1,50 +0,0 @@ -+++ -title = "Automated Builds with Bitbucket" -description = "Docker Hub Automated Builds using Bitbucket" -keywords = ["Docker, docker, registry, accounts, plans, Dockerfile, Docker Hub, docs, documentation, trusted, builds, trusted builds, automated builds, bitbucket"] -[menu.main] -parent="mn_pubhub" -weight=8 -+++ - -# Automated Builds with Bitbucket - -If you've previously linked Docker Hub to your Bitbucket account, -you'll be able to skip to [Creating an Automated Build](#creating-an-automated-build). - -## Linking to your Bitbucket account - -In order to set up an Automated Build of a repository on Bitbucket, you need to -link your [Docker Hub](https://hub.docker.com/account/authorized-services/) -account to a Bitbucket account. This will allow the registry to see your Bitbucket -repositories. - -To add, remove or view your linked account, go to the "Linked Accounts & Services" -section of your Hub profile "Settings". - -![authorized-services](images/authorized-services.png) - -Then follow the onscreen instructions to authorize and link your -Bitbucket account to Docker Hub. Once it is linked, you'll be able -to create a Docker Hub repository from which to create the Automatic Build. - -## Creating an Automated Build - -You can [create an Automated Build]( -https://hub.docker.com/add/automated-build/bitbucket/orgs/) from any of your -public or private Bitbucket repositories with a `Dockerfile`. - -To get started, log in to Docker Hub and click the -"Create ▼" menu item at the top right of the screen. Then select -[Create Automated Build](https://hub.docker.com/add/automated-build). - -Select the the linked Bitbucket account, and then choose a repository to set up -an Automated Build for. - -## The Bitbucket webhook - -When you create an Automated Build in Docker Hub, a webhook is added to your Bitbucket repository automatically. - -You can also manually add a webhook from your repository's **Settings** page. Set the URL to `https://registry.hub.docker.com/hooks/bitbucket`, to be triggered for repository pushes. - -![bitbucket-hooks](images/bitbucket-hook.png) diff --git a/docs/builds.md b/docs/builds.md deleted file mode 100644 index 199c437342..0000000000 --- a/docs/builds.md +++ /dev/null @@ -1,219 +0,0 @@ -+++ -title = "Automated Builds" -description = "Docker Hub Automated Builds" -keywords = ["Dockerfile, Hub, builds, trusted builds, automated builds"] -[menu.main] -parent="mn_pubhub" -weight=6 -+++ - -# Automated Builds on Docker Hub - -You can build your images automatically from a build context stored in a repository. A *build context* is a Dockerfile and any files at a specific location. For an automated build, the build context is a repository containing a Dockerfile. - -Automated Builds have several advantages: - - * Images built in this way are built exactly as specified. - * The `Dockerfile` is available to anyone with access to -your Docker Hub repository. - * Your repository is kept up-to-date with code changes automatically. - -Automated Builds are supported for both public and private repositories -on both [GitHub](http://github.com) and [Bitbucket](https://bitbucket.org/). This document guides you through the process of working with automated builds. - -## Prerequisites - -To use automated builds you must have an [account on Docker Hub](accounts.md) and on the hosted repository provider (GitHub or Bitbucket). If -you have previously linked your Github or Bitbucket account, you must have -chosen the Public and Private connection type. To view your current connection -settings, log in to Docker Hub and choose Profile > Settings > Linked Accounts & Services. - - -## Link to a hosted repository service - -1. Log into Docker Hub. - -2. Navigate to Profile > Settings > Linked Accounts & Services. - -3. Click the service you want to link. - - The system prompts you to choose between Public and Private and Limited Access. The Public and Private connection type is required if you want to use the Automated Builds. - -4. Press Select under Public and Private connection type. - - The system prompts you to enter your service credentials (Bitbucket or GitHub) to login. For example, Bitbucket's prompt looks like this: - - ![Bitbucket](images/bitbucket_creds.png) - - After you grant access to your code repository, the system returns you to Docker Hub and the link is complete. - - ![Linked account](images/linked-acct.png) - -## Create an automated build - -Automated build repositories rely on the integration with your code repository -in order to build. However, you can also push already-built images to these -repositories using the `docker push` command. - -1. Select **Create** > **Create Automated Build** from Docker Hub. - - The system prompts you with a list of User/Organizations and code repositories. - -2. Select from the User/Organizations. - -3. Optionally, type to filter the repository list. - -4. Pick the project to build. - - The system displays the Create Automated Build dialog. - - ![Create dialog](images/create-dialog1.png) - - The dialog assumes some defaults which you can customize. By default, Docker - builds images for each branch in your repository. It assumes the Dockerfile - lives at the root of your source. When it builds an image, Docker tags it with - the branch name. - -6. Customize the automated build by pressing the Click here to customize this behavior link. - - ![Create dialog](images/create-dialog.png) - - Specify which code branches or tags to build from. You can add new - configurations by clicking the + (plus sign). The dialog accepts regular - expressions. - - ![Create dialog](images/regex-help.png) - -9. Click Create. - - The system displays the home page for your AUTOMATED BUILD. - - ![Home page](images/home-page.png) - - Within GitHub, a Docker integration appears in your repositories Settings > Webhooks & services page. - - ![GitHub](images/docker-integration.png) - - A similar page appears in Bitbucket if you use that code repository.Be - careful to leave the Docker integration in place. Removing it causes your - automated builds to stop. - -### Understand the build process - -The first time you create a new automated build, Docker Hub builds your image. -In a few minutes, you should see your new build on the image dashboard. The -Build Details page shows a log of your build systems: - -![Pending](images/first_pending.png) - -During the build process, Docker copies the contents of your `Dockerfile` to -Docker Hub. The Docker community (for public repositories) or approved team -members/orgs (for private repositories) can then view the Dockerfile on your -repository page. - -The build process looks for a `README.md` in the same directory as your -`Dockerfile`. If you have a `README.md` file in your repository, it is used in -the repository as the full description. If you change the full description after -a build, it's overwritten the next time the Automated Build runs. To make -changes, modify the `README.md` in your Git repository. - -You can only trigger one build at a time and no more than one every five -minutes. If you already have a build pending, or if you recently submitted a -build request, Docker ignores new requests. - -### Build statuses explained - -Check your build status through the Build Details screen as seen in the following example. - -![Build statuses](images/build-states-ex.png) - -The statuses are: - -* **Queued**: You're in line and your image will be built soon. Queue time varies depending on number of concurrent builds available to you. -* **Building**: Your image is currently being constructed. -* **Success**: The image has been built with no issues. -* **Error**: There was an issue with your image. Click the row to access the Builds Details screen. The banner at the top of the page displays the last sentence of the log file indicating what the error was. If you need more information, scroll to the bottom of the screen to the logs section. - - -## Use the Build Settings page - -The Build Settings page allows you to manage your existing automated build configurations and add new ones. By default, when new code is merged into your source repository, it triggers a build of your DockerHub image. - -![Default checkbox](images/merge_builds.png) - -Clear the checkbox to turn this behavior off. You can use the other settings on -the page to configure and build images. - -## Add and run a new build - -At the top of the Build Dialog is a list of configured builds. You can build from a code branch or by build tag. - -![Build or tag](images/build-by.png) - -Docker builds everything listed whenever a push is made to the code repository. -If you specify a branch or tag, you can manually build that image by -pressing the Trigger. If you use a regular expression syntax (regex) to define -your build branch or tag, Docker does not give you the option to manually build. -To add a new build: - -1. Press the + (plus sign). - -2. Choose the Type. - - You can build by a code branch or by an image tag. - -3. Enter the Name of the branch or tag. - - You can enter a specific value or use a regex to select multiple values. To - see examples of regex, press the Show More link on the right of the page. - - ![Regexhelp](images/regex-help.png) - -4. Enter a Dockerfile location. - -5. Specify a Tag Name. - -6. Press Save Changes. - -If you make a mistake or want to delete a build, press the - (minus sign) and then Save Changes. - -## Repository links - -Repository links let you link one Automated Build with another. If one Automated -Build gets updated, Docker triggers a build of the other. This makes it easy to -ensure that related images are kept in sync. You can link more than one image -repository. You only need to link one side of two related builds. Linking both -sides causes an endless build loop. - -To add a link: - -1. Go to the Build Settings for an automated build repository. - -2. In the Repository Links section, enter an image repository name. - - A remote repository name should be either an official repository name such as `ubuntu` or a public repository name `namespace/repoName`. - -3. Press Add. - - ![Links](images/repo_links.png) - - -## Remote Build triggers - -To trigger Automated Builds programmatically, you can set up a remote build -trigger in another application such as GitHub or Bitbucket. When you Activate -the build trigger for an Automated Build, it supplies you with a Token and a URL. - -![Build trigger screen](images/build-trigger.png) - -You can use `curl` to trigger a build: - -```bash -$ curl --data build=true -X POST https://registry.hub.docker.com/u/svendowideit/testhook/trigger/be579c -82-7c0e-11e4-81c4-0242ac110020/ -OK -``` - -To verify everything is working correctly, check the **Last 10 Trigger Logs** on the page. - -  diff --git a/docs/github.md b/docs/github.md deleted file mode 100644 index 797c37cc9c..0000000000 --- a/docs/github.md +++ /dev/null @@ -1,204 +0,0 @@ -+++ -title = "Automated Builds from GitHub" -description = "Docker Hub Automated Builds with GitHub" -keywords = ["Docker, docker, registry, accounts, plans, Dockerfile, Docker Hub, docs, documentation, trusted, builds, trusted builds, automated builds, GitHub"] -[menu.main] -parent="mn_pubhub" -weight=9 -+++ - -# Automated Builds from GitHub - -If you've previously linked Docker Hub to your GitHub account, -you'll be able to skip to [Creating an Automated Build](#creating-an-automated-build). - -## Linking Docker Hub to a GitHub account - -> *Note:* -> Automated Builds currently require *read* and *write* access since -> [Docker Hub](https://hub.docker.com) needs to set up a GitHub service -> hook. We have no choice here, this is how GitHub manages permissions. -> We do guarantee nothing else will be touched in your account. - -In order to set up an Automated Build of a repository on GitHub, you need to -link [Docker Hub](https://hub.docker.com/account/authorized-services/) to your GitHub account. This will allow the registry to see your GitHub -repositories. - -To add, remove or view your linked account, go to the "Linked Accounts & Services" section of your Hub profile "Settings". - -![authorized-services](images/authorized-services.png) - -When linking to GitHub, you'll need to select either "Public and Private", -or "Limited Access" linking. - -![add-authorized-github-service.png](images/add-authorized-github-service.png) - -The "Public and Private" option is the easiest to use, -as it grants the Docker Hub full access to all of your repositories. GitHub -also allows you to grant access to repositories belonging to your GitHub -organizations. - -If you choose "Limited Access", Docker Hub only gets permission -to access your public data and public repositories. - -Follow the onscreen instructions to authorize and link your -GitHub account to Docker Hub. Once it is linked, you'll be able to -choose a source repository from which to create the Automatic Build. - -You will be able to review and revoke Docker Hub's access by visiting the -[GitHub User's Applications settings](https://github.com/settings/applications). - -> **Note**: If you delete the GitHub account linkage that is used for one of your -> automated build repositories, the previously built images will still be available. -> If you re-link to that GitHub account later, the automated build can be started -> using the "Start Build" button on the Hub, or if the webhook on the GitHub repository -> still exists, it will be triggered by any subsequent commits. - -## Auto builds and limited linked GitHub accounts. - -If you selected to link your GitHub account with only a "Limited Access" link, then -after creating your automated build, you will need to either manually trigger a -Docker Hub build using the "Start a Build" button, or add the GitHub webhook -manually, as described in [GitHub Service Hooks](#github-service-hooks). - -## Changing the GitHub user link - -If you want to remove, or change the level of linking between your GitHub account -and the Docker Hub, you need to do this in two places. - -First, remove the "Linked Account" from your Docker Hub "Settings". -Then go to your GitHub account's Personal settings, and in the "Applications" -section, "Revoke access". - -You can now re-link your account at any time. - -## GitHub organizations - -GitHub organizations and private repositories forked from organizations will be -made available to auto build using the "Docker Hub Registry" application, which -needs to be added to the organization - and then will apply to all users. - -To check, or request access, go to your GitHub user's "Setting" page, select the -"Applications" section from the left side bar, then click the "View" button for -"Docker Hub Registry". - -![Check User access to GitHub](images/gh-check-user-org-dh-app-access.png) - -The organization's administrators may need to go to the Organization's "Third -party access" screen in "Settings" to grant or deny access to the Docker Hub -Registry application. This change will apply to all organization members. - -![Check Docker Hub application access to Organization](images/gh-check-admin-org-dh-app-access.png) - -More detailed access controls to specific users and GitHub repositories can be -managed using the GitHub "People and Teams" interfaces. - -## Creating an Automated Build - -You can [create an Automated Build]( -https://hub.docker.com/add/automated-build/github/) from any of your -public or private GitHub repositories that have a `Dockerfile`. - -Once you've selected the source repository, you can then configure: - -- The Hub user/org namespace the repository is built to - either your Docker ID name, or the name of any Hub organizations your account is in -- The Docker repository name the image is built to -- The description of the repository -- If the visibility of the Docker repository: "Public" or "Private" - You can change the accessibility options after the repository has been created. - If you add a Private repository to a Hub user namespace, then you can only add other users - as collaborators, and those users will be able to view and pull all images in that - repository. To configure more granular access permissions, such as using teams of - users or allow different users access to different image tags, then you need - to add the Private repository to a Hub organization for which your user has Administrator - privileges. -- Enable or disable rebuilding the Docker image when a commit is pushed to the - GitHub repository. - -You can also select one or more: -- The git branch/tag, -- A repository sub-directory to use as the context, -- The Docker image tag name - -You can modify the description for the repository by clicking the "Description" section -of the repository view. -Note that the "Full Description" will be over-written by the README.md file when the -next build is triggered. - -## GitHub private submodules - -If your GitHub repository contains links to private submodules, you'll get an -error message in your build. - -Normally, the Docker Hub sets up a deploy key in your GitHub repository. -Unfortunately, GitHub only allows a repository deploy key to access a single repository. - -To work around this, you can create a dedicated user account in GitHub and attach -the automated build's deploy key that account. This dedicated build account -can be limited to read-only access to just the repositories required to build. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                                    StepScreenshotDescription
                                    1.First, create the new account in GitHub. It should be given read-only - access to the main repository and all submodules that are needed.
                                    2.This can be accomplished by adding the account to a read-only team in - the organization(s) where the main GitHub repository and all submodule - repositories are kept.
                                    3.Next, remove the deploy key from the main GitHub repository. This can be done in the GitHub repository's "Deploy keys" Settings section.
                                    4.Your automated build's deploy key is in the "Build Details" menu - under "Deploy keys".
                                    5.In your dedicated GitHub User account, add the deploy key from your - Docker Hub Automated Build.
                                    - -## GitHub service hooks - -A GitHub Service hook allows GitHub to notify the Docker Hub when something has -been committed to a given git repository. - -When you create an Automated Build from a GitHub user that has full "Public and -Private" linking, a Service Hook should get automatically added to your GitHub -repository. - -If your GitHub account link to the Docker Hub is "Limited Access", then you will -need to add the Service Hook manually. - -To add, confirm, or modify the service hook, log in to GitHub, then navigate to -the repository, click "Settings" (the gear), then select "Webhooks & Services". -You must have Administrator privileges on the repository to view or modfy -this setting. - -The image below shows the "Docker" Service Hook. - -![bitbucket-hooks](images/github-side-hook.png) - -If you add the "Docker" service manually, make sure the "Active" checkbox is -selected and click the "Update service" button to save your changes. diff --git a/docs/images/add-authorized-github-service.png b/docs/images/add-authorized-github-service.png deleted file mode 100644 index a4fd351713..0000000000 Binary files a/docs/images/add-authorized-github-service.png and /dev/null differ diff --git a/docs/images/authorized-services.png b/docs/images/authorized-services.png deleted file mode 100644 index ccae6a7256..0000000000 Binary files a/docs/images/authorized-services.png and /dev/null differ diff --git a/docs/images/bitbucket-hook.png b/docs/images/bitbucket-hook.png deleted file mode 100644 index 3fd37708d8..0000000000 Binary files a/docs/images/bitbucket-hook.png and /dev/null differ diff --git a/docs/images/bitbucket_creds.png b/docs/images/bitbucket_creds.png deleted file mode 100644 index b24e185268..0000000000 Binary files a/docs/images/bitbucket_creds.png and /dev/null differ diff --git a/docs/images/build-by.png b/docs/images/build-by.png deleted file mode 100644 index d1071da272..0000000000 Binary files a/docs/images/build-by.png and /dev/null differ diff --git a/docs/images/build-states-ex.png b/docs/images/build-states-ex.png deleted file mode 100644 index 8f068ddd4d..0000000000 Binary files a/docs/images/build-states-ex.png and /dev/null differ diff --git a/docs/images/build-trigger.png b/docs/images/build-trigger.png deleted file mode 100644 index 8f034608ae..0000000000 Binary files a/docs/images/build-trigger.png and /dev/null differ diff --git a/docs/images/busybox-image-tags.png b/docs/images/busybox-image-tags.png deleted file mode 100644 index c3b07adb5e..0000000000 Binary files a/docs/images/busybox-image-tags.png and /dev/null differ diff --git a/docs/images/create-dialog.png b/docs/images/create-dialog.png deleted file mode 100644 index 1a4bddaf9b..0000000000 Binary files a/docs/images/create-dialog.png and /dev/null differ diff --git a/docs/images/create-dialog1.png b/docs/images/create-dialog1.png deleted file mode 100644 index c14e099f25..0000000000 Binary files a/docs/images/create-dialog1.png and /dev/null differ diff --git a/docs/images/dashboard.png b/docs/images/dashboard.png deleted file mode 100644 index 038be4cbba..0000000000 Binary files a/docs/images/dashboard.png and /dev/null differ diff --git a/docs/images/deploy_key.png b/docs/images/deploy_key.png deleted file mode 100644 index f1d8d92d22..0000000000 Binary files a/docs/images/deploy_key.png and /dev/null differ diff --git a/docs/images/docker-integration.png b/docs/images/docker-integration.png deleted file mode 100644 index 362e27ac09..0000000000 Binary files a/docs/images/docker-integration.png and /dev/null differ diff --git a/docs/images/first_pending.png b/docs/images/first_pending.png deleted file mode 100644 index 9deaeeea49..0000000000 Binary files a/docs/images/first_pending.png and /dev/null differ diff --git a/docs/images/getting-started.png b/docs/images/getting-started.png deleted file mode 100644 index 59f242d797..0000000000 Binary files a/docs/images/getting-started.png and /dev/null differ diff --git a/docs/images/gh-check-admin-org-dh-app-access.png b/docs/images/gh-check-admin-org-dh-app-access.png deleted file mode 100644 index 0df38c6946..0000000000 Binary files a/docs/images/gh-check-admin-org-dh-app-access.png and /dev/null differ diff --git a/docs/images/gh-check-user-org-dh-app-access.png b/docs/images/gh-check-user-org-dh-app-access.png deleted file mode 100644 index 13ad6468f6..0000000000 Binary files a/docs/images/gh-check-user-org-dh-app-access.png and /dev/null differ diff --git a/docs/images/gh_add_ssh_user_key.png b/docs/images/gh_add_ssh_user_key.png deleted file mode 100644 index 7d0092170f..0000000000 Binary files a/docs/images/gh_add_ssh_user_key.png and /dev/null differ diff --git a/docs/images/gh_docker-service.png b/docs/images/gh_docker-service.png deleted file mode 100644 index 7a84c81b7e..0000000000 Binary files a/docs/images/gh_docker-service.png and /dev/null differ diff --git a/docs/images/gh_menu.png b/docs/images/gh_menu.png deleted file mode 100644 index 84458a445f..0000000000 Binary files a/docs/images/gh_menu.png and /dev/null differ diff --git a/docs/images/gh_org_members.png b/docs/images/gh_org_members.png deleted file mode 100644 index 465f5da565..0000000000 Binary files a/docs/images/gh_org_members.png and /dev/null differ diff --git a/docs/images/gh_repo_deploy_key.png b/docs/images/gh_repo_deploy_key.png deleted file mode 100644 index 983b5eec77..0000000000 Binary files a/docs/images/gh_repo_deploy_key.png and /dev/null differ diff --git a/docs/images/gh_service_hook.png b/docs/images/gh_service_hook.png deleted file mode 100644 index c344c24afc..0000000000 Binary files a/docs/images/gh_service_hook.png and /dev/null differ diff --git a/docs/images/gh_settings.png b/docs/images/gh_settings.png deleted file mode 100644 index 2af9cb5138..0000000000 Binary files a/docs/images/gh_settings.png and /dev/null differ diff --git a/docs/images/gh_team_members.png b/docs/images/gh_team_members.png deleted file mode 100644 index 3bdf4abd95..0000000000 Binary files a/docs/images/gh_team_members.png and /dev/null differ diff --git a/docs/images/github-side-hook.png b/docs/images/github-side-hook.png deleted file mode 100644 index c742b4080a..0000000000 Binary files a/docs/images/github-side-hook.png and /dev/null differ diff --git a/docs/images/groups.png b/docs/images/groups.png deleted file mode 100644 index b725b48ba9..0000000000 Binary files a/docs/images/groups.png and /dev/null differ diff --git a/docs/images/home-page.png b/docs/images/home-page.png deleted file mode 100644 index e9c66cec9a..0000000000 Binary files a/docs/images/home-page.png and /dev/null differ diff --git a/docs/images/hub.png b/docs/images/hub.png deleted file mode 100644 index 959f961ae5..0000000000 Binary files a/docs/images/hub.png and /dev/null differ diff --git a/docs/images/invite.png b/docs/images/invite.png deleted file mode 100644 index f663340443..0000000000 Binary files a/docs/images/invite.png and /dev/null differ diff --git a/docs/images/linked-acct.png b/docs/images/linked-acct.png deleted file mode 100644 index 340733602c..0000000000 Binary files a/docs/images/linked-acct.png and /dev/null differ diff --git a/docs/images/login-web.png b/docs/images/login-web.png deleted file mode 100644 index 64e29c9014..0000000000 Binary files a/docs/images/login-web.png and /dev/null differ diff --git a/docs/images/merge_builds.png b/docs/images/merge_builds.png deleted file mode 100644 index 589bba9325..0000000000 Binary files a/docs/images/merge_builds.png and /dev/null differ diff --git a/docs/images/org-repo-collaborators.png b/docs/images/org-repo-collaborators.png deleted file mode 100644 index 3d80a1aa66..0000000000 Binary files a/docs/images/org-repo-collaborators.png and /dev/null differ diff --git a/docs/images/orgs.png b/docs/images/orgs.png deleted file mode 100644 index fe1b89b31c..0000000000 Binary files a/docs/images/orgs.png and /dev/null differ diff --git a/docs/images/plus-carrot.png b/docs/images/plus-carrot.png deleted file mode 100644 index 8c4cd37ded..0000000000 Binary files a/docs/images/plus-carrot.png and /dev/null differ diff --git a/docs/images/prompt.png b/docs/images/prompt.png deleted file mode 100644 index a94ccf08c9..0000000000 Binary files a/docs/images/prompt.png and /dev/null differ diff --git a/docs/images/regex-help.png b/docs/images/regex-help.png deleted file mode 100644 index ad404de476..0000000000 Binary files a/docs/images/regex-help.png and /dev/null differ diff --git a/docs/images/register-web.png b/docs/images/register-web.png deleted file mode 100644 index ea95e1f50b..0000000000 Binary files a/docs/images/register-web.png and /dev/null differ diff --git a/docs/images/repo_links.png b/docs/images/repo_links.png deleted file mode 100644 index 09a4bd63c1..0000000000 Binary files a/docs/images/repo_links.png and /dev/null differ diff --git a/docs/images/repos.png b/docs/images/repos.png deleted file mode 100644 index 959f961ae5..0000000000 Binary files a/docs/images/repos.png and /dev/null differ diff --git a/docs/images/scan-drilldown.gif b/docs/images/scan-drilldown.gif deleted file mode 100644 index e74acc162e..0000000000 Binary files a/docs/images/scan-drilldown.gif and /dev/null differ diff --git a/docs/images/scan-results.png b/docs/images/scan-results.png deleted file mode 100644 index 608674fee3..0000000000 Binary files a/docs/images/scan-results.png and /dev/null differ diff --git a/docs/images/scan-tags.png b/docs/images/scan-tags.png deleted file mode 100644 index ec2de8baad..0000000000 Binary files a/docs/images/scan-tags.png and /dev/null differ diff --git a/docs/index.md b/docs/index.md deleted file mode 100644 index 5a51c99055..0000000000 --- a/docs/index.md +++ /dev/null @@ -1,92 +0,0 @@ -+++ -title = "Overview of Docker Hub" -description = "Docker Hub overview" -keywords = ["Docker, docker, registry, accounts, plans, Dockerfile, Docker Hub, docs, documentation, accounts, organizations, repositories, groups, teams"] -aliases = "/docker-hub/overview/" -[menu.main] -parent="mn_pubhub" -weight=-99 - -+++ - -# Overview of Docker Hub - -[Docker Hub](https://hub.docker.com) is a cloud-based registry service which -allows you to link to code repositories, build your images and test them, stores -manually pushed images, and links to [Docker Cloud](https://docs.docker.com/docker-cloud/) so you can deploy images to your -hosts. It provides a centralized resource for container image discovery, -distribution and change management, [user and team collaboration](orgs.md), and -workflow automation throughout the development pipeline. - -Log in to Docker Hub and Docker Cloud using [your free Docker ID](accounts.md). - -![Getting started with Docker Hub](./images/getting-started.png) - -Docker Hub provides the following major features: - -* [Image Repositories](repos.md): Find, manage, and push and pull images from community, official, and private image libraries. -* [Automated Builds](builds.md): Automatically create new images when you make changes to a source code repository. -* [Webhooks](webhooks.md): A feature of Automated Builds, Webhooks let you trigger actions after a successful push to a repository. -* [Organizations](orgs.md): Create work groups to manage access to image repositories. -* GitHub and Bitbucket Integration: Add the Hub and your Docker Images to your current workflows. - - -## Create a Docker ID - -To explore Docker Hub, you'll need to create an account by following the -directions in [Your Docker ID](accounts.md). - -> **Note**: You can search for and pull Docker images from Hub without logging in, however to push images you must log in. - -Your Docker ID gives you one private Docker Hub repository for free. If you need -more private repositories, you can upgrade from your free account to a paid -plan. To learn more, log in to Docker Hub and go to [Billing & Plans](https://hub.docker.com/account/billing-plans/), in the Settings menu. - -### Explore repositories - -You can find public repositories and images from Docker Hub in two ways. -You can "Search" from the Docker Hub website, or you can use the Docker command line tool to run the `docker search` command. For example if you were looking for an ubuntu image, you might run the following command line search: - -``` - $ docker search ubuntu -``` - -Both methods list the available public repositories on Docker Hub which match -the search term. - -Private repositories do not appear in the repository search results. To see all -the repositories you can access and their status, view your "Dashboard" page on -[Docker Hub](https://hub.docker.com). - - -You can find more information on working with Docker images in the [Docker userguide](https://docs.docker.com/userguide/dockerimages/). - -### Use Official Repositories - -Docker Hub contains a number of [Official -Repositories](http://hub.docker.com/explore/). These are public, certified -repositories from vendors and contributors to Docker. They contain Docker images -from vendors like Canonical, Oracle, and Red Hat that you can use as the basis -to building your applications and services. - -With Official Repositories you know you're using an optimized and -up-to-date image that was built by experts to power your applications. - -> **Note:** If you would like to contribute an Official Repository for your organization or product, see the documentation on [Official Repositories on Docker Hub](official_repos.md) for more information. - - -## Work with Docker Hub image repositories - -Docker Hub provides a place for you and your team to build and ship Docker images. - -You can configure Docker Hub repositories in two ways: - -* [Repositories](repos.md), which allow you to push images from a local Docker daemon to Docker Hub, and -* [Automated Builds](builds.md), which link to a source code repository and trigger an image rebuild process on Docker Hub when changes are detected in the source code. - -You can create public repositories which can be accessed by any other Hub user, or you can create private repositories with limited access you control. - -### Docker commands and Docker Hub - -Docker itself provides access to Docker Hub services via the [`docker search`](http://docs.docker.com/reference/commandline/search), -[`pull`](http://docs.docker.com/reference/commandline/pull), [`login`](http://docs.docker.com/reference/commandline/login), and [`push`](http://docs.docker.com/reference/commandline/push) commands. diff --git a/docs/menu.md b/docs/menu.md deleted file mode 100644 index 1a89dc09ae..0000000000 --- a/docs/menu.md +++ /dev/null @@ -1,14 +0,0 @@ - - -# Menu topic - -If you can view this content, please raise a bug report. diff --git a/docs/official_repos.md b/docs/official_repos.md deleted file mode 100644 index 56b5689a7f..0000000000 --- a/docs/official_repos.md +++ /dev/null @@ -1,125 +0,0 @@ -+++ -title = "Official Repositories on Docker Hub" -description = "Guidelines for Official Repositories on Docker Hub" -keywords = ["Docker, docker, registry, accounts, plans, Dockerfile, Docker Hub, docs, official, image, documentation"] -[menu.main] -parent="mn_pubhub" -weight=15 -+++ - -# Official Repositories on Docker Hub - -The Docker [Official Repositories](https://hub.docker.com/official/) are a -curated set of Docker repositories that are promoted on Docker Hub. They are designed to: - -* Provide essential base OS repositories (for example, - [ubuntu](https://hub.docker.com/_/ubuntu/), - [centos](https://hub.docker.com/_/centos/)) that serve as the - starting point for the majority of users. - -* Provide drop-in solutions for popular programming language runtimes, data - stores, and other services, similar to what a Platform-as-a-Service (PAAS) - would offer. - -* Exemplify [`Dockerfile` best practices](https://docs.docker.com/articles/dockerfile_best-practices) - and provide clear documentation to serve as a reference for other `Dockerfile` - authors. - -* Ensure that security updates are applied in a timely manner. This is - particularly important as many Official Repositories are some of the most - popular on Docker Hub. - -* Provide a channel for software vendors to redistribute up-to-date and - supported versions of their products. Organization accounts on Docker Hub can - also serve this purpose, without the careful review or restrictions on what - can be published. - -Docker, Inc. sponsors a dedicated team that is responsible for reviewing and -publishing all Official Repositories content. This team works in collaboration -with upstream software maintainers, security experts, and the broader Docker -community. - -While it is preferrable to have upstream software authors maintaining their -corresponding Official Repositories, this is not a strict requirement. Creating -and maintaining images for Official Repositories is a public process. It takes -place openly on GitHub where participation is encouraged. Anyone can provide -feedback, contribute code, suggest process changes, or even propose a new -Official Repository. - -## Should I use Official Repositories? - -New Docker users are encouraged to use the Official Repositories in their -projects. These repositories have clear documentation, promote best practices, -and are designed for the most common use cases. Advanced users are encouraged to -review the Official Repositories as part of their `Dockerfile` learning process. - -A common rationale for diverging from Official Repositories is to optimize for -image size. For instance, many of the programming language stack images contain -a complete build toolchain to support installation of modules that depend on -optimized code. An advanced user could build a custom image with just the -necessary pre-compiled libraries to save space. - -A number of language stacks such as -[python](https://hub.docker.com/_/python/) and -[ruby](https://hub.docker.com/_/ruby/) have `-slim` tag variants -designed to fill the need for optimization. Even when these "slim" variants are -insufficient, it is still recommended to inherit from an Official Repository -base OS image to leverage the ongoing maintenance work, rather than duplicating -these efforts. - -## How do I know the Official Repositories are secure? - -Docker provides a preview version of Docker Cloud's [Security Scanning service](http://docs.docker.com/docker-cloud/builds/image-scan/) for all of the -Official Repositories located on Docker Hub. These security scan results provide -valuable information about which images contain security vulnerabilities, which -you should use to help you choose secure components for your own projects. - -To view the Docker Security Scanning results: - -1. Make sure you're logged in to Docker Hub. - You can view Official Images even while logged out, however the scan results are only available once you log in. -2. Navigate to the official repository whose security scan you want to view. -3. Click the `Tags` tab to see a list of tags and their security scan summaries. - ![](images/scan-drilldown.gif) - -You can click into a tag's detail page to see more information about which -layers in the image and which components within the layer are vulnerable. -Details including a link to the official CVE report for the vulnerability appear -when you click an individual vulnerable component. - -## How can I get involved? - -All Official Repositories contain a **User Feedback** section in their -documentation which covers the details for that specific repository. In most -cases, the GitHub repository which contains the Dockerfiles for an Official -Repository also has an active issue tracker. General feedback and support -questions should be directed to `#docker-library` on Freenode IRC. - -## How do I create a new Official Repository? - -From a high level, an Official Repository starts out as a proposal in the form -of a set of GitHub pull requests. You'll find detailed and objective proposal -requirements in the following GitHub repositories: - -* [docker-library/official-images](https://github.com/docker-library/official-images) - -* [docker-library/docs](https://github.com/docker-library/docs) - -The Official Repositories team, with help from community contributors, formally -review each proposal and provide feedback to the author. This initial review -process may require a bit of back and forth before the proposal is accepted. - -There are also subjective considerations during the review process. These -subjective concerns boil down to the basic question: "is this image generally -useful?" For example, the [python](https://hub.docker.com/_/python/) -Official Repository is "generally useful" to the large Python developer -community, whereas an obscure text adventure game written in Python last week is -not. - -Once a new proposal is accepted, the author is responsibile for keeping -their images up-to-date and responding to user feedback. The Official -Repositories team becomes responsibile for publishing the images and -documentation on Docker Hub. Updates to the Official Repository follow the same -pull request process, though with less review. The Official Repositories team -ultimately acts as a gatekeeper for all changes, which helps mitigate the risk -of quality and security issues from being introduced. diff --git a/docs/orgs.md b/docs/orgs.md deleted file mode 100644 index d14f5a1dce..0000000000 --- a/docs/orgs.md +++ /dev/null @@ -1,53 +0,0 @@ -+++ -title = "Teams & Organizations" -description = "Docker Hub Teams and Organizations" -keywords = ["Docker, docker, registry, teams, organizations, plans, Dockerfile, Docker Hub, docs, documentation"] -[menu.main] -parent="mn_pubhub" -weight=-80 -+++ - -# Organizations and teams - -Docker Hub [organizations](https://hub.docker.com/organizations/) let you -create teams so you can give colleagues access to shared image repositories. -A Docker Hub organization can contain public and private repositories just like -a user account. -Access to push or pull for these repositories is allocated by defining teams of users and then assigning team rights to specific repositories. Repository -creation is limited to users in the organization owner's group. This allows you -to distribute limited access Docker images, and to select which Docker Hub users -can publish new images. - -### Creating and viewing organizations - -You can see which organizations you belong to and add new organizations by clicking "Organizations" in the top nav bar. - -![organizations](images/orgs.png) - -### Organization teams - -Users in the "Owners" team of an organization can create and modify the -membership of all teams. - -Other users can only see teams they belong to. - -![teams](images/groups.png) - -### Repository team permissions - -Use teams to manage who can interact with your repositories. - -You need to be a member of the organization's "Owners" team to create a new team, -Hub repository, or automated build. As an "Owner", you then delegate the following -repository access rights to a team using the "Collaborators" section of the repository view: - -- `Read` access allows a user to view, search, and pull a private repository in the same way as they can a public repository. -- `Write` access users are able to push to non-automated repositories on the Docker Hub. -- `Admin` access allows the user to modify the repositories "Description", "Collaborators" rights, - "Public/Private" visibility and "Delete". - -> **Note**: A User who has not yet verified their email address will only have -> `Read` access to the repository, regardless of the rights their team -> membership has given them. - -![Organization repository collaborators](images/org-repo-collaborators.png) diff --git a/docs/repos.md b/docs/repos.md deleted file mode 100644 index 7f47b83cf1..0000000000 --- a/docs/repos.md +++ /dev/null @@ -1,270 +0,0 @@ -+++ -title = "Repositories on Docker Hub" -description = "Your Repositories on Docker Hub" -keywords = ["Docker, docker, trusted, registry, accounts, plans, Dockerfile, Docker Hub, webhooks, docs, documentation"] -[menu.main] -parent="mn_pubhub" -weight=5 -+++ - -# Your Hub repositories - -Docker Hub repositories let you share images with co-workers, -customers, or the Docker community at large. If you're building your images internally, -either on your own Docker daemon, or using your own Continuous integration services, -you can push them to a Docker Hub repository that you add to your Docker Hub user or -organization account. - -Alternatively, if the source code for your Docker image is on GitHub or Bitbucket, -you can use an "Automated build" repository, which is built by the Docker Hub -services. See the [automated builds documentation](builds.md) to read about -the extra functionality provided by those services. - -![repositories](images/repos.png) - -## Searching for images - -You can search the [Docker Hub](https://hub.docker.com) registry via its search -interface or by using the command line interface. Searching can find images by image -name, user name, or description: - - $ docker search centos - NAME DESCRIPTION STARS OFFICIAL AUTOMATED - centos The official build of CentOS. 1034 [OK] - ansible/centos7-ansible Ansible on Centos7 43 [OK] - tutum/centos Centos image with SSH access. For the root... 13 [OK] - ... - -There you can see two example results: `centos` and `ansible/centos7-ansible`. The second -result shows that it comes from the public repository of a user, named -`ansible/`, while the first result, `centos`, doesn't explicitly list a -repository which means that it comes from the top-level namespace for -[Official Repositories](official_repos.md). The `/` character separates -a user's repository from the image name. - -Once you've found the image you want, you can download it with `docker pull `: - - $ docker pull centos - latest: Pulling from centos - 6941bfcbbfca: Pull complete - 41459f052977: Pull complete - fd44297e2ddb: Already exists - centos:latest: The image you are pulling has been verified. Important: image verification is a tech preview feature and should not be relied on to provide security. - Digest: sha256:d601d3b928eb2954653c59e65862aabb31edefa868bd5148a41fa45004c12288 - Status: Downloaded newer image for centos:latest - -You now have an image from which you can run containers. - -## Viewing repository tags - -Docker Hub's repository "Tags" view shows you the available tags and the size -of the associated image. - -Image sizes are the cumulative space taken up by the image and all -its parent images. This is also the disk space used by the contents of the -Tar file created when you `docker save` an image. - -![images/busybox-image-tags.png](images/busybox-image-tags.png) - -## Creating a new repository on Docker Hub - -When you first create a Docker Hub user, you will have a "Get started with Docker Hub." -screen, from which you can click directly into "Create Repository". -You can also use the "Create ▼" menu to "Create Repository". - -When creating a new repository, you can choose to put it in your Docker ID namespace, or that of any [organization](orgs.md) that you -are in the "Owners" team. -The Repository Name will need to be unique in that namespace, can be two to 255 characters, -and can only contain lowercase letters, numbers or `-` and `_`. - -The "Short Description" of 100 characters will be used in the search results, while the -"Full Description" can be used as the Readme for the repository, and can use Markdown to -add simple formatting. - -After you hit the "Create" button, you then need to `docker push` images to that Hub based -repository. - - - -## Pushing a repository image to Docker Hub - -In order to push a repository to the Docker Hub, you need to -name your local image using your Docker Hub username, and the -repository name that you created in the previous step. -You can add multiple images to a repository, by adding a specific `:` to -it (for example `docs/base:testing`). If its not specified, the tag defaults to -`latest`. -You can name your local images either when you build it, using -`docker build -t /[:]`, -by re-tagging an existing local image `docker tag /[:]`, -or by using `docker commit /[:]` to commit -changes. -See [Working with Docker images](https://docs.docker.com/userguide/dockerimages) for a detailed description. - -Now you can push this repository to the registry designated by its name or tag. - - $ docker push /: - -The image will then be uploaded and available for use by your team-mates and/or the -community. - - -## Stars - -Your repositories can be starred and you can star repositories in -return. Stars are a way to show that you like a repository. They are -also an easy way of bookmarking your favorites. - -## Comments - -You can interact with other members of the Docker community and maintainers by -leaving comments on repositories. If you find any comments that are not -appropriate, you can flag them for review. - -## Collaborators and their role - -A collaborator is someone you want to give access to a private -repository. Once designated, they can `push` and `pull` to your -repositories. They will not be allowed to perform any administrative -tasks such as deleting the repository or changing its status from -private to public. - -> **Note:** -> A collaborator cannot add other collaborators. Only the owner of -> the repository has administrative access. - -You can also assign more granular collaborator rights ("Read", "Write", or "Admin") -on Docker Hub by using organizations and teams. For more information -see the [organizations documentation](orgs.md). - -## Private repositories - -Private repositories allow you to have repositories that contain images -that you want to keep private, either to your own account or within an -organization or team. - -To work with a private repository on [Docker -Hub](https://hub.docker.com), you will need to add one via the [Add -Repository](https://hub.docker.com/add/repository/) -button. You get one private repository for free with your Docker Hub -user account (not usable for organizations you're a member of). If -you need more accounts you can upgrade your [Docker -Hub](https://hub.docker.com/account/billing-plans/) plan. - -Once the private repository is created, you can `push` and `pull` images -to and from it using Docker. - -> *Note:* You need to be signed in and have access to work with a -> private repository. - -Private repositories are just like public ones. However, it isn't -possible to browse them or search their content on the public registry. -They do not get cached the same way as a public repository either. - -It is possible to give access to a private repository to those whom you -designate (i.e., collaborators) from its "Settings" page. From there, you -can also switch repository status (*public* to *private*, or -vice-versa). You will need to have an available private repository slot -open before you can do such a switch. If you don't have any available, -you can always upgrade your [Docker -Hub](https://hub.docker.com/account/billing-plans/) plan. - -## Webhooks - -A webhook is an HTTP call-back triggered by a specific event. -You can use a Hub repository webhook to notify people, services, and other -applications after a new image is pushed to your repository (this also happens -for Automated builds). For example, you can trigger an automated test or -deployment to happen as soon as the image is available. - -To get started adding webhooks, go to the desired repository in the Hub, -and click "Webhooks" under the "Settings" box. -A webhook is called only after a successful `push` is -made. The webhook calls are HTTP POST requests with a JSON payload -similar to the example shown below. - -*Example webhook JSON payload:* - -```json -{ - "callback_url": "https://registry.hub.docker.com/u/svendowideit/busybox/hook/2141bc0cdec4hebec411i4c1g40242eg110020/", - "push_data": { - "images": [ - "27d47432a69bca5f2700e4dff7de0388ed65f9d3fb1ec645e2bc24c223dc1cc3", - "51a9c7c1f8bb2fa19bcd09789a34e63f35abb80044bc10196e304f6634cc582c", - "..." - ], - "pushed_at": 1.417566822e+09, - "pusher": "svendowideit" - }, - "repository": { - "comment_count": 0, - "date_created": 1.417566665e+09, - "description": "", - "full_description": "webhook triggered from a 'docker push'", - "is_official": false, - "is_private": false, - "is_trusted": false, - "name": "busybox", - "namespace": "svendowideit", - "owner": "svendowideit", - "repo_name": "svendowideit/busybox", - "repo_url": "https://registry.hub.docker.com/u/svendowideit/busybox/", - "star_count": 0, - "status": "Active" - } -} -``` - - - ->**Note:** If you want to test your webhook, we recommend using a tool like ->[requestb.in](http://requestb.in/). Also note, the Docker Hub server can't be ->filtered by IP address. - -### Webhook chains - -Webhook chains allow you to chain calls to multiple services. For example, -you can use this to trigger a deployment of your container only after -it has been successfully tested, then update a separate Changelog once the -deployment is complete. -After clicking the "Add webhook" button, simply add as many URLs as necessary -in your chain. - -The first webhook in a chain will be called after a successful push. Subsequent -URLs will be contacted after the callback has been validated. - -### Validating a callback - -In order to validate a callback in a webhook chain, you need to - -1. Retrieve the `callback_url` value in the request's JSON payload. -1. Send a POST request to this URL containing a valid JSON body. - -> **Note**: A chain request will only be considered complete once the last -> callback has been validated. - -To help you debug or simply view the results of your webhook(s), -view the "History" of the webhook available on its settings page. - -#### Callback JSON data - -The following parameters are recognized in callback data: - -* `state` (required): Accepted values are `success`, `failure` and `error`. - If the state isn't `success`, the webhook chain will be interrupted. -* `description`: A string containing miscellaneous information that will be - available on the Docker Hub. Maximum 255 characters. -* `context`: A string containing the context of the operation. Can be retrieved - from the Docker Hub. Maximum 100 characters. -* `target_url`: The URL where the results of the operation can be found. Can be - retrieved on the Docker Hub. - -*Example callback payload:* - - { - "state": "success", - "description": "387 tests PASSED", - "context": "Continuous integration by Acme CI", - "target_url": "http://ci.acme.com/results/afd339c1c3d27" - } diff --git a/docs/s3_website.json b/docs/s3_website.json deleted file mode 100644 index 96eea7318e..0000000000 --- a/docs/s3_website.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "ErrorDocument": { - "Key": "jsearch/index.html" - }, - "IndexDocument": { - "Suffix": "index.html" - } -} diff --git a/docs/webhooks.md b/docs/webhooks.md deleted file mode 100644 index a50206e3f6..0000000000 --- a/docs/webhooks.md +++ /dev/null @@ -1,50 +0,0 @@ -+++ -title = "Webhooks for automated builds" -description = "Docker Hub Automated Builds" -keywords = ["Docker, webhookds, hub, builds"] -[menu.main] -parent="mn_pubhub" -weight=7 -+++ - -# Webhooks for automated builds - -If you have an automated build repository in Docker Hub, you can use Webhooks to cause an action in another application in response to an event in the repository. Docker Hub webhooks fire when an image is built in, or a new tag added to, your automated build repository. - -With your webhook, you specify a target URL and a JSON payload to deliver. The example webhook below generates an HTTP POST that delivers a JSON payload: - -```json -{ - "callback_url": "https://registry.hub.docker.com/u/svendowideit/testhook/hook/2141b5bi5i5b02bec211i4eeih0242eg11000a/", - "push_data": { - "images": [ - "27d47432a69bca5f2700e4dff7de0388ed65f9d3fb1ec645e2bc24c223dc1cc3", - "51a9c7c1f8bb2fa19bcd09789a34e63f35abb80044bc10196e304f6634cc582c", - "..." - ], - "pushed_at": 1.417566161e+09, - "pusher": "trustedbuilder" - }, - "repository": { - "comment_count": "0", - "date_created": 1.417494799e+09, - "description": "", - "dockerfile": "#\n# BUILD\u0009\u0009docker build -t svendowideit/apt-cacher .\n# RUN\u0009\u0009docker run -d -p 3142:3142 -name apt-cacher-run apt-cacher\n#\n# and then you can run containers with:\n# \u0009\u0009docker run -t -i -rm -e http_proxy http://192.168.1.2:3142/ debian bash\n#\nFROM\u0009\u0009ubuntu\nMAINTAINER\u0009SvenDowideit@home.org.au\n\n\nVOLUME\u0009\u0009[\/var/cache/apt-cacher-ng\]\nRUN\u0009\u0009apt-get update ; apt-get install -yq apt-cacher-ng\n\nEXPOSE \u0009\u00093142\nCMD\u0009\u0009chmod 777 /var/cache/apt-cacher-ng ; /etc/init.d/apt-cacher-ng start ; tail -f /var/log/apt-cacher-ng/*\n, - full_description: Docker Hub based automated build from a GitHub repo", - "is_official": false, - "is_private": true, - "is_trusted": true, - "name": "testhook", - "namespace": "svendowideit", - "owner": "svendowideit", - "repo_name": "svendowideit/testhook", - "repo_url": "https://registry.hub.docker.com/u/svendowideit/testhook/", - "star_count": 0, - "status": "Active" - } -} -``` - ->**Note:** If you want to test your webhook, we recommend using a tool like ->[requestb.in](http://requestb.in/). Also note, the Docker Hub server can't be ->filtered by IP address. diff --git a/fabfile.py b/fabfile.py deleted file mode 100644 index 80d2a1aedc..0000000000 --- a/fabfile.py +++ /dev/null @@ -1,14 +0,0 @@ -from fabric.api import run - -def start_project(email="none", user="none", auth="none", beta_password="maybejustnotsomeemptyspaceyea?", sha="latest", new_relic_key="", new_relic_app_name="hub-stage-node"): - run('docker rm $(docker ps -a -q) > /dev/null 2>&1 || :') - run('docker rmi $(docker images -q) > /dev/null 2>&1 || :') - run('cd /home/') - run('docker login -e %s -u %s -p %s' % (email, user, auth)) - run('docker pull bagel/hub-prod:%s' % sha) - run('docker pull bagel/haproxy_beta:latest') - run("docker ps | awk '{if($1 != \"CONTAINER\"){print $1}}' | xargs -r docker kill") - # We should tag the image with the git commit and deploy that instead of "latest" - run('docker run -dp 7001:3000 -e ENV=production --restart=on-failure:5 -e HUB_API_BASE_URL=https://hub-beta-stage.docker.com -e REGISTRY_API_BASE_URL=https://hub-beta-stage.docker.com -e NEW_RELIC_LICENSE_KEY=%s -e NEW_RELIC_APP_NAME=%s bagel/hub-prod:%s' % (new_relic_key, new_relic_app_name, sha)) - # HAProxy doesn't change a lot. We should check the image names before killing/rebooting - run('docker run -dp 80:80 -p 443:443 -e BETA_PASSWORD=%s --restart=on-failure:5 -v /opt/haproxy.pem:/haproxy/keys/hub-beta.docker.com/hub-beta.docker.pem bagel/haproxy_beta:latest' % beta_password) diff --git a/flow-libs/async.js b/flow-libs/async.js deleted file mode 100644 index 2d9f0cccef..0000000000 --- a/flow-libs/async.js +++ /dev/null @@ -1,12 +0,0 @@ -type AsyncCallback = (err: ?Object, results: ?any) => void; -type ParallelFuncs = (callback: AsyncCallback) => void; - -declare module 'async' { - declare function parallel(tasks: Array | Object, - callback: AsyncCallback): void - declare function series(tasks: Array, - callback: AsyncCallback): void - declare function each(arr: Array, - func: Function, - callback: Function): void -} \ No newline at end of file diff --git a/flow-libs/debug.js b/flow-libs/debug.js deleted file mode 100644 index 4807c40f8a..0000000000 --- a/flow-libs/debug.js +++ /dev/null @@ -1,5 +0,0 @@ -type DebugFunction = (thing: any) => void; - -declare module 'debug' { - declare function exports(string: string): DebugFunction; -} \ No newline at end of file diff --git a/flow-libs/fluxible.js b/flow-libs/fluxible.js deleted file mode 100644 index 3ad2f4e95f..0000000000 --- a/flow-libs/fluxible.js +++ /dev/null @@ -1,4 +0,0 @@ -export type FluxibleActionContext = { - dispatch(eventName: string, - payload: any): void; -} diff --git a/flow-libs/hub-js-sdk.js b/flow-libs/hub-js-sdk.js deleted file mode 100644 index 79da45ff99..0000000000 --- a/flow-libs/hub-js-sdk.js +++ /dev/null @@ -1,74 +0,0 @@ -type SuperAgentCallback = (err: any, - res: any) => void; - -type JWT = String; -type ChangePasswordData = { - username: String; - oldpassword: String; - newpassword: String -} - -declare module 'hub-js-sdk' { - declare var Auth: { - getToken(username: string, - password: string, - cb: SuperAgentCallback): void; - } - declare var Repositories: { - createRepository(jwt: JWT, - repository: any, - cb: SuperAgentCallback): void; - getReposForUser(jwt: JWT, - username: String, - cb: SuperAgentCallback): void - } - declare var Emails: { - getEmailSubscriptions(JWT: JWT, - user: String, - cb: SuperAgentCallback): void; - unsubscribeEmails(JWT: JWT, - user: String, - data: Object, - cb: SuperAgentCallback): void; - subscribeEmails(JWT:JWT, - user: String, - data: Object, - cb: SuperAgentCallback): void; - getEmailsJWT(JWT:JWT, - cb:SuperAgentCallback): void; - getEmailsForUser(JWT: JWT, - user: String, - cb: SuperAgentCallback): void; - deleteEmailByID(JWT: JWT, - id: String, - cb: SuperAgentCallback): void; - updateEmailByID(JWT: JWT, - id: String, - data: Object, - cb: SuperAgentCallback): void; - addEmailsForUser(JWT: JWT, - user: Object, - email: string, - cb: SuperAgentCallback): void; - } -} - -declare module 'hub-js-sdk/src/Hub/SDK/Users' { - declare function changePassword(JWT: JWT, - data: ChangePasswordData, - cb: SuperAgentCallback): void; - declare function getUser(JWT: JWT, - user: String, - cb: SuperAgentCallback): void; -} - -declare module 'hub-js-sdk/src/Hub/SDK/Auth' { - declare function getToken(username: String, - password: String, - cb: SuperAgentCallback): void; -} - -declare module 'hub-js-sdk/src/Hub/SDK/Notifications' { - declare function getActivityFeed(JWT: JWT, - cb: SuperAgentCallback): void; -} diff --git a/flow-libs/lodash.js b/flow-libs/lodash.js deleted file mode 100644 index a047b9e1b5..0000000000 --- a/flow-libs/lodash.js +++ /dev/null @@ -1,5 +0,0 @@ -declare module 'lodash' { - declare function sortByOrder(arr: Array, - properties: Array, - sortOrder: Array): Array; -} \ No newline at end of file diff --git a/gulp-tasks/img.js b/gulp-tasks/img.js deleted file mode 100644 index 524d9a86f6..0000000000 --- a/gulp-tasks/img.js +++ /dev/null @@ -1,24 +0,0 @@ -var gulp = require('gulp'); -var imagemin = require('gulp-imagemin'); -var pngquant = require('imagemin-pngquant'); - -//Hub2 Images for dev & production (There is a separate task for docker-ux images) -gulp.task('images::dev', function () { - return gulp.src('app/img/**') - .pipe(imagemin({ - progressive: true, - svgoPlugins: [{removeViewBox: false}], - use: [pngquant({ quality: '65-80', speed: 4 })] - })) - .pipe(gulp.dest('app/.build/public/img')); -}); - -gulp.task('images::prod', function() { - return gulp.src('app/img/**') - .pipe(imagemin({ - progressive: true, - svgoPlugins: [{removeViewBox: false}], - use: [pngquant({ quality: '65-80', speed: 4 })] - })) - .pipe(gulp.dest('.tmp/server/build/img')); -}); diff --git a/gulpfile.js b/gulpfile.js deleted file mode 100644 index 05734a32b9..0000000000 --- a/gulpfile.js +++ /dev/null @@ -1,3 +0,0 @@ -'use strict'; -require('./gulp-tasks/img'); - diff --git a/local.Dockerfile b/local.Dockerfile deleted file mode 100644 index 34163d2fd2..0000000000 --- a/local.Dockerfile +++ /dev/null @@ -1,22 +0,0 @@ -FROM bagel/universe:337f873f4f23f4b2603972229ae3519c5f61f6d7 - -ENV ENV local -ENV NODE_ENV local - -COPY ./app /opt/hub/app -COPY ./Makefile /opt/hub/Makefile -COPY ./_webpack /opt/hub/_webpack -COPY ./gulpfile.js /opt/hub/gulpfile.js -COPY ./gulp-tasks /opt/hub/gulp-tasks -COPY ./app-server /opt/hub/app-server -COPY ./.eslintrc /opt/hub/.eslintrc - -RUN make server-prod-target -RUN make server-extras -RUN make js-local -RUN make images-prod -RUN make docker-font-prod -RUN gulp images::prod -RUN make styles-base-prod -RUN make stats-dir -RUN make css-stats diff --git a/package.json b/package.json deleted file mode 100644 index fe9abf952a..0000000000 --- a/package.json +++ /dev/null @@ -1,114 +0,0 @@ -{ - "name": "docker-2.0", - "version": "0.0.1", - "private": true, - "scripts": { - "test": "jest", - "build:dev": "DEBUG=* webpack -dw" - }, - "jest": { - "rootDir": "./app/scripts", - "scriptPreprocessor": "../../node_modules/babel-jest", - "testFileExtensions": [ - "js" - ], - "moduleFileExtensions": [ - "jsx", - "js", - "json" - ], - "modulePathIgnorePatterns": [ - "/node_modules/" - ], - "unmockedModulePathPatterns": [ - "react" - ] - }, - "dependencies": { - "@dux/element-button": "0.0.3", - "@dux/element-card": "0.0.7", - "@dux/element-markdown": "0.0.8", - "@dux/hub-sdk": "^0.1.1", - "async": "^1.3.0", - "babel": "^5.6.14", - "babel-core": "^5.6.14", - "babel-runtime": "^5.6.18", - "body-parser": "^1.12.2", - "bugsnag": "^1.7.0", - "classnames": "^2.1.2", - "cookie": "^0.2.3", - "cookie-parser": "^1.3.4", - "csurf": "^1.8.0", - "debug": "^2.1.3", - "dux": "file:./private-deps/docker-ux", - "express": "^4.12.3", - "express-state": "^1.2.0", - "fluxible": "^1.0.3", - "fluxible-addons-react": "^0.2.0", - "highlight.js": "^9.0.0", - "history": "^1.17.0", - "hub-js-sdk": "file:./private-deps/hub-js-sdk", - "immutable": "^3.7.6", - "keymirror": "^0.1.1", - "lodash": "^3.6.0", - "marked": "^0.3.3", - "md5": "^2.0.0", - "moment": "^2.10.3", - "newrelic": "christopherbiscardi/node-newrelic#c4ccca3764acafaf9c5899e4a1abece828e1f7b8", - "normalizr": "^1.4.0", - "numeral": "^1.5.3", - "rc-tooltip": "^3.3.0", - "react": "^0.14.7", - "react-document-title": "^2.0.2", - "react-dom": "^0.14.3", - "react-router": "^1.0.0", - "react-select": "^1.0.0-beta6", - "recurly-js": "git://github.com/recurly/recurly-js#d9740eb3ee416fb999635daecfb524a492dbb058", - "redux": "^3.0.5", - "redux-logger": "^2.3.2", - "redux-ui": "0.0.8", - "remarkable": "^1.6.0", - "reselect": "^2.0.1", - "serialize-javascript": "^1.0.0", - "serve-favicon": "^2.2.0", - "superagent": "^1.1.0", - "svg-inline-react": "^0.3.1", - "velocity-animate": "^1.2.3", - "velocity-react": "1.1.3" - }, - "devDependencies": { - "babel-eslint": "^4.0.0", - "babel-jest": "^5.0.1", - "babel-loader": "^5.0.0", - "css-loader": "^0.23.0", - "cssnano": "^3.2.0", - "cssstats": "^1.10.0", - "eslint": "^1.2.1", - "eslint-loader": "^1.0.0", - "extract-text-webpack-plugin": "^0.9.1", - "gulp": "^3.8.11", - "gulp-imagemin": "^2.2.1", - "imagemin-pngquant": "^4.0.0", - "json-loader": "^0.5.2", - "lost": "^6.6.2", - "nodemon": "^1.3.7", - "postcss-browser-reporter": "^0.4.0", - "postcss-constants": "^0.1.1", - "postcss-cssnext": "^2.1.0", - "postcss-cssstats": "^1.0.0", - "postcss-each": "^0.7.0", - "postcss-import": "^7.0.0", - "postcss-loader": "^0.8.0", - "postcss-nested": "^1.0.0", - "postcss-url": "^5.0.1", - "react-redux": "^4.0.3", - "redux": "^3.0.5", - "reselect": "^2.0.1", - "style-loader": "^0.13.0", - "svg-inline-loader": "^0.4.0", - "webpack": "^1.10" - }, - "engines": { - "node": ">=4.0.0" - } -} diff --git a/pr-docs/css.md b/pr-docs/css.md deleted file mode 100644 index f019c08e6c..0000000000 --- a/pr-docs/css.md +++ /dev/null @@ -1,62 +0,0 @@ -[Demo](https://css-modules.github.io/webpack-demo/) - -The approach is thus: Use Foundation as a "browser reset" stylesheet, -then put everything that isn't a foundation `_settings.scss` variable -in CSSModule sidecar files. This links our javascript modules with our -css and increases the ease with which we can create a module library. - -# Implementation - -## File Structure - -``` -app/scripts/ -|-- ScopedSelectors.js -|-- ScopedSelectors.css -``` - -## Usage - -```javascript -import styles from './ScopedSelectors.css'; - -import React, { Component } from 'react'; - -export default class ScopedSelectors extends Component { - - render() { - return ( -
                                    -

                                    Scoped Selectors

                                    -
                                    - ); - } - -}; -``` - -```css -.root { - border-width: 2px; - border-style: solid; - border-color: #777; - padding: 0 20px; - margin: 0 6px; - max-width: 400px; -} - -.text { - color: #777; - font-size: 24px; - font-family: helvetica, arial, sans-serif; - font-weight: 600; -} -``` - -# Approach - -* modules should be scoped to themselves and not affect children or - siblings. -* Webpack already has support for css-modules in it's `css-loader`. So - we'll start with that. -* [css-modules and preprocessors (sass)](https://github.com/css-modules/css-modules#usage-with-preprocessors) diff --git a/pr-docs/linting.md b/pr-docs/linting.md deleted file mode 100644 index e66ad8c472..0000000000 --- a/pr-docs/linting.md +++ /dev/null @@ -1,28 +0,0 @@ -# Linting - -All code must pass [ESLint][eslint] before being merged into master -branch. The ESLint config can be found in `.eslintrc` and is -integrated into webpack. - -# Running ESLint - -``` -gulp webpack -``` - -Since linting is integrated with webpack, it is possible to lint code -while it is being developed without any extra effort. This is -important because if it is not approximate to effortless to run -linting, it will not be run while developing. - -# We should block deploys for linting errors - -Since we do CI/CD, the static analysis present in ESLint can help us -catch bugs before shipping. We should therefore block deploys if -ESLint detects an error-level (level `2` in `.eslintrc`) issue. - -* [eslint][eslint] -* [babel-eslint][babel-eslint] - -[eslint]: http://eslint.org/ -[babel-eslint]: https://github.com/babel/babel-eslint diff --git a/pr-docs/routes.md b/pr-docs/routes.md deleted file mode 100644 index 99876f2e52..0000000000 --- a/pr-docs/routes.md +++ /dev/null @@ -1,262 +0,0 @@ -# Routes - -Two items affect this proposal. - -1. [Distribution's work](https://github.com/docker/distribution), - specifically relating to defining Repositories, Images, Manifests, - Digests and Tags. -2. The Current Hub's Routing Issues - -## Distributions Work (partially summarized) - -### Repository - -* A set of blobs -* Subsets of these blobs make up Images - -### Image - -* A set of blobs - - Layers - - Tag - - Signatures - - Manifest -* A Tag (potentially containing signatures) points to a Manifest -* A Manifest points to multiple layers. - -### Manifest - -As defined in the [distribution][manifest-pr] Manifest PR: - -> A [Content Manifest][manifest] is a simple JSON file which contains -> general fields that are typical to any package management -> system. The goal is for these manifests to describe an application -> and its dependencies in a content-addressable and verifiable way. - -### Tag - -As defined in the [distribution][d-tag-pr] PR: - -> A [tag][tag] is simply a named pointer to content. The content can -> be any blob but should mostly be a manifest. One can sign tags to -> later verify that they were created by a trusted party. - -### Additional Content - -Image names will be allowed to have many slashes in the future. - -## Current Hub Issues - -### Collisions - -The URLs for user and repo collide: - -A user's Starred Repos: - -``` -/u/biscarch/starred/ -``` - -A user's repository, named Starred. - -``` -/u/biscarch/starred/ -``` - -## Future Problems - -An image for the user `biscarch`, named `my/repo`: - -``` -/u/biscarch/my/repo/ -``` - -An image for the user `biscarch`, named `my`, tagged `repo`: - -``` -/u/biscarch/my/repo/ -``` - -## Solutions - -Namespace `Users`, `Repos` and `Images` as such (with the user -`biscarch`) - -``` -/u/:user -/r/:user/:repo -/i/:user/:repo/:tag -``` - -### Solving Starred Repos - -Prefix defines whether we are referring to a repo or attribute of a -user: - -``` -/u/biscarch/starred -/r/biscarch/starred -``` - -### Solving Repo/Image Conflicts - -Prefix determines whether we are referring to a Repository or Image: - -``` -/r/biscarch/my/repo/ -/i/biscarch/my/repo/ -``` - -## The new Spec - -``` -/u/ -/u/:user/ -/r/:user/:repo/ -/i/:user/:repo/:tag/ -``` - -### Full List - -### Dashboard - -`/` - -### Official Repositories - -"username" === library, which is represented as the root `_`. -All management of `library` namespaced repos is done from the usual -`/u/library/:repo/` - -``` -/_/:repo/ -/_/:repo/dockerfile/ -/_/:repo/dockerfile/raw -/_/:repo/tags/ -``` - -### Single Endpoints - -* Search - - `/search/` -* Plans - - `/plans/` - -### Account - -Mostly Settings; Add Repository Page; - -`/account/` should redirect to `/account/settings/` - -``` -/account/accounts/ -/account/authorized_services/ -/account/change-password/ -/account/confirm-email// -/account/emails/ -/account/notifications/ -/account/organizations/ -/account/organizations/:org_name/ -/account/organizations/:org_name/groups/:group_id/ -/account/repositories/add/ -/account/settings/ -/account/subscriptions/ -``` - -### Users - -``` -/u/ -/u/:user/ -/u/:user/activity/ -/u/:user/contributed/ -/u/:user/starred/ -``` - -### Repos - -``` -/r/:user/:repo/ -/r/:user/:repo/~/settings/ -/r/:user/:repo/~/settings/collaborators/ -/r/:user/:repo/~/settings/links/ -/r/:user/:repo/~/settings/triggers/ -/r/:user/:repo/~/settings/webhooks/ -/r/:user/:repo/~/settings/tags/ -``` - -Current build history urls: - -``` -/r/:user/:repo/~/builds_history/ -``` - -### Images - -We currently don't do a lot for Images. Repositories have been the -main focus. - -``` -/i/:user/:repo/:tag/ -/i/:user/:repo/:tag/~/dockerfile/ -/i/:user/:repo/:tag/~/dockerfile/raw/ -``` - -### Automated Builds - -``` -/automated-builds/ -/builds/ -/builds/:user/:repo/ -``` - -### Convenience Redirects - -Also, potential pages to build out more agressively. - -* `/official/` - - redirects to `/search?q=library&f=official` - - future: Potentially `Explore` type page for official repos -* `/most_stars/`, `/popular/` - - redirects to `search?q=library&s=stars` -* `/recent_updated/` - - `search?q=library&s=last_updated` - -#### Help - -* `/help` - - `https://www.docker.com/resources/help/` - - Can we rely on this url to stick around? -* `/help/docs` - - `https://docs.docker.com/` - -## Make Separate Sites for: - -### Highland URLs - -We need to pull out the APIs used on the current Hub for this. - -``` -/highland/ -/highland/build-configs/ -/highland/builds/ -/highland/search/ -/highland/stats/ -``` - - -## More Issues - -* There are no links to comments -* `/opensearch.xml` times out on the current site - - Should we re-implement? -* `/sitemap.xml` - -# Concerns with this Proposal - -* Automated Build urls need to be given more thought - -[tag]: https://github.com/stevvooe/distribution/blob/a8d3f3474b7b60576dc64250d95db3717bf07c33/doc/spec/tags.md#tags -[d-tag-pr]: https://github.com/docker/distribution/pull/173/files -[d-manifest-pr]: https://github.com/docker/distribution/pull/62 -[manifest]: https://github.com/jlhawn/distribution/blob/e8b5c8c32b565b9b643c3a0b0e87339bf40eb206/doc/spec/manifest.md diff --git a/production_ready.md b/production_ready.md deleted file mode 100644 index ee92e5a3b3..0000000000 --- a/production_ready.md +++ /dev/null @@ -1,93 +0,0 @@ -Production Readiness: Docker Hub Front-End (hub-web-v2) -================================ - -Testing -------- - - * **What is the max traffic load that your service has been tested with?** - Hub UI has not been load tested. - - * **How has the service been soak-tested?** - Hub UI has not been soak tested. - - Monitoring - ---------- - - * **How do you monitor?** - New Relic for server monitoring, BugSnag for JavaScript errors and PagerDuty for alerting. - - * **What’s the link(s) to the dashboard(s)?** - New Relic: https://rpm.newrelic.com/accounts/532547/applications/8853774 - BugSnag: https://bugsnag.com/docker/hub-prod/errors - PagerDuty: https://docker.pagerduty.com/services/PKZG21B - - * **Do you use an exception tracking service (e.g. Bugsnag, Sentry, New Relic)?** - Yes, BugSnag and New Relic. - - * **What’s the health check endpoint? And what checks does that endpoint perform?** - https://hub.docker.com/_health/ - - * **What external services do you depend on? How do you monitor them and handle failures?** - Hub API Gateway and all downstream Docker Cloud services. - Google Tag Manager (gtm.js) - Recurly (recurly.js) - - - - * **What’s the link to view the logs?** - - Alerting - -------- - - * **How do you know if your service is down?** - PagerDuty alerts - Prometheus alerts - - * **What are the metrics that you alert on?** - 500's from Front End containers - - * **Have you tested tripping on an alert to page somebody?** - Not manually tested. But production systems are paging properly. - - * **What’s the link to your on-call schedule?** - https://docker.pagerduty.com/schedules#P88XAI9 - - * **Where is your on-call run-book?** - https://docker.atlassian.net/wiki/display/DE/Hub+UI+Runbook - - Disaster - -------- - - * **What’s the plan if your persistence layer blows up?** - Front-end is stateless so this shouldn't be required, but restart Container if unsure. - - * **What’s the plan if any of your external service dependencies blows up?** - Hub API Gateway or downstream service - find service owner, escalate/alert through PagerDuty, contact service team via Slack. - Google Tag Manager - disable Google Tag Manager from https://tagmanager.google.com - single signon with docker.com account - Recurly problem - check status.recurly.com, escalate/alert Billing team through PagerDuty, contact service team via Slack. - Update status.io describing impact to UI if any. - - - Security - -------- - - * **Is the service exposed on the public internet? Does it require TLS?** - https://hub.docker.com/ - - * **How do you store production secrets?** - Front-End does not store secrets. JWT is stored in user's browser cookie. - - * **What is your authentication model (both user authentication and service-to-service authentication)?** - oauth - - * **Do you store any sensitive user data (emails, phone numbers, intellectual property)?** - JWT in cookie. - - Release process - --------------- - - * **What’s the link to your docs on how to do a release?** - https://docker.atlassian.net/wiki/display/DH/Hub+frontend+Deployment+Process - - * **How long does it take to release a code fix to production?** - 4-8 hours diff --git a/startup-scripts/boot-dev-tmux.sh b/startup-scripts/boot-dev-tmux.sh deleted file mode 100755 index 0907330ac3..0000000000 --- a/startup-scripts/boot-dev-tmux.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash - -set -e - -eval $(docker-machine env dev) - -############################################################### -# You must have `tmux` installed locally. On OSX, this can be # -# accomplished with `brew install tmux` # -############################################################### - -SESSION=HubDev -DIR=${PWD##*/}_hub_1 -CONTAINER=$(sed s/-//g <<< $DIR) - - -# Create new tmux session -tmux -2 new-session -d -s $SESSION - -# Window 1 - -## webpack task -tmux split-window -tmux select-pane -t 0 -tmux send-keys "DEBUG=* webpack -wd" C-m - -## styles - -tmux select-pane -t 1 -tmux send-keys "DEBUG=* gulp watch::styles::dev" C-m - -## Flow - -tmux split-window -h -tmux select-pane -t 2 -tmux send-keys "flow" C-m - -## docker logs - -tmux select-pane -t 0 -tmux split-window -h -tmux send-keys "docker-compose logs hub" C-m - -# Attach to session -tmux -2 attach-session -t $SESSION diff --git a/startup-scripts/boot-dev.sh b/startup-scripts/boot-dev.sh deleted file mode 100755 index 83b569ffe3..0000000000 --- a/startup-scripts/boot-dev.sh +++ /dev/null @@ -1,2 +0,0 @@ -DEBUG=* webpack -dw & -cd app/.build && nodemon ./server.js diff --git a/startup-scripts/bootstrap-dev.sh b/startup-scripts/bootstrap-dev.sh deleted file mode 100755 index 454c4620fa..0000000000 --- a/startup-scripts/bootstrap-dev.sh +++ /dev/null @@ -1,8 +0,0 @@ -# run this before the development container to bootstrap your local filesystem -npm install -cp app/favicon.ico app/.build/favicon.ico -make server-target -make styles-base -gulp images::dev -make images -make docker-font-dev diff --git a/webpack.config.js b/webpack.config.js deleted file mode 100644 index 9a5242e5ec..0000000000 --- a/webpack.config.js +++ /dev/null @@ -1,151 +0,0 @@ -const debug = require('debug')('webpack-debug'); -var ENV_CONFIG = require('./_webpack/_envConfig.js'); -var fs = require('fs'); -var path = require('path'); -var ExtractTextPlugin = require("extract-text-webpack-plugin"); -var _ = require('lodash'); -var webpack = require('webpack'); - -var loaders = require('./_webpack/_commonLoaders'); - -/** - * blacklist this array from being included in `externals`. - * - * This has the effect of making any modules in this list be - * resolved at build time instead of runtime. This affects the - * server bundle - */ -var blacklist = ['.bin', 'hub-js-sdk', 'dux']; -var node_modules = fs.readdirSync('node_modules').filter(function(x) { - return !_.includes(blacklist, x); -}); - -/* Dux Button Config */ -var elementButton = require('@dux/element-button/defaults'); -var buttons = elementButton.mkButtons([{ - name: 'primary', - color: '#FFF', - bg: '#22B8EB' -},{ - name: 'secondary', - color: '#FFF', - bg: '#232C37' -},{ - name: 'coral', - color: '#FFF', - bg: '#FF85AF' -},{ - name: 'success', - color: '#FFF', - bg: '#0FD85A' -},{ - name: 'warning', - color: '#FFF', - bg: '#FF8546' -},{ - name: 'yellow', - color: '#FFF', - bg: '#FFDE50' -},{ - name: 'alert', - color: '#FFF', - bg: '#EB3E46' -}]); -debug('modules that will be runtime require dependencies of the server if the server requires them: ', node_modules); -var commonConfig = { - resolve: { - extensions: ['', '.js', '.jsx', '.json'], - root: [ - path.resolve(__dirname, './app/scripts/'), - path.resolve(__dirname, './app/scripts/components/') - ], - modulesDirectories: ['node_modules', 'app/scripts'] - }, - module: { - preLoaders: loaders.preLoaders, - loaders: loaders.commonLoaders - }, - plugins: [ - ENV_CONFIG, - new webpack.optimize.DedupePlugin(), - new ExtractTextPlugin('public/styles/style.css', { allChunks: true }) - ], - postcss: [ - require('postcss-import')(), - require('postcss-constants')({ - defaults: _.merge(require('@dux/element-card/defaults')({ - capBackground: '#f1f6fb', - borderColor: '#c4cdda' - }), - { - duxElementButton: { - radius: '.25rem', - buttons: buttons - } - }) - }), - require('postcss-each'), - require('postcss-cssnext')({ - browsers: 'last 2 versions', - features: { - // https://github.com/robwierzbowski/node-pixrem/issues/40 - rem: false - } - }), - require('postcss-nested'), - require('lost')({ - gutter: '1.25rem', - flexbox: 'flex' - }), - require('postcss-cssstats')(function(stats) { - /** - * this is in test-phase because it runs on all - * files individually. We should either figure out - * that that is useful or get it to run on the full postcss - * AST or extracted CSS file. - */ - debug(stats); - }), - require('postcss-url')(), - require('cssnano')(), - require('postcss-browser-reporter') - ], - eslint: { - failOnError: true - }, - profile: true -} - -var clientBundle = _.assign({}, - commonConfig, - { - // client.js - entry: './app/scripts/client.js', - devtool: 'eval-source-map', - output: { - path: 'app/.build/public/', - filename: 'js/client.js' - } - }); - -var serverBundle = _.assign({}, - commonConfig, - { - // server.js - entry: './app/scripts/server.js', - output: { - path: 'app/.build/', - filename: 'server.js', - libraryTarget: 'commonjs2' - }, - target: 'node', - externals: node_modules, - node: { - __dirname: '/opt/hub/' - } - }); - -module.exports = [ - clientBundle, - serverBundle -];