├── .editorconfig ├── .flowconfig ├── .gitattributes ├── .gitignore ├── .travis.yml ├── Dockerfile ├── LICENSE.txt ├── README.md ├── package.json ├── public ├── apple-touch-icon.png ├── browserconfig.xml ├── crossdomain.xml ├── favicon.ico ├── humans.txt ├── robots.txt ├── tile-wide.png └── tile.png ├── src ├── actions │ ├── actionTypes.js │ ├── authActions.js │ ├── msgStackActions.js │ ├── productsActions.js │ ├── registersActions.js │ ├── routesActions.js │ └── usersActions.js ├── client.js ├── components │ ├── AccessKeys │ │ ├── AccessKeys.css │ │ ├── AccessKeys.js │ │ ├── PopShowKey │ │ │ ├── PopShowKey.js │ │ │ └── package.json │ │ └── package.json │ ├── App │ │ ├── App.dev.js │ │ ├── App.prod.js │ │ ├── index.js │ │ └── package.json │ ├── ChangePassword │ │ ├── ChangePassword.css │ │ ├── ChangePassword.js │ │ └── package.json │ ├── Countdown │ │ ├── Countdown.js │ │ └── package.json │ ├── Deployment │ │ ├── Deployment.css │ │ ├── Deployment.js │ │ └── package.json │ ├── DevTools │ │ ├── index.js │ │ └── package.json │ ├── Footer │ │ ├── Footer.css │ │ ├── Footer.js │ │ └── package.json │ ├── Header │ │ ├── Header.css │ │ ├── Header.js │ │ └── package.json │ ├── Home │ │ ├── Home.css │ │ ├── Home.js │ │ └── package.json │ ├── Html.js │ ├── Layout │ │ ├── Layout.css │ │ ├── Layout.js │ │ ├── Layout.test.js │ │ └── package.json │ ├── Link │ │ ├── Link.js │ │ └── package.json │ ├── Login │ │ ├── Login.js │ │ └── package.json │ ├── MsgStack │ │ ├── MsgStack.js │ │ └── package.json │ ├── MyEditor │ │ ├── MyEditor.js │ │ └── package.json │ ├── Navigation │ │ ├── Navigation.js │ │ └── package.json │ ├── Page │ │ ├── Page.css │ │ ├── Page.js │ │ └── package.json │ ├── PopAddApp │ │ ├── PopAddApp.js │ │ └── package.json │ ├── Product │ │ ├── Product.css │ │ ├── Product.js │ │ └── package.json │ ├── ProductList │ │ ├── ProductList.css │ │ ├── ProductList.js │ │ └── package.json │ ├── Register │ │ ├── NavStep │ │ │ ├── NavStep.css │ │ │ ├── NavStep.js │ │ │ ├── arrow.png │ │ │ └── package.json │ │ ├── Register.css │ │ ├── Register.js │ │ ├── StepDone │ │ │ ├── StepDone.js │ │ │ └── package.json │ │ ├── StepOne │ │ │ ├── StepOne.js │ │ │ └── package.json │ │ ├── StepThree │ │ │ ├── StepThree.js │ │ │ └── package.json │ │ ├── StepTwo │ │ │ ├── StepTwo.js │ │ │ └── package.json │ │ └── package.json │ └── variables.css ├── config.js ├── containers │ ├── AccessKeysContainer.js │ ├── ChangePasswordContainer.js │ ├── DeploymentContainer.js │ ├── HomeContainer.js │ ├── LayoutContainer.js │ ├── LoginContainer.js │ ├── LogoutContainer.js │ ├── MsgStackContainer.js │ ├── PopAddAppContainer.js │ ├── ProductContainer.js │ ├── ProductListContainer.js │ └── RegisterContainer.js ├── core │ ├── DOMUtils.js │ ├── devUtils.js │ ├── fetch │ │ ├── fetch.client.js │ │ ├── fetch.server.js │ │ └── package.json │ └── history.js ├── network │ └── RestApi.js ├── reducers │ ├── auth.js │ ├── index.js │ ├── msgStack.js │ ├── products.js │ ├── registers.js │ ├── routes.js │ └── users.js ├── routes │ ├── accessKeys │ │ └── index.js │ ├── apps │ │ └── index.js │ ├── error │ │ ├── ErrorPage.css │ │ ├── ErrorPage.js │ │ └── index.js │ ├── home │ │ └── index.js │ ├── index.js │ ├── login │ │ └── index.js │ ├── notFound │ │ ├── NotFound.css │ │ ├── NotFound.js │ │ └── index.js │ ├── register │ │ └── index.js │ └── users │ │ └── index.js ├── server.js └── store │ ├── configureStore.dev.js │ ├── configureStore.js │ ├── configureStore.prod.js │ ├── createHelpers.js │ └── logger │ ├── logger.client.js │ ├── logger.server.js │ └── package.json ├── test ├── .eslintrc └── setup.js ├── tools ├── .eslintrc ├── README.md ├── build.js ├── bundle.js ├── clean.js ├── copy.js ├── deploy.js ├── lib │ ├── cp.js │ ├── fs.js │ └── markdown-loader.js ├── postcss.config.js ├── render.js ├── run.js ├── runServer.js ├── start.js └── webpack.config.js └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # http://editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | 9 | # Change these settings to your own preference 10 | indent_style = space 11 | indent_size = 2 12 | 13 | # We recommend you to keep these unchanged 14 | end_of_line = lf 15 | charset = utf-8 16 | trim_trailing_whitespace = true 17 | insert_final_newline = true 18 | 19 | # editorconfig-tools is unable to ignore longs strings or urls 20 | max_line_length = null 21 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | .*/build 3 | .*/config 4 | .*/node_modules 5 | .*/gulpfile.js 6 | 7 | [include] 8 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Automatically normalize line endings for all text-based files 2 | # http://git-scm.com/docs/gitattributes#_end_of_line_conversion 3 | * text=auto 4 | 5 | # For the following file types, normalize line endings to LF on 6 | # checkin and prevent conversion to CRLF when they are checked out 7 | # (this is required in order to prevent newline related issues like, 8 | # for example, after the build script is run) 9 | .* text eol=lf 10 | *.html text eol=lf 11 | *.css text eol=lf 12 | *.less text eol=lf 13 | *.scss text eol=lf 14 | *.sss text eol=lf 15 | *.js text eol=lf 16 | *.json text eol=lf 17 | *.md text eol=lf 18 | *.sh text eol=lf 19 | *.txt text eol=lf 20 | *.xml text eol=lf 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Include your project-specific ignores in this file 2 | # Read about how to use .gitignore: https://help.github.com/articles/ignoring-files 3 | 4 | build 5 | node_modules 6 | ncp-debug.log 7 | npm-debug.log 8 | stats.json 9 | report.html 10 | .DS_Store 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '7' 4 | - '6' 5 | env: 6 | - CXX=g++-4.8 7 | addons: 8 | apt: 9 | sources: 10 | - ubuntu-toolchain-r-test 11 | packages: 12 | - g++-4.8 13 | script: 14 | - yarn lint 15 | - yarn test 16 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:6.9.5-alpine 2 | 3 | # Copy application files 4 | COPY ./build /usr/src/app 5 | WORKDIR /usr/src/app 6 | 7 | # Install Yarn and Node.js dependencies 8 | RUN npm install yarn --global --no-progress --silent --depth 0 && \ 9 | yarn install --production --no-progress 10 | 11 | CMD [ "node", "server.js" ] 12 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (c) 2016-present tablee 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | 'Software'), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # @deprecated 2 | 3 | # CodePush Web [source](https://github.com/lisong/code-push-web) 4 | 5 | CodePush Web is a [CodePush Server](https://github.com/lisong/code-push-server)'s web client. it's will more friendly then [code-push-cli](https://github.com/Microsoft/code-push) 6 | 7 | ## INSTALL 8 | 9 | ```shell 10 | $ cd /path/to/code-push-web 11 | $ npm install 12 | ``` 13 | 14 | ## CONFIGURE 15 | 16 | ``` shell 17 | $ vim ./src/config #change URL to production 18 | ``` 19 | 20 | ## RUN DEV 21 | 22 | ```shell 23 | $ npm start 24 | ``` 25 | 26 | ## BUILD AND RUN IN PRODUCTION 27 | 28 | ```shell 29 | $ cd /path/to/code-push-web 30 | $ npm run build -- --release 31 | $ cd ./build 32 | $ npm install 33 | $ node ./server.js 34 | ``` 35 | 36 | ## BASE ON [React Starter Kit](https://github.com/kriasoft/react-starter-kit) 37 | 38 | ## License 39 | MIT License [read](https://github.com/lisong/code-push-web/blob/master/LICENSE.txt) 40 | -------------------------------------------------------------------------------- /public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lisong/code-push-web/1bb945ac2a343713a0985f5a4aa29dbd6bb27a8a/public/apple-touch-icon.png -------------------------------------------------------------------------------- /public/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /public/crossdomain.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 15 | 16 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lisong/code-push-web/1bb945ac2a343713a0985f5a4aa29dbd6bb27a8a/public/favicon.ico -------------------------------------------------------------------------------- /public/humans.txt: -------------------------------------------------------------------------------- 1 | # humanstxt.org/ 2 | # The humans responsible & technology colophon 3 | 4 | # TEAM 5 | 6 | -- -- 7 | 8 | # THANKS 9 | 10 | 11 | 12 | # TECHNOLOGY COLOPHON 13 | 14 | CSS3, HTML5, JavaScript 15 | React, Flux, SuperAgent 16 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # www.robotstxt.org/ 2 | 3 | # Allow crawling of all content 4 | User-agent: * 5 | Disallow: 6 | -------------------------------------------------------------------------------- /public/tile-wide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lisong/code-push-web/1bb945ac2a343713a0985f5a4aa29dbd6bb27a8a/public/tile-wide.png -------------------------------------------------------------------------------- /public/tile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lisong/code-push-web/1bb945ac2a343713a0985f5a4aa29dbd6bb27a8a/public/tile.png -------------------------------------------------------------------------------- /src/actions/actionTypes.js: -------------------------------------------------------------------------------- 1 | /*========= begin authActions ===========*/ 2 | export const REQUEST_AUTH = 'REQUEST_AUTH'; 3 | export const RECEIVE_AUTH = 'RECEIVE_AUTH'; 4 | 5 | export const SAVE_AUTH = 'SAVE_AUTH'; 6 | export const DELETE_AUTH = 'DELETE_AUTH'; 7 | 8 | export const REQUEST_ACCESS_KEYS = 'REQUEST_ACCESS_KEYS'; 9 | export const RECEIVE_ACCESS_KEYS = 'RECEIVE_ACCESS_KEYS'; 10 | 11 | export const REQUEST_REMOVE_ACCESS_KEY = 'REQUEST_REMOVE_ACCESS_KEY'; 12 | export const RECEIVE_REMOVE_ACCESS_KEY = 'RECEIVE_REMOVE_ACCESS_KEY'; 13 | 14 | export const REQUEST_PATCH_ACCESS_KEY = 'REQUEST_PATCH_ACCESS_KEY'; 15 | export const RECEIVE_PATCH_ACCESS_KEY = 'RECEIVE_PATCH_ACCESS_KEY'; 16 | 17 | export const REQUEST_CREATE_ACCESS_KEY = 'REQUEST_CREATE_ACCESS_KEY'; 18 | export const RECEIVE_CREATE_ACCESS_KEY = 'RECEIVE_CREATE_ACCESS_KEY'; 19 | 20 | export const OPEN_POP_SHOW_KEY = 'OPEN_POP_SHOW_KEY'; 21 | export const CLOSE_POP_SHOW_KEY = 'CLOSE_POP_SHOW_KEY'; 22 | /*========= end authActions ===========*/ 23 | 24 | /*========= begin usersActions ===========*/ 25 | export const USER_LOGOUT = 'USER_LOGOUT'; 26 | export const LOGIN_CHANGE_ACCOUNT_INPUT = 'LOGIN_CHANGE_ACCOUNT_INPUT'; 27 | export const LOGIN_CHANGE_PASSWORD_INPUT = 'LOGIN_CHANGE_PASSWORD_INPUT'; 28 | 29 | export const REQUEST_LOGIN = 'REQUEST_LOGIN'; 30 | export const RECEIVE_LOGIN = 'RECEIVE_LOGIN'; 31 | export const RECEIVE_LOGIN_ERROR = 'RECEIVE_LOGIN_ERROR'; 32 | 33 | export const PASSWORD_CHANGE_OLD_INPUT = 'PASSWORD_CHANGE_OLD_INPUT'; 34 | export const PASSWORD_CHANGE_NEW_INPUT = 'PASSWORD_CHANGE_NEW_INPUT'; 35 | export const PASSWORD_CHANGE_NEW_CONFIRM_INPUT = 'PASSWORD_CHANGE_NEW_CONFIRM_INPUT'; 36 | 37 | export const REQUEST_MODIFY_PASSWORD = 'REQUEST_MODIFY_PASSWORD'; 38 | export const RECEIVE_MODIFY_PASSWORD = 'RECEIVE_MODIFY_PASSWORD'; 39 | export const RECEIVE_MODIFY_PASSWORD_ERROR = 'RECEIVE_MODIFY_PASSWORD_ERROR'; 40 | /*========= end usersActions ===========*/ 41 | 42 | /*========= begin registersActions ===========*/ 43 | export const REGISTER_CHANGE_EMAIL_INPUT = 'REGISTER_CHANGE_EMAIL_INPUT'; 44 | 45 | export const REQUEST_REGISTER_CHECK_EMAIL = 'REQUEST_REGISTER_CHECK_EMAIL'; 46 | export const RECEIVE_REGISTER_CHECK_EMAIL = 'RECEIVE_REGISTER_CHECK_EMAIL'; 47 | export const RECEIVE_REGISTER_CHECK_EMAIL_ERROR = 'RECEIVE_REGISTER_CHECK_EMAIL_ERROR'; 48 | 49 | export const REGISTER_CHANGE_VALIDATE_CODE_INPUT = 'REGISTER_CHANGE_VALIDATE_CODE_INPUT'; 50 | 51 | export const REQUEST_REGISTER_SEND_VALIDATE_CODE = 'REQUEST_REGISTER_SEND_VALIDATE_CODE'; 52 | export const RECEIVE_REGISTER_SEND_VALIDATE_CODE = 'RECEIVE_REGISTER_SEND_VALIDATE_CODE'; 53 | export const RECEIVE_REGISTER_SEND_VALIDATE_CODE_ERROR = 'RECEIVE_REGISTER_SEND_VALIDATE_CODE_ERROR'; 54 | 55 | export const REQUEST_REGISTER_CHECK_CODE_EXISTS = 'REQUEST_REGISTER_CHECK_CODE_EXISTS'; 56 | export const RECEIVE_REGISTER_CHECK_CODE_EXISTS = 'RECEIVE_REGISTER_CHECK_CODE_EXISTS'; 57 | export const RECEIVE_REGISTER_CHECK_CODE_EXISTS_ERROR = 'RECEIVE_REGISTER_CHECK_CODE_EXISTS_ERROR'; 58 | 59 | export const REGISTER_CHANGE_PASSWORD_INPUT = 'REGISTER_CHANGE_PASSWORD_INPUT'; 60 | export const REGISTER_CHANGE_PASSWORD_CONFIRM_INPUT = 'REGISTER_CHANGE_PASSWORD_CONFIRM_INPUT'; 61 | 62 | export const REQUEST_REGISTER = 'REQUEST_REGISTER'; 63 | export const RECEIVE_REGISTER = 'RECEIVE_REGISTER'; 64 | export const RECEIVE_REGISTER_ERROR = 'RECEIVE_REGISTER_ERROR'; 65 | 66 | export const RECEIVE_REGISTER_CLEAN = 'RECEIVE_REGISTER_CLEAN'; 67 | /*========= end registersActions ===========*/ 68 | 69 | /*========= begin routesActions ===========*/ 70 | export const SET_BACK_HISTORY = 'SET_BACK_HISTORY'; 71 | export const GO_BACK_HISTORY = 'GO_BACK_HISTORY'; 72 | export const SHOW_HOME = 'SHOW_HOME'; 73 | export const SHOW_LOGIN = 'SHOW_LOGIN'; 74 | /*========= end routesActions ===========*/ 75 | 76 | /*========= begin productsActions ===========*/ 77 | export const REQUEST_PRODUCTS = 'REQUEST_PRODUCTS'; 78 | export const RECEIVE_PRODUCTS = 'RECEIVE_PRODUCTS'; 79 | export const SHOW_POP_ADD_APP = 'SHOW_POP_ADD_APP'; 80 | export const CLOSE_POP_ADD_APP = 'CLOSE_POP_ADD_APP'; 81 | export const POP_ADD_APP_INPUT = 'POP_ADD_APP_INPUT'; 82 | export const REQUEST_ADD_PRODUCTS = 'REQUEST_ADD_PRODUCTS'; 83 | export const RECEIVE_ADD_PRODUCTS = 'RECEIVE_ADD_PRODUCTS'; 84 | export const REQUEST_PRODUCTS_DEPLOYMENTS = 'REQUEST_PRODUCTS_DEPLOYMENTS'; 85 | export const RECEIVE_PRODUCTS_DEPLOYMENTS = 'RECEIVE_PRODUCTS_DEPLOYMENTS'; 86 | /*========= end productsActions ===========*/ 87 | 88 | /*========= begin msgStackActions ===========*/ 89 | export const MSG_STACK_SHOW_MSG = 'MSG_STACK_SHOW_MSG'; 90 | export const MSG_STACK_CLOSE_MSG = 'MSG_STACK_CLOSE_MSG'; 91 | /*========= end msgStackActions ===========*/ 92 | -------------------------------------------------------------------------------- /src/actions/authActions.js: -------------------------------------------------------------------------------- 1 | import { 2 | REQUEST_AUTH, 3 | RECEIVE_AUTH, 4 | SAVE_AUTH, 5 | DELETE_AUTH, 6 | REQUEST_ACCESS_KEYS, 7 | RECEIVE_ACCESS_KEYS, 8 | REQUEST_REMOVE_ACCESS_KEY, 9 | RECEIVE_REMOVE_ACCESS_KEY, 10 | REQUEST_PATCH_ACCESS_KEY, 11 | RECEIVE_PATCH_ACCESS_KEY, 12 | REQUEST_CREATE_ACCESS_KEY, 13 | RECEIVE_CREATE_ACCESS_KEY, 14 | CLOSE_POP_SHOW_KEY, 15 | OPEN_POP_SHOW_KEY, 16 | } from './actionTypes'; 17 | import {showLogin} from './routesActions.js' 18 | import {addShowMsg} from './msgStackActions'; 19 | import restApi from '../network/RestApi'; 20 | import _ from 'lodash'; 21 | 22 | function requestAuth() { 23 | return { 24 | type: REQUEST_AUTH, 25 | } 26 | } 27 | 28 | function receiveAuth(data) { 29 | return { 30 | type: RECEIVE_AUTH, 31 | payload: data, 32 | } 33 | } 34 | 35 | export function fetchAuth(isLogin = false) { 36 | return (dispatch) => { 37 | dispatch(requestAuth()); 38 | let auth = sessionStorage.getItem('auth'); 39 | if (!_.isEmpty(auth)) { 40 | dispatch(receiveAuth(auth)) 41 | } else { 42 | dispatch(receiveAuth(null)) 43 | if (isLogin) { 44 | dispatch(showLogin()); 45 | } 46 | } 47 | }; 48 | } 49 | 50 | export function saveAuth(auth) { 51 | return { 52 | type: SAVE_AUTH, 53 | payload: auth, 54 | } 55 | } 56 | 57 | export function deleteAuth() { 58 | return { 59 | type: DELETE_AUTH, 60 | } 61 | } 62 | 63 | export function requestAccessKeys() { 64 | return { 65 | type: REQUEST_ACCESS_KEYS, 66 | } 67 | } 68 | 69 | export function receiveAccessKeys(data) { 70 | return { 71 | type: RECEIVE_ACCESS_KEYS, 72 | payload: data 73 | } 74 | } 75 | 76 | export function fetchAccessKeys() { 77 | return (dispatch) => { 78 | dispatch(requestAccessKeys()); 79 | return restApi.getAccessKeys() 80 | .then(data => { 81 | dispatch(receiveAccessKeys(data)); 82 | }); 83 | }; 84 | } 85 | 86 | export function requestRemoveAccessKey() { 87 | return { 88 | type: REQUEST_REMOVE_ACCESS_KEY, 89 | } 90 | } 91 | 92 | export function receiveRemoveAccessKey(data) { 93 | return { 94 | type: RECEIVE_REMOVE_ACCESS_KEY, 95 | payload: data 96 | } 97 | } 98 | 99 | export function reomveAccessKey(name) { 100 | return (dispatch) => { 101 | dispatch(requestRemoveAccessKey()); 102 | return restApi.removeAccessKey(name) 103 | .then(data => { 104 | if (_.get(data,'status') !== "OK") { 105 | dispatch(addShowMsg("删除密钥失败:"+ _.get(data, 'errorMessage'), "danger")); 106 | } else { 107 | dispatch(addShowMsg("删除密钥成功:" + name, "success")); 108 | } 109 | dispatch(receiveRemoveAccessKey(data)); 110 | }); 111 | }; 112 | } 113 | 114 | export function requestPatchAccessKey() { 115 | return { 116 | type: REQUEST_PATCH_ACCESS_KEY, 117 | } 118 | } 119 | 120 | export function receivePatchAccessKey(name, data) { 121 | return { 122 | type: RECEIVE_PATCH_ACCESS_KEY, 123 | payload: {friendlyName:name, ...data} 124 | } 125 | } 126 | 127 | export function patchAccessKey(name, friendlyName=null, ttl=0) { 128 | return (dispatch) => { 129 | dispatch(requestPatchAccessKey()); 130 | return restApi.patchAccessKey(name, friendlyName, ttl) 131 | .then(data => { 132 | if (_.get(data,'status') !== "OK") { 133 | dispatch(addShowMsg("修改密钥失败:"+ _.get(data, 'errorMessage'), "danger")); 134 | } else { 135 | dispatch(addShowMsg("修改密钥成功:" + friendlyName, "success")); 136 | } 137 | dispatch(receivePatchAccessKey(name, data)); 138 | }).catch(function(e){ 139 | console.log(e); 140 | }); 141 | }; 142 | } 143 | 144 | export function requestCreateAccessKey() { 145 | return { 146 | type: REQUEST_CREATE_ACCESS_KEY, 147 | } 148 | } 149 | 150 | export function receiveCreateAccessKey(data) { 151 | return { 152 | type: RECEIVE_CREATE_ACCESS_KEY, 153 | payload: data 154 | } 155 | } 156 | 157 | export function createAccessKey() { 158 | return (dispatch) => { 159 | dispatch(requestCreateAccessKey()); 160 | return restApi.createAccessKey() 161 | .then(data => { 162 | if (_.get(data,'status') !== "OK") { 163 | dispatch(addShowMsg("创建密钥失败:"+ _.get(data, 'errorMessage'), "danger")); 164 | } else { 165 | dispatch(addShowMsg("创建密钥成功:" + _.get(data, 'results.accessKey.friendlyName'), "success")); 166 | } 167 | dispatch(openPopShowKey(_.get(data, 'results.accessKey.name'))); 168 | dispatch(receiveCreateAccessKey(data)); 169 | }); 170 | }; 171 | } 172 | 173 | export function openPopShowKey(key) { 174 | return { 175 | type: OPEN_POP_SHOW_KEY, 176 | payload: key 177 | } 178 | } 179 | 180 | export function closePopShowKey() { 181 | return { 182 | type: CLOSE_POP_SHOW_KEY, 183 | } 184 | } 185 | 186 | export function checkResponseAuth(dispatch, data) { 187 | if (data.httpCode == 401) { 188 | dispatch(fetchAuth(true)); 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /src/actions/msgStackActions.js: -------------------------------------------------------------------------------- 1 | import { 2 | MSG_STACK_SHOW_MSG, 3 | MSG_STACK_CLOSE_MSG, 4 | } from './actionTypes'; 5 | import _ from 'lodash'; 6 | 7 | export function addShowMsg(text, type="info", showTime=10) { 8 | return { 9 | type: MSG_STACK_SHOW_MSG, 10 | payload: {text,type,showTime}, 11 | } 12 | } 13 | 14 | export function closeMsg(id) { 15 | return { 16 | type: MSG_STACK_CLOSE_MSG, 17 | payload: id, 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/actions/productsActions.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | 3 | import * as types from './actionTypes'; 4 | import restApi from '../network/RestApi'; 5 | import {checkResponseAuth} from './authActions'; 6 | import {addShowMsg} from './msgStackActions'; 7 | 8 | export function requestProducts() { 9 | return { 10 | type: types.REQUEST_PRODUCTS, 11 | } 12 | } 13 | 14 | export function receiveProducts(data) { 15 | return { 16 | type: types.RECEIVE_PRODUCTS, 17 | payload: data 18 | } 19 | } 20 | 21 | export function getProducts() { 22 | return (dispatch) => { 23 | dispatch(requestProducts()); 24 | return restApi.getProducts() 25 | .then(data => { 26 | checkResponseAuth(dispatch, data); 27 | dispatch(receiveProducts(data)); 28 | }); 29 | }; 30 | } 31 | 32 | export function showPopAddApp() { 33 | return {type: types.SHOW_POP_ADD_APP}; 34 | } 35 | 36 | export function closePopAddApp() { 37 | return {type: types.CLOSE_POP_ADD_APP}; 38 | } 39 | 40 | export function popAddAppInput(params) { 41 | return { 42 | type: types.POP_ADD_APP_INPUT, 43 | payload : params 44 | } 45 | } 46 | 47 | export function requestAddProducts() { 48 | return { 49 | type: types.REQUEST_ADD_PRODUCTS, 50 | } 51 | } 52 | 53 | export function receiveAddProducts(data) { 54 | return { 55 | type: types.RECEIVE_ADD_PRODUCTS, 56 | payload: data 57 | } 58 | } 59 | 60 | export function addProducts(appName, os, platform) { 61 | return (dispatch) => { 62 | dispatch(requestAddProducts()); 63 | return restApi.addProducts(appName, os, platform) 64 | .then(data => { 65 | checkResponseAuth(dispatch, data); 66 | if (_.get(data, 'status') !== "OK") { 67 | dispatch(addShowMsg("创建应用: "+_.get(data,'errorMessage'), "danger")); 68 | } else { 69 | dispatch(addShowMsg("创建 "+_.get(data,'results.app.name')+" 应用成功", "success")); 70 | } 71 | dispatch(receiveAddProducts(data)); 72 | dispatch(getProducts()); 73 | }); 74 | }; 75 | } 76 | 77 | export function requestDeployments(appName) { 78 | return { 79 | type: types.REQUEST_PRODUCTS_DEPLOYMENTS, 80 | payload: appName 81 | } 82 | } 83 | 84 | export function receiveDeployments(appName, data) { 85 | return { 86 | type: types.RECEIVE_PRODUCTS_DEPLOYMENTS, 87 | payload: {appName, ...data} 88 | } 89 | } 90 | 91 | export function fetchDeployments(appName) { 92 | return (dispatch) => { 93 | dispatch(requestDeployments(appName)); 94 | return restApi.getDeployments(appName) 95 | .then(data => { 96 | checkResponseAuth(dispatch, data); 97 | dispatch(receiveDeployments(appName, data)); 98 | }); 99 | }; 100 | } 101 | -------------------------------------------------------------------------------- /src/actions/registersActions.js: -------------------------------------------------------------------------------- 1 | import * as types from './actionTypes'; 2 | import restApi from '../network/RestApi'; 3 | import _ from 'lodash'; 4 | 5 | export function registerChangeEmailInput(email) { 6 | return { 7 | type: types.REGISTER_CHANGE_EMAIL_INPUT, 8 | payload: email 9 | }; 10 | } 11 | 12 | function requestRegisterCheckEmail() { 13 | return { 14 | type: types.REQUEST_REGISTER_CHECK_EMAIL, 15 | } 16 | } 17 | 18 | function receiveRegisterCheckEmail(data) { 19 | return { 20 | type: types.RECEIVE_REGISTER_CHECK_EMAIL, 21 | payload: data, 22 | } 23 | } 24 | 25 | function receiveRegisterCheckEmailError(error) { 26 | return { 27 | type: types.RECEIVE_REGISTER_CHECK_EMAIL_ERROR, 28 | payload: error, 29 | } 30 | } 31 | 32 | export function registerCheckEmail(email) { 33 | return (dispatch) => { 34 | dispatch(requestRegisterCheckEmail()); 35 | return restApi.checkEmailExists(email) 36 | .then(data => { 37 | if (_.get(data,'status') == "OK" && _.get(data, 'exists') == false) { 38 | dispatch(receiveRegisterCheckEmail(data)); 39 | } else { 40 | var message = `${email} 已经注册了,请更换其他邮箱注册` 41 | if (_.get(data,'status') != "OK") { 42 | message = _.get(data, 'message'); 43 | } 44 | dispatch(receiveRegisterCheckEmailError({message: message})); 45 | } 46 | }); 47 | }; 48 | } 49 | 50 | export function registerChangeValidateCodeInput(validateCode) { 51 | return { 52 | type: types.REGISTER_CHANGE_VALIDATE_CODE_INPUT, 53 | payload: validateCode 54 | }; 55 | } 56 | 57 | function requestRegisterSendValidateCode() { 58 | return { 59 | type: types.REQUEST_REGISTER_SEND_VALIDATE_CODE, 60 | } 61 | } 62 | 63 | function receiveRegisterSendValidateCode(data) { 64 | return { 65 | type: types.RECEIVE_REGISTER_SEND_VALIDATE_CODE, 66 | payload: data, 67 | } 68 | } 69 | 70 | function receiveRegisterSendValidateCodeError(error) { 71 | return { 72 | type: types.RECEIVE_REGISTER_SEND_VALIDATE_CODE_ERROR, 73 | payload: error, 74 | } 75 | } 76 | 77 | export function registerSendValidateCode(email) { 78 | return (dispatch) => { 79 | dispatch(requestRegisterSendValidateCode()); 80 | return restApi.sendRegisterCode(email) 81 | .then(data => { 82 | if (_.get(data, 'status') == "OK") { 83 | dispatch(receiveRegisterSendValidateCode(data)); 84 | } else { 85 | var message = _.get(data, 'message'); 86 | dispatch(receiveRegisterSendValidateCodeError({message: message})); 87 | } 88 | }); 89 | }; 90 | } 91 | 92 | function requestRegisterCheckCodeExists() { 93 | return { 94 | type: types.REQUEST_REGISTER_CHECK_CODE_EXISTS, 95 | } 96 | } 97 | 98 | function receiveRegisterCheckCodeExists(data) { 99 | return { 100 | type: types.RECEIVE_REGISTER_CHECK_CODE_EXISTS, 101 | payload: data, 102 | } 103 | } 104 | 105 | function receiveRegisterCheckCodeExistsError(error) { 106 | return { 107 | type: types.RECEIVE_REGISTER_CHECK_CODE_EXISTS_ERROR, 108 | payload: error, 109 | } 110 | } 111 | 112 | export function registerCheckCodeExists(email, validateCode) { 113 | return (dispatch) => { 114 | dispatch(requestRegisterCheckCodeExists()); 115 | return restApi.checkRegisterCodeExists(email, validateCode) 116 | .then(data => { 117 | if (_.get(data, 'status') == "OK") { 118 | dispatch(receiveRegisterCheckCodeExists(data)); 119 | } else { 120 | var message = _.get(data, 'message'); 121 | dispatch(receiveRegisterCheckCodeExistsError({message: message})); 122 | } 123 | }); 124 | }; 125 | } 126 | 127 | export function registerChangePasswordInput(password) { 128 | return { 129 | type: types.REGISTER_CHANGE_PASSWORD_INPUT, 130 | payload: password 131 | }; 132 | } 133 | 134 | export function registerChangePasswordConfirmInput(passwordConfirm) { 135 | return { 136 | type: types.REGISTER_CHANGE_PASSWORD_CONFIRM_INPUT, 137 | payload: passwordConfirm 138 | }; 139 | } 140 | 141 | function requestRegister() { 142 | return { 143 | type: types.REQUEST_REGISTER, 144 | } 145 | } 146 | 147 | function receiveRegister(data) { 148 | return { 149 | type: types.RECEIVE_REGISTER, 150 | payload: data, 151 | } 152 | } 153 | 154 | function receiveRegisterError(error) { 155 | return { 156 | type: types.RECEIVE_REGISTER_ERROR, 157 | payload: error, 158 | } 159 | } 160 | 161 | export function register(email, password, validateCode) { 162 | return (dispatch) => { 163 | dispatch(requestRegister()); 164 | return restApi.register(email, password, validateCode) 165 | .then(data => { 166 | if (_.get(data, 'status') == "OK") { 167 | dispatch(receiveRegister(data)); 168 | } else { 169 | var message = _.get(data, 'message'); 170 | dispatch(receiveRegisterError({message: message})); 171 | } 172 | }); 173 | }; 174 | } 175 | 176 | export function registerClean() { 177 | return {type: types.RECEIVE_REGISTER_CLEAN} 178 | } 179 | -------------------------------------------------------------------------------- /src/actions/routesActions.js: -------------------------------------------------------------------------------- 1 | import { 2 | SET_BACK_HISTORY, 3 | GO_BACK_HISTORY, 4 | SHOW_HOME, 5 | SHOW_LOGIN, 6 | } from './actionTypes'; 7 | 8 | export function setBackHistory(history="/") { 9 | return { 10 | type: SET_BACK_HISTORY, 11 | payload: history 12 | }; 13 | } 14 | 15 | export function goBackHistory() { 16 | return {type: GO_BACK_HISTORY}; 17 | } 18 | 19 | export function showHome() { 20 | return {type: SHOW_HOME}; 21 | } 22 | 23 | export function showLogin() { 24 | return {type: SHOW_LOGIN}; 25 | } 26 | -------------------------------------------------------------------------------- /src/actions/usersActions.js: -------------------------------------------------------------------------------- 1 | import * as types from './actionTypes'; 2 | import restApi from '../network/RestApi'; 3 | import {saveAuth, deleteAuth, checkResponseAuth} from './authActions'; 4 | import {showLogin} from './routesActions'; 5 | import {addShowMsg} from './msgStackActions'; 6 | import _ from 'lodash'; 7 | 8 | export function logout() { 9 | return (dispatch) => { 10 | dispatch(deleteAuth()); 11 | return dispatch({type: types.USER_LOGOUT}); 12 | } 13 | } 14 | 15 | export function loginChangeAccountInput(account) { 16 | return { 17 | type: types.LOGIN_CHANGE_ACCOUNT_INPUT, 18 | payload: account 19 | }; 20 | } 21 | 22 | export function loginChangePasswordInput(password) { 23 | return { 24 | type: types.LOGIN_CHANGE_PASSWORD_INPUT, 25 | payload: password 26 | }; 27 | } 28 | 29 | function requestLogin() { 30 | return { 31 | type: types.REQUEST_LOGIN, 32 | } 33 | } 34 | 35 | function receiveLogin(data) { 36 | return { 37 | type: types.RECEIVE_LOGIN, 38 | payload: data, 39 | } 40 | } 41 | 42 | function receiveLoginError(error) { 43 | return { 44 | type: types.RECEIVE_LOGIN_ERROR, 45 | payload: error, 46 | } 47 | } 48 | 49 | export function fetchLogin(account, password) { 50 | return (dispatch) => { 51 | dispatch(requestLogin()); 52 | return restApi.login(account, password) 53 | .then(data => { 54 | var auth = _.get(data, 'results.tokens'); 55 | if (!_.isEmpty(auth)) { 56 | dispatch(saveAuth(auth)); 57 | dispatch(receiveLogin(data)); 58 | } else { 59 | dispatch(receiveLoginError({errorMessage:_.get(data, 'errorMessage')})); 60 | } 61 | }); 62 | }; 63 | } 64 | 65 | export function passwordChangeOldInput(oldPassword) { 66 | return { 67 | type: types.PASSWORD_CHANGE_OLD_INPUT, 68 | payload: oldPassword 69 | } 70 | } 71 | 72 | export function passwordChangeNewInput(newPassword) { 73 | return { 74 | type: types.PASSWORD_CHANGE_NEW_INPUT, 75 | payload: newPassword 76 | } 77 | } 78 | 79 | export function passwordChangeNewConfirmInput(newPasswordConfirm) { 80 | return { 81 | type: types.PASSWORD_CHANGE_NEW_CONFIRM_INPUT, 82 | payload: newPasswordConfirm 83 | } 84 | } 85 | 86 | function requestModifyPassword() { 87 | return { 88 | type: types.REQUEST_MODIFY_PASSWORD, 89 | } 90 | } 91 | 92 | function receiveModifyPassword(data) { 93 | return { 94 | type: types.RECEIVE_MODIFY_PASSWORD, 95 | payload: data, 96 | } 97 | } 98 | 99 | function receiveModifyPasswordError(error) { 100 | return { 101 | type: types.RECEIVE_MODIFY_PASSWORD_ERROR, 102 | payload: error, 103 | } 104 | } 105 | 106 | export function modifyPassword(oldPassword, newPassword) { 107 | return (dispatch) => { 108 | dispatch(requestModifyPassword()); 109 | return restApi.password(oldPassword, newPassword) 110 | .then(data => { 111 | checkResponseAuth(dispatch, data); 112 | if (_.get(data, 'status') == "OK") { 113 | dispatch(deleteAuth()); 114 | dispatch(receiveModifyPassword(data)); 115 | dispatch(showLogin()); 116 | } else { 117 | dispatch(receiveModifyPasswordError({message: _.get(data, 'message')})); 118 | } 119 | }); 120 | }; 121 | } 122 | -------------------------------------------------------------------------------- /src/client.js: -------------------------------------------------------------------------------- 1 | /** 2 | * React Starter Kit (https://www.reactstarterkit.com/) 3 | * 4 | * Copyright © 2014-present Kriasoft, LLC. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | import React from 'react'; 11 | import ReactDOM from 'react-dom'; 12 | import FastClick from 'fastclick'; 13 | import UniversalRouter from 'universal-router'; 14 | import queryString from 'query-string'; 15 | import { createPath } from 'history/PathUtils'; 16 | import history from './core/history'; 17 | import App from './components/App'; 18 | import configureStore from './store/configureStore'; 19 | import { updateMeta } from './core/DOMUtils'; 20 | import { ErrorReporter, deepForceUpdate } from './core/devUtils'; 21 | 22 | // Global (context) variables that can be easily accessed from any React component 23 | // https://facebook.github.io/react/docs/context.html 24 | const context = { 25 | // Enables critical path CSS rendering 26 | // https://github.com/kriasoft/isomorphic-style-loader 27 | insertCss: (...styles) => { 28 | // eslint-disable-next-line no-underscore-dangle 29 | const removeCss = styles.map(x => x._insertCss()); 30 | return () => { removeCss.forEach(f => f()); }; 31 | }, 32 | // Initialize a new Redux store 33 | // http://redux.js.org/docs/basics/UsageWithReact.html 34 | store: configureStore(window.APP_STATE, { history }), 35 | }; 36 | 37 | // Switch off the native scroll restoration behavior and handle it manually 38 | // https://developers.google.com/web/updates/2015/09/history-api-scroll-restoration 39 | const scrollPositionsHistory = {}; 40 | if (window.history && 'scrollRestoration' in window.history) { 41 | window.history.scrollRestoration = 'manual'; 42 | } 43 | 44 | let onRenderComplete = function initialRenderComplete() { 45 | const elem = document.getElementById('css'); 46 | if (elem) elem.parentNode.removeChild(elem); 47 | onRenderComplete = function renderComplete(route, location) { 48 | document.title = route.title; 49 | 50 | updateMeta('description', route.description); 51 | // Update necessary tags in at runtime here, ie: 52 | // updateMeta('keywords', route.keywords); 53 | // updateCustomMeta('og:url', route.canonicalUrl); 54 | // updateCustomMeta('og:image', route.imageUrl); 55 | // updateLink('canonical', route.canonicalUrl); 56 | // etc. 57 | 58 | let scrollX = 0; 59 | let scrollY = 0; 60 | const pos = scrollPositionsHistory[location.key]; 61 | if (pos) { 62 | scrollX = pos.scrollX; 63 | scrollY = pos.scrollY; 64 | } else { 65 | const targetHash = location.hash.substr(1); 66 | if (targetHash) { 67 | const target = document.getElementById(targetHash); 68 | if (target) { 69 | scrollY = window.pageYOffset + target.getBoundingClientRect().top; 70 | } 71 | } 72 | } 73 | 74 | // Restore the scroll position if it was saved into the state 75 | // or scroll to the given #hash anchor 76 | // or scroll to top of the page 77 | window.scrollTo(scrollX, scrollY); 78 | 79 | // Google Analytics tracking. Don't send 'pageview' event after 80 | // the initial rendering, as it was already sent 81 | if (window.ga) { 82 | window.ga('send', 'pageview', createPath(location)); 83 | } 84 | }; 85 | }; 86 | 87 | // Make taps on links and buttons work fast on mobiles 88 | FastClick.attach(document.body); 89 | 90 | const container = document.getElementById('app'); 91 | let appInstance; 92 | let currentLocation = history.location; 93 | let routes = require('./routes').default; 94 | 95 | // Re-render the app when window.location changes 96 | async function onLocationChange(location, action) { 97 | // Remember the latest scroll position for the previous location 98 | scrollPositionsHistory[currentLocation.key] = { 99 | scrollX: window.pageXOffset, 100 | scrollY: window.pageYOffset, 101 | }; 102 | // Delete stored scroll position for next page if any 103 | if (action === 'PUSH') { 104 | delete scrollPositionsHistory[location.key]; 105 | } 106 | currentLocation = location; 107 | 108 | try { 109 | // Traverses the list of routes in the order they are defined until 110 | // it finds the first route that matches provided URL path string 111 | // and whose action method returns anything other than `undefined`. 112 | const route = await UniversalRouter.resolve(routes, { 113 | ...context, 114 | path: location.pathname, 115 | query: queryString.parse(location.search), 116 | }); 117 | 118 | // Prevent multiple page renders during the routing process 119 | if (currentLocation.key !== location.key) { 120 | return; 121 | } 122 | 123 | if (route.redirect) { 124 | history.replace(route.redirect); 125 | return; 126 | } 127 | 128 | appInstance = ReactDOM.render( 129 | {route.component}, 130 | container, 131 | () => onRenderComplete(route, location), 132 | ); 133 | } catch (error) { 134 | // Display the error in full-screen for development mode 135 | if (__DEV__) { 136 | appInstance = null; 137 | document.title = `Error: ${error.message}`; 138 | ReactDOM.render(, container); 139 | throw error; 140 | } 141 | 142 | console.error(error); // eslint-disable-line no-console 143 | 144 | // Do a full page reload if error occurs during client-side navigation 145 | if (action && currentLocation.key === location.key) { 146 | window.location.reload(); 147 | } 148 | } 149 | } 150 | 151 | // Handle client-side navigation by using HTML5 History API 152 | // For more information visit https://github.com/mjackson/history#readme 153 | history.listen(onLocationChange); 154 | onLocationChange(currentLocation); 155 | 156 | // Handle errors that might happen after rendering 157 | // Display the error in full-screen for development mode 158 | if (__DEV__) { 159 | window.addEventListener('error', (event) => { 160 | appInstance = null; 161 | document.title = `Runtime Error: ${event.error.message}`; 162 | ReactDOM.render(, container); 163 | }); 164 | } 165 | 166 | // Enable Hot Module Replacement (HMR) 167 | if (module.hot) { 168 | module.hot.accept('./routes', () => { 169 | routes = require('./routes').default; // eslint-disable-line global-require 170 | 171 | if (appInstance) { 172 | try { 173 | // Force-update the whole tree, including components that refuse to update 174 | deepForceUpdate(appInstance); 175 | } catch (error) { 176 | appInstance = null; 177 | document.title = `Hot Update Error: ${error.message}`; 178 | ReactDOM.render(, container); 179 | return; 180 | } 181 | } 182 | 183 | onLocationChange(currentLocation); 184 | }); 185 | } 186 | -------------------------------------------------------------------------------- /src/components/AccessKeys/AccessKeys.css: -------------------------------------------------------------------------------- 1 | 2 | @import '../../components/variables.css'; 3 | 4 | .root { 5 | padding-left: 20px; 6 | padding-right: 20px; 7 | } 8 | 9 | .container { 10 | margin: 0 auto; 11 | padding: 0 0 40px; 12 | min-height: 480px; 13 | max-width: var(--max-content-width); 14 | } 15 | 16 | table{ 17 | font-size: 1.2em; 18 | width: 100%; 19 | text-align: center; 20 | } 21 | -------------------------------------------------------------------------------- /src/components/AccessKeys/AccessKeys.js: -------------------------------------------------------------------------------- 1 | 2 | import React, { PropTypes, Component } from 'react'; 3 | import { Breadcrumb, Table, Button, Col } from 'react-bootstrap'; 4 | import withStyles from 'isomorphic-style-loader/lib/withStyles'; 5 | import s from './AccessKeys.css'; 6 | import cx from 'classnames'; 7 | import _ from 'lodash'; 8 | import Link from '../Link'; 9 | import MyEditor from '../MyEditor'; 10 | import PopShowKey from './PopShowKey'; 11 | 12 | class AccessKeys extends Component { 13 | static propTypes = { 14 | isFetching: PropTypes.bool, 15 | rs: PropTypes.array, 16 | removeKey: PropTypes.func, 17 | patchKey: PropTypes.func, 18 | isCreating: PropTypes.bool, 19 | createKey: PropTypes.func, 20 | isShowKey: PropTypes.bool, 21 | close: PropTypes.func, 22 | token: PropTypes.string, 23 | }; 24 | 25 | static defaultProps = { 26 | isFetching: true, 27 | rs: [], 28 | removeKey: (name) => {}, 29 | patchKey: (name, friendlyName = null, ttl = 0) => {}, 30 | isCreating: false, 31 | createKey: () => {}, 32 | isShowKey: false, 33 | close: () => {}, 34 | token: '', 35 | }; 36 | 37 | constructor() { 38 | super(); 39 | this.renderRow = this.renderRow.bind(this); 40 | } 41 | 42 | renderRow(rowData, index) { 43 | const self = this; 44 | const moment = require('moment'); 45 | return ( 46 | 47 | 48 | { 50 | if (!_.eq(str, _.get(rowData, 'friendlyName'))) { 51 | self.props.patchKey(_.get(rowData, 'friendlyName'), str); 52 | } 53 | }} 54 | value={_.get(rowData, 'friendlyName')} 55 | /> 56 | 57 | {_.get(rowData, 'createdBy')} 58 | {_.get(rowData, 'isSession') ? 'session' : 'accessKey'} 59 | {moment(_.get(rowData, 'createdTime')).fromNow()} 60 | {moment(_.get(rowData, 'expires')).fromNow()} 61 | 62 | 68 | 69 | 70 | ); 71 | } 72 | 73 | render() { 74 | const self = this; 75 | let tipText = '暂无数据'; 76 | if (this.props.isFetching) { 77 | tipText = '加载数据中...'; 78 | } 79 | return ( 80 |
81 | 86 |
87 | 88 | 89 | 密钥列表 90 | 91 | 92 | 93 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | { 116 | this.props.rs.length > 0 ? 117 | _.map(this.props.rs, (item, index) => self.renderRow(item, index)) 118 | : 119 | 120 | 121 | 122 | } 123 | 124 |
名字创建者类型创建时间过期时间操作
{tipText}
125 |
126 |
127 | ); 128 | } 129 | } 130 | export default withStyles(s)(AccessKeys); 131 | -------------------------------------------------------------------------------- /src/components/AccessKeys/PopShowKey/PopShowKey.js: -------------------------------------------------------------------------------- 1 | 2 | import React, { PropTypes, Component } from 'react'; 3 | import {Modal, Button, FormGroup, FormControl, HelpBlock} from 'react-bootstrap'; 4 | 5 | class PopShowKey extends Component { 6 | static propTypes = { 7 | value: PropTypes.string, 8 | close: PropTypes.func, 9 | showModal: PropTypes.bool, 10 | }; 11 | 12 | static defaultProps = { 13 | value: '', 14 | showModal: false, 15 | close: ()=>{}, 16 | }; 17 | 18 | constructor() { 19 | super(); 20 | this.close = this.close.bind(this); 21 | } 22 | 23 | close() { 24 | this.props.close(); 25 | } 26 | 27 | render() { 28 | return ( 29 | 30 | 31 | 创建密钥成功 32 | 33 | 34 | 35 | { 38 | event.target.select(); 39 | }} 40 | onClick={(event)=>{ 41 | event.target.select(); 42 | }} 43 | onMouseOver={(event)=>{ 44 | event.target.select(); 45 | }} 46 | readOnly 47 | type="text" 48 | /> 49 | 复制上面的密钥, 然后关闭弹框 50 | 51 | 52 | 53 | 54 | 55 | 56 | ) 57 | } 58 | } 59 | export default PopShowKey; 60 | -------------------------------------------------------------------------------- /src/components/AccessKeys/PopShowKey/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "PopShowKey", 3 | "version": "0.0.0", 4 | "private": true, 5 | "main": "./PopShowKey.js" 6 | } 7 | -------------------------------------------------------------------------------- /src/components/AccessKeys/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "AccessKeys", 3 | "version": "0.0.0", 4 | "private": true, 5 | "main": "./AccessKeys.js" 6 | } 7 | -------------------------------------------------------------------------------- /src/components/App/App.dev.js: -------------------------------------------------------------------------------- 1 | /** 2 | * React Starter Kit (https://www.reactstarterkit.com/) 3 | * 4 | * Copyright © 2014-present Kriasoft, LLC. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | import React, { Children, PropTypes } from 'react'; 11 | import { Provider } from 'react-redux'; 12 | import _ from 'lodash'; 13 | import uuid from 'uuid'; 14 | import DevTools from '../DevTools'; 15 | import restApi from '../../network/RestApi'; 16 | import { fetchAuth } from '../../actions/authActions'; 17 | 18 | const ContextType = { 19 | // Enables critical path CSS rendering 20 | // https://github.com/kriasoft/isomorphic-style-loader 21 | insertCss: PropTypes.func.isRequired, 22 | // Integrate Redux 23 | // http://redux.js.org/docs/basics/UsageWithReact.html 24 | store: PropTypes.shape({ 25 | subscribe: PropTypes.func.isRequired, 26 | dispatch: PropTypes.func.isRequired, 27 | getState: PropTypes.func.isRequired, 28 | }).isRequired, 29 | }; 30 | 31 | /** 32 | * The top-level React component setting context (global) variables 33 | * that can be accessed from all the child components. 34 | * 35 | * https://facebook.github.io/react/docs/context.html 36 | * 37 | * Usage example: 38 | * 39 | * const context = { 40 | * history: createBrowserHistory(), 41 | * store: createStore(), 42 | * }; 43 | * 44 | * ReactDOM.render( 45 | * 46 | * 47 | * 48 | * 49 | * , 50 | * container, 51 | * ); 52 | */ 53 | class App extends React.PureComponent { 54 | 55 | static propTypes = { 56 | context: PropTypes.shape(ContextType).isRequired, 57 | children: PropTypes.element.isRequired, 58 | }; 59 | 60 | static childContextTypes = ContextType; 61 | 62 | getChildContext() { 63 | return this.props.context; 64 | } 65 | 66 | componentDidMount() { 67 | let aQQGuid = localStorage.getItem('aQQ_guid'); 68 | if (_.isEmpty(aQQGuid) || aQQGuid.length < 10) { 69 | aQQGuid = uuid.v1(); 70 | localStorage.setItem('aQQ_guid', aQQGuid); 71 | } 72 | let sessid = sessionStorage.getItem('sessid'); 73 | if (_.isEmpty(sessid) || sessid.length < 10) { 74 | sessid = uuid.v1(); 75 | sessionStorage.setItem('sessid', sessid); 76 | } 77 | restApi.setUUID(sessid, aQQGuid); 78 | this.props.context.store.dispatch(fetchAuth()); 79 | } 80 | 81 | render() { 82 | const store = this.props.context.store; 83 | // NOTE: If you need to add or modify header, footer etc. of the app, 84 | // please do that inside the Layout component. 85 | return ( 86 | 87 |
88 | {Children.only(this.props.children)} 89 | 90 |
91 |
92 | ); 93 | } 94 | 95 | } 96 | 97 | export default App; 98 | -------------------------------------------------------------------------------- /src/components/App/App.prod.js: -------------------------------------------------------------------------------- 1 | /** 2 | * React Starter Kit (https://www.reactstarterkit.com/) 3 | * 4 | * Copyright © 2014-present Kriasoft, LLC. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | import React, { Children, PropTypes } from 'react'; 11 | import { Provider } from 'react-redux'; 12 | import _ from 'lodash'; 13 | import uuid from 'uuid'; 14 | import restApi from '../../network/RestApi'; 15 | import { fetchAuth } from '../../actions/authActions'; 16 | 17 | const ContextType = { 18 | // Enables critical path CSS rendering 19 | // https://github.com/kriasoft/isomorphic-style-loader 20 | insertCss: PropTypes.func.isRequired, 21 | // Integrate Redux 22 | // http://redux.js.org/docs/basics/UsageWithReact.html 23 | store: PropTypes.shape({ 24 | subscribe: PropTypes.func.isRequired, 25 | dispatch: PropTypes.func.isRequired, 26 | getState: PropTypes.func.isRequired, 27 | }).isRequired, 28 | }; 29 | 30 | /** 31 | * The top-level React component setting context (global) variables 32 | * that can be accessed from all the child components. 33 | * 34 | * https://facebook.github.io/react/docs/context.html 35 | * 36 | * Usage example: 37 | * 38 | * const context = { 39 | * history: createBrowserHistory(), 40 | * store: createStore(), 41 | * }; 42 | * 43 | * ReactDOM.render( 44 | * 45 | * 46 | * 47 | * 48 | * , 49 | * container, 50 | * ); 51 | */ 52 | class App extends React.PureComponent { 53 | 54 | static propTypes = { 55 | context: PropTypes.shape(ContextType).isRequired, 56 | children: PropTypes.element.isRequired, 57 | }; 58 | 59 | static childContextTypes = ContextType; 60 | 61 | getChildContext() { 62 | return this.props.context; 63 | } 64 | 65 | componentDidMount() { 66 | let aQQGuid = localStorage.getItem('aQQ_guid'); 67 | if (_.isEmpty(aQQGuid) || aQQGuid.length < 10) { 68 | aQQGuid = uuid.v1(); 69 | localStorage.setItem('aQQ_guid', aQQGuid); 70 | } 71 | let sessid = sessionStorage.getItem('sessid'); 72 | if (_.isEmpty(sessid) || sessid.length < 10) { 73 | sessid = uuid.v1(); 74 | sessionStorage.setItem('sessid', sessid); 75 | } 76 | restApi.setUUID(sessid, aQQGuid); 77 | this.props.context.store.dispatch(fetchAuth()); 78 | } 79 | 80 | render() { 81 | const store = this.props.context.store; 82 | // NOTE: If you need to add or modify header, footer etc. of the app, 83 | // please do that inside the Layout component. 84 | return ( 85 | 86 |
87 | {Children.only(this.props.children)} 88 |
89 |
90 | ); 91 | } 92 | 93 | } 94 | 95 | export default App; 96 | -------------------------------------------------------------------------------- /src/components/App/index.js: -------------------------------------------------------------------------------- 1 | if (__DEV__ && process.env.BROWSER) { 2 | module.exports = require('./App.dev'); 3 | } else { 4 | module.exports = require('./App.prod'); 5 | } 6 | -------------------------------------------------------------------------------- /src/components/App/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "App", 3 | "version": "0.0.0", 4 | "private": true, 5 | "main": "./App.js" 6 | } 7 | -------------------------------------------------------------------------------- /src/components/ChangePassword/ChangePassword.css: -------------------------------------------------------------------------------- 1 | 2 | @import '../../components/variables.css'; 3 | 4 | .root { 5 | padding-left: 20px; 6 | padding-right: 20px; 7 | } 8 | 9 | .container { 10 | margin: 0 auto; 11 | padding: 4% 0 40px; 12 | max-width: 380px; 13 | min-height: 480px; 14 | } 15 | 16 | .formGroup { 17 | margin-bottom: 15px; 18 | } 19 | 20 | .label { 21 | display: inline; 22 | margin-bottom: 5px; 23 | font-weight: 700; 24 | padding-right: 20px; 25 | width: 20%; 26 | } 27 | 28 | .input { 29 | display: inline; 30 | box-sizing: border-box; 31 | padding: 10px 16px; 32 | width: 70%; 33 | height: 46px; 34 | outline: 0; 35 | border: 1px solid #ccc; 36 | border-radius: 0; 37 | background: #fff; 38 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); 39 | color: #616161; 40 | font-size: 18px; 41 | line-height: 1.3333333; 42 | transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s; 43 | } 44 | 45 | .input:focus { 46 | border-color: #0074c2; 47 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(0, 116, 194, 0.6); 48 | } 49 | 50 | .errorTip { 51 | color: red; 52 | margin-bottom: 20px; 53 | margin-left: 27%; 54 | } 55 | -------------------------------------------------------------------------------- /src/components/ChangePassword/ChangePassword.js: -------------------------------------------------------------------------------- 1 | 2 | import React, { PropTypes, Component } from 'react'; 3 | import { 4 | Col, 5 | ControlLabel, 6 | Form, 7 | FormGroup, 8 | FormControl, 9 | Checkbox, 10 | Button, 11 | Panel, 12 | } from 'react-bootstrap'; 13 | 14 | import _ from 'lodash'; 15 | 16 | class ChangePassword extends Component { 17 | static propTypes = { 18 | isFetching: PropTypes.bool, 19 | oldPassword: PropTypes.string, 20 | oldPasswordInputChange: PropTypes.func, 21 | newPassword: PropTypes.string, 22 | newPasswordInputChange: PropTypes.func, 23 | newPasswordConfirm: PropTypes.string, 24 | newPasswordConfirmInputChange: PropTypes.func, 25 | submit: PropTypes.func, 26 | error: PropTypes.object, 27 | }; 28 | 29 | static defaultProps = { 30 | isFetching: false, 31 | oldPassword: '', 32 | oldPasswordInputChange: (oldPassword)=>{}, 33 | newPassword: '', 34 | newPasswordInputChange: (newPassword)=>{}, 35 | newPasswordConfirm: '', 36 | newPasswordConfirmInputChange: (newPasswordConfirm)=>{}, 37 | submit: ()=>{}, 38 | error: {}, 39 | }; 40 | 41 | constructor(){ 42 | super(); 43 | this.state = {field1: false, field2: false, field3: false}; 44 | this.setOldPassword = this.setOldPassword.bind(this); 45 | this.setNewPassword = this.setNewPassword.bind(this); 46 | this.setNewPasswordConfirm = this.setNewPasswordConfirm.bind(this); 47 | } 48 | 49 | setOldPassword(event) { 50 | this.props.oldPasswordInputChange(event.target.value); 51 | } 52 | 53 | setNewPassword(event) { 54 | this.props.newPasswordInputChange(event.target.value); 55 | } 56 | 57 | setNewPasswordConfirm(event) { 58 | this.props.newPasswordConfirmInputChange(event.target.value); 59 | } 60 | 61 | render() { 62 | const self = this; 63 | let isValidate = true; 64 | let oldPasswordTips = ''; 65 | if (!this.props.oldPassword) { 66 | isValidate = false; 67 | oldPasswordTips = '请您输入旧密码'; 68 | } 69 | let newPasswordTips = ''; 70 | let newPasswordConfirmTips = ''; 71 | if (this.props.newPassword.length < 6) { 72 | newPasswordTips = '请您输入6~22位字符或数字' 73 | } 74 | if (!_.eq(this.props.newPassword, this.props.newPasswordConfirm)) { 75 | isValidate = false; 76 | newPasswordConfirmTips = '两次输入的密码不一致' 77 | } 78 | var disabled = true; 79 | if (!this.props.isFetching && isValidate){ 80 | disabled = false; 81 | } 82 | return ( 83 |
84 | 85 |
86 | 87 | 原密码 88 | this.setState({field1: true})} 94 | autoFocus 95 | /> 96 | 97 | 98 |
99 | { 100 | this.state.field1 ? 101 | oldPasswordTips 102 | : null 103 | } 104 |
105 |
106 | 107 | 新密码 108 | this.setState({field2: true})} 114 | /> 115 | 116 | 117 |
118 | { 119 | this.state.field2 ? 120 | newPasswordTips 121 | : null 122 | } 123 |
124 |
125 | 126 | 确认新密码 127 | this.setState({field3: true})} 133 | /> 134 | 135 | 136 |
137 | { 138 | this.state.field3 ? 139 | newPasswordConfirmTips 140 | : null 141 | } 142 |
143 |
144 | 145 |
146 | {_.get(this.props, 'error.message')} 147 |
148 |
149 | 150 | 163 | 164 |
165 |
166 |
167 | ); 168 | } 169 | } 170 | export default ChangePassword; 171 | -------------------------------------------------------------------------------- /src/components/ChangePassword/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ChangePassword", 3 | "version": "0.0.0", 4 | "private": true, 5 | "main": "./ChangePassword.js" 6 | } 7 | -------------------------------------------------------------------------------- /src/components/Countdown/Countdown.js: -------------------------------------------------------------------------------- 1 | import React, {PropTypes, Component} from 'react'; 2 | import _ from 'lodash'; 3 | 4 | export default class Countdown extends Component { 5 | 6 | static propTypes = { 7 | leftTime: PropTypes.number, 8 | timeoutCb: PropTypes.func, 9 | renderFunc: PropTypes.func.isRequired, 10 | renderRetryFunc: PropTypes.func.isRequired, 11 | level: PropTypes.number, 12 | second: PropTypes.number, 13 | }; 14 | 15 | static retryTimes = 0; 16 | 17 | static defaultProps = { 18 | leftTime: 0, 19 | timeoutCb: ()=> { 20 | }, 21 | renderFunc: ()=> { 22 | }, 23 | renderRetryFunc: (retryTimes)=> { 24 | }, 25 | level: 1, 26 | second: 1, 27 | }; 28 | 29 | constructor() { 30 | super(); 31 | Countdown.retryTimes = 0; 32 | this.state = {leftTime: 0}; 33 | this.leftTimeCount = this.leftTimeCount.bind(this); 34 | this.leftTimeSplite = this.leftTimeSplite.bind(this); 35 | } 36 | 37 | componentDidMount() { 38 | this.leftTimeCount(this.props.leftTime); 39 | } 40 | 41 | leftTimeCount(time) { 42 | this.setState({leftTime: time}); 43 | if (this.timer) { 44 | clearInterval(this.timer); 45 | } 46 | this.timer = setInterval(()=> { 47 | if (this.state.leftTime <= 0 && this.timer) { 48 | Countdown.retryTimes += 1; 49 | this.props.timeoutCb && this.props.timeoutCb(); 50 | clearInterval(this.timer); 51 | } else { 52 | this.setState({leftTime: this.state.leftTime - this.props.second}); 53 | } 54 | }, this.props.second * 1000); 55 | } 56 | 57 | componentWillUnmount() { 58 | this.timer && clearInterval(this.timer); 59 | } 60 | 61 | componentWillReceiveProps(props) { 62 | if (!_.eq(this.props.leftTime, props.leftTime)) { 63 | this.leftTimeCount(props.leftTime); 64 | } 65 | } 66 | 67 | render() { 68 | if (this.state.leftTime <= 0) { 69 | return this.props.renderRetryFunc(Countdown.retryTimes); 70 | } 71 | 72 | return this.props.renderFunc(this.leftTimeSplite(this.state.leftTime, this.props.level)); 73 | } 74 | 75 | leftTimeSplite(leftTime, showLevel=4){ 76 | var day = 0, hour = 0, minute = 0, second = 0;//时间默认值 77 | if (leftTime > 0) { 78 | if (showLevel >= 4) { 79 | day = Math.floor(leftTime / (60 * 60 * 24)); 80 | } 81 | if (showLevel >= 3) { 82 | hour = Math.floor(leftTime / (60 * 60)) - (day * 24); 83 | } 84 | if (showLevel >= 2) { 85 | minute = Math.floor(leftTime / 60) - (day * 24 * 60) - (hour * 60); 86 | } 87 | second = Math.floor(leftTime) - (day * 24 * 60 * 60) - (hour * 60 * 60) - (minute * 60); 88 | } 89 | return {day, hour, minute, second}; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/components/Countdown/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Countdown", 3 | "version": "0.0.0", 4 | "private": true, 5 | "main": "./Countdown.js" 6 | } 7 | -------------------------------------------------------------------------------- /src/components/Deployment/Deployment.css: -------------------------------------------------------------------------------- 1 | @import '../../components/variables.css'; 2 | 3 | .root { 4 | padding-left: 20px; 5 | padding-right: 20px; 6 | } 7 | 8 | .container { 9 | margin: 0 auto; 10 | padding: 0 0 40px; 11 | min-height: 480px; 12 | max-width: var(--max-content-width); 13 | } 14 | -------------------------------------------------------------------------------- /src/components/Deployment/Deployment.js: -------------------------------------------------------------------------------- 1 | 2 | import React, { PropTypes, Component } from 'react'; 3 | import {Breadcrumb, Table} from 'react-bootstrap'; 4 | import cx from 'classnames'; 5 | import _ from 'lodash'; 6 | import withStyles from 'isomorphic-style-loader/lib/withStyles'; 7 | import s from './Deployment.css'; 8 | import Link from '../Link'; 9 | 10 | class Deployment extends Component { 11 | static propTypes = { 12 | appName: PropTypes.string, 13 | deploymentName: PropTypes.string, 14 | }; 15 | 16 | static defaultProps = { 17 | appName: '', 18 | deploymentName: '', 19 | }; 20 | 21 | constructor() { 22 | super(); 23 | } 24 | 25 | 26 | render() { 27 | const self = this; 28 | const tipText = '暂无数据'; 29 | return ( 30 |
31 |
32 | 33 | 34 | 应用列表 35 | 36 | 37 | {this.props.appName} 38 | 39 | 40 | {this.props.deploymentName} 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 |
AppVersionPackageInfoInstall Metrics操作
55 |
56 |
57 | ); 58 | } 59 | } 60 | export default withStyles(s)(Deployment); 61 | -------------------------------------------------------------------------------- /src/components/Deployment/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Deployment", 3 | "version": "0.0.0", 4 | "private": true, 5 | "main": "./Deployment.js" 6 | } 7 | -------------------------------------------------------------------------------- /src/components/DevTools/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { createDevTools } from 'redux-devtools'; 3 | import DockMonitor from 'redux-devtools-dock-monitor'; 4 | import MultipleMonitors from 'redux-devtools-multiple-monitors'; 5 | import LogMonitor from 'redux-devtools-inspector'; 6 | import Dispatcher from 'redux-devtools-dispatch'; 7 | 8 | 9 | export default createDevTools( 10 | 15 | 16 | 17 | 18 | 19 | 20 | ); 21 | -------------------------------------------------------------------------------- /src/components/DevTools/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "DevTools", 3 | "version": "0.0.0", 4 | "private": true, 5 | "main": "./index.js" 6 | } 7 | -------------------------------------------------------------------------------- /src/components/Footer/Footer.css: -------------------------------------------------------------------------------- 1 | @import '../variables.css'; 2 | 3 | .root { 4 | /*position: absolute;*/ 5 | /*bottom: 0;*/ 6 | width: 100%; 7 | /* Set the fixed height of the footer here */ 8 | height: 60px; 9 | background-color: #222; 10 | border-color: #080808; 11 | } 12 | 13 | .container { 14 | margin: 0 auto; 15 | padding: 20px 15px; 16 | max-width: var(--max-content-width); 17 | text-align: center; 18 | } 19 | 20 | .text { 21 | color: rgba(255, 255, 255, 0.5); 22 | } 23 | 24 | .spacer { 25 | color: rgba(255, 255, 255, 0.3); 26 | } 27 | 28 | .text, 29 | .link { 30 | padding: 2px 5px; 31 | font-size: 1em; 32 | } 33 | 34 | .link, 35 | .link:active, 36 | .link:visited { 37 | color: rgba(255, 255, 255, 0.6); 38 | text-decoration: none; 39 | } 40 | 41 | .link:hover { 42 | color: rgba(255, 255, 255, 1); 43 | } 44 | -------------------------------------------------------------------------------- /src/components/Footer/Footer.js: -------------------------------------------------------------------------------- 1 | 2 | import React from 'react'; 3 | import withStyles from 'isomorphic-style-loader/lib/withStyles'; 4 | import s from './Footer.css'; 5 | import Link from '../Link'; 6 | 7 | function Footer() { 8 | return ( 9 |
10 |
11 | © CodePush Server 12 | · 13 | Home 14 | · 15 | Report an issue 16 |
17 |
18 | ); 19 | } 20 | 21 | export default withStyles(s)(Footer); 22 | -------------------------------------------------------------------------------- /src/components/Footer/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Footer", 3 | "version": "0.0.0", 4 | "private": true, 5 | "main": "./Footer.js" 6 | } 7 | -------------------------------------------------------------------------------- /src/components/Header/Header.css: -------------------------------------------------------------------------------- 1 | 2 | @import '../variables.css'; 3 | 4 | .brand { 5 | color: lightness(+10%)); 6 | text-decoration: none; 7 | font-size: 1.75em; /* ~28px */ 8 | } 9 | -------------------------------------------------------------------------------- /src/components/Header/Header.js: -------------------------------------------------------------------------------- 1 | 2 | import React, {PropTypes, Component} from 'react'; 3 | import withStyles from 'isomorphic-style-loader/lib/withStyles'; 4 | import _ from 'lodash'; 5 | import { 6 | Navbar, 7 | } from 'react-bootstrap'; 8 | import s from './Header.css'; 9 | import Link from '../Link'; 10 | import Navigation from '../Navigation'; 11 | 12 | 13 | class Header extends Component { 14 | static propTypes = { 15 | isAuth: PropTypes.bool, 16 | noNav: PropTypes.bool, 17 | }; 18 | 19 | static defaultProps = { 20 | isAuth: false, 21 | noNav: false 22 | }; 23 | 24 | render() { 25 | return ( 26 | 27 | 28 | 29 | 30 | CodePush Server 31 | 32 | 33 | 34 | 35 | {_.get(this.props, 'noNav') !== true ? : null} 36 | 37 | ); 38 | } 39 | } 40 | 41 | export default withStyles(s)(Header); 42 | -------------------------------------------------------------------------------- /src/components/Header/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Header", 3 | "version": "0.0.0", 4 | "private": true, 5 | "main": "./Header.js" 6 | } 7 | -------------------------------------------------------------------------------- /src/components/Home/Home.css: -------------------------------------------------------------------------------- 1 | 2 | @import '../../components/variables.css'; 3 | 4 | .root { 5 | padding-left: 20px; 6 | padding-right: 20px; 7 | } 8 | 9 | .container { 10 | margin: 0 auto; 11 | padding: 0 0 40px; 12 | max-width: var(--max-content-width); 13 | } 14 | -------------------------------------------------------------------------------- /src/components/Home/Home.js: -------------------------------------------------------------------------------- 1 | 2 | import React, { PropTypes, Component } from 'react'; 3 | import withStyles from 'isomorphic-style-loader/lib/withStyles'; 4 | import s from './Home.css'; 5 | 6 | class Home extends Component { 7 | render() { 8 | return ( 9 |
10 |
11 |
12 |
13 |
14 | ); 15 | } 16 | } 17 | export default withStyles(s)(Home); 18 | -------------------------------------------------------------------------------- /src/components/Home/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Home", 3 | "version": "0.0.0", 4 | "private": true, 5 | "main": "./Home.js" 6 | } 7 | -------------------------------------------------------------------------------- /src/components/Html.js: -------------------------------------------------------------------------------- 1 | /** 2 | * React Starter Kit (https://www.reactstarterkit.com/) 3 | * 4 | * Copyright © 2014-present Kriasoft, LLC. All rights reserved. 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.txt file in the root directory of this source tree. 8 | */ 9 | 10 | import React, { PropTypes } from 'react'; 11 | import serialize from 'serialize-javascript'; 12 | import { analytics } from '../config'; 13 | 14 | class Html extends React.Component { 15 | static propTypes = { 16 | title: PropTypes.string.isRequired, 17 | description: PropTypes.string.isRequired, 18 | styles: PropTypes.arrayOf(PropTypes.shape({ 19 | id: PropTypes.string.isRequired, 20 | cssText: PropTypes.string.isRequired, 21 | }).isRequired), 22 | scripts: PropTypes.arrayOf(PropTypes.string.isRequired), 23 | // eslint-disable-next-line react/forbid-prop-types 24 | state: PropTypes.object, 25 | children: PropTypes.string.isRequired, 26 | }; 27 | 28 | static defaultProps = { 29 | styles: [], 30 | scripts: [], 31 | state: null, 32 | }; 33 | 34 | render() { 35 | const { title, description, styles, scripts, state, children } = this.props; 36 | return ( 37 | 38 | 39 | 40 | 41 | {title} 42 | 43 | 44 | 45 | 46 | {styles.map(style => 47 |