├── .dockerignore ├── .gitignore ├── .jshintrc ├── .travis.yml ├── Dockerfile ├── LICENCE.txt ├── README.md ├── changeLog.md ├── dispatch.js ├── docker ├── config.prod.ts └── nginx.conf ├── package-lock.json ├── package.json ├── public ├── favicon.ico ├── favicon.png ├── index.html └── logo.svg ├── rap2-dolores.release ├── scripts ├── app.js ├── openChrome.applescript └── worker.js ├── src ├── actions │ ├── account.ts │ ├── analytics.ts │ ├── common.ts │ ├── interface.ts │ ├── module.ts │ ├── organization.ts │ ├── property.ts │ ├── repository.ts │ ├── rootAction.ts │ └── types.ts ├── assets │ ├── README.md │ ├── components.css.map │ ├── components.sass │ ├── fonts.css.map │ ├── fonts.sass │ ├── index.css.map │ ├── index.sass │ ├── shortcuts.css.map │ ├── shortcuts.sass │ ├── theme.css.map │ ├── theme.sass │ ├── variables.css.map │ └── variables.sass ├── components │ ├── account │ │ ├── EditMyAccountDialog.tsx │ │ ├── FindpwdForm.css.map │ │ ├── FindpwdForm.sass │ │ ├── FindpwdForm.tsx │ │ ├── Index.tsx │ │ ├── LoginForm.css.map │ │ ├── LoginForm.sass │ │ ├── LoginForm.tsx │ │ ├── MyAccountView.tsx │ │ ├── MySettings.tsx │ │ ├── MySettingsView.tsx │ │ ├── Navigation.tsx │ │ ├── RegisterForm.css.map │ │ ├── RegisterForm.sass │ │ ├── RegisterForm.tsx │ │ ├── ResetForm.css.map │ │ ├── ResetForm.sass │ │ ├── ResetpwdForm.tsx │ │ ├── ThemeChangeOverlay.tsx │ │ ├── UpdateForm.css.map │ │ ├── UpdateForm.sass │ │ ├── User.tsx │ │ ├── UserList.css.map │ │ ├── UserList.sass │ │ └── UserList.tsx │ ├── api │ │ ├── API.css.map │ │ ├── API.sass │ │ └── API.tsx │ ├── checker │ │ ├── Checker.css.map │ │ ├── Checker.sass │ │ └── Checker.tsx │ ├── common │ │ ├── ConfirmDialog.tsx │ │ ├── Footer.css.map │ │ ├── Footer.sass │ │ ├── Footer.tsx │ │ ├── GlobalStyles.tsx │ │ ├── Header.css.map │ │ ├── Header.tsx │ │ ├── LoadingButton.tsx │ │ ├── Message.tsx │ │ ├── MuiTheme.tsx │ │ ├── Navigation.tsx │ │ ├── NoData.tsx │ │ ├── Select.tsx │ │ ├── Transition.tsx │ │ ├── UserList.tsx │ │ ├── nprogress.css.map │ │ └── nprogress.sass │ ├── editor │ │ ├── DefaultValueModal.tsx │ │ ├── DuplicatedInterfacesWarning.tsx │ │ ├── HistoryLogDrawer.tsx │ │ ├── Importer.tsx │ │ ├── InterfaceEditor.tsx │ │ ├── InterfaceEditorToolbar.tsx │ │ ├── InterfaceForm.tsx │ │ ├── InterfaceList.css.map │ │ ├── InterfaceList.sass │ │ ├── InterfaceList.tsx │ │ ├── InterfacePreviewer.tsx │ │ ├── InterfaceSummary.css.map │ │ ├── InterfaceSummary.sass │ │ ├── InterfaceSummary.tsx │ │ ├── ModuleForm.tsx │ │ ├── ModuleList.tsx │ │ ├── MoveInterfaceForm.tsx │ │ ├── MoveModuleForm.tsx │ │ ├── PropertyForm.tsx │ │ ├── PropertyList.css.map │ │ ├── PropertyList.sass │ │ ├── PropertyList.tsx │ │ ├── RapperInstallerModal.tsx │ │ ├── RepositoryEditor.css.map │ │ ├── RepositoryEditor.sass │ │ ├── RepositoryEditor.tsx │ │ └── RepositorySearcher.tsx │ ├── home │ │ ├── AboutView.tsx │ │ ├── Home.css.map │ │ ├── Home.sass │ │ ├── Home.tsx │ │ ├── JoinedRepositoriesCard.tsx │ │ ├── LogsCard.tsx │ │ └── OwnedRepositoriesCard.tsx │ ├── layout │ │ ├── Logo.tsx │ │ └── MainMenu.tsx │ ├── organization │ │ ├── AllOrganizationList.tsx │ │ ├── JoinedOrganizationList.tsx │ │ ├── Organization.css.map │ │ ├── Organization.sass │ │ ├── Organization.tsx │ │ ├── OrganizationForm.tsx │ │ ├── OrganizationList.tsx │ │ ├── OrganizationListParts.tsx │ │ └── OrganizationRepositoryList.tsx │ ├── repository │ │ ├── AllRepositoryList.tsx │ │ ├── ExportPostmanForm.tsx │ │ ├── ImportRepositoryForm.css.map │ │ ├── ImportRepositoryForm.sass │ │ ├── ImportRepositoryForm.tsx │ │ ├── ImportSwaggerRepositoryForm.css.map │ │ ├── ImportSwaggerRepositoryForm.sass │ │ ├── ImportSwaggerRepositoryForm.tsx │ │ ├── JoinedRepositoryList.tsx │ │ ├── Repository.css.map │ │ ├── Repository.sass │ │ ├── Repository.tsx │ │ ├── RepositoryForm.tsx │ │ ├── RepositoryList.tsx │ │ └── RepositoryListParts.tsx │ ├── status │ │ ├── Status.css.map │ │ ├── Status.sass │ │ └── Status.tsx │ ├── tester │ │ ├── Tester.css.map │ │ ├── Tester.sass │ │ └── Tester.tsx │ └── utils │ │ ├── CopyToClipboard.css.map │ │ ├── CopyToClipboard.sass │ │ ├── CopyToClipboard.tsx │ │ ├── CustomScroll.tsx │ │ ├── Dialog.css.map │ │ ├── Dialog.sass │ │ ├── Dialog.tsx │ │ ├── DialogController.tsx │ │ ├── Form.tsx │ │ ├── MembersInput.tsx │ │ ├── Modal.css.map │ │ ├── Modal.sass │ │ ├── Modal.tsx │ │ ├── ModalExample.tsx │ │ ├── NoMatch.tsx │ │ ├── Pagination.css.map │ │ ├── Pagination.sass │ │ ├── Pagination.tsx │ │ ├── Popover.css.map │ │ ├── Popover.sass │ │ ├── Popover.tsx │ │ ├── PopoverExample.tsx │ │ ├── Portal.tsx │ │ ├── PropertyEditor.css.map │ │ ├── PropertyEditor.sass │ │ ├── PropertyEditor.tsx │ │ ├── RChart.tsx │ │ ├── RCodeMirror.css.map │ │ ├── RCodeMirror.sass │ │ ├── RCodeMirror.tsx │ │ ├── RModal.css.map │ │ ├── RModal.sass │ │ ├── RModal.tsx │ │ ├── RParsley.css.map │ │ ├── RParsley.sass │ │ ├── RParsley.tsx │ │ ├── RSortable.css.map │ │ ├── RSortable.sass │ │ ├── RSortable.tsx │ │ ├── RSortableExample.tsx │ │ ├── RadioList.css.map │ │ ├── RadioList.sass │ │ ├── RadioList.tsx │ │ ├── SmartTextarea.tsx │ │ ├── SmartTextareaExample.tsx │ │ ├── Spin.css.map │ │ ├── Spin.sass │ │ ├── Spin.tsx │ │ ├── SpinExample.tsx │ │ ├── SpinInline.tsx │ │ ├── TagsInput.css.map │ │ ├── TagsInput.sass │ │ ├── TagsInput.tsx │ │ ├── TagsInputExample.tsx │ │ ├── Tree.ts │ │ ├── Utils.css.map │ │ ├── Utils.sass │ │ ├── Utils.tsx │ │ └── index.ts ├── config │ ├── config.dev.ts │ ├── config.prod.ts │ └── index.ts ├── family │ ├── Bundle.tsx │ ├── Family.tsx │ ├── GlobalProvider.tsx │ ├── UIConst.ts │ ├── classNames.ts │ ├── handleLocation.ts │ ├── index.ts │ ├── loggerMiddleware.ts │ └── start.tsx ├── hooks │ ├── useAlert.ts │ └── useConfirm.ts ├── i18n │ └── TODO ├── index.tsx ├── react-app-env.d.ts ├── relatives │ ├── AccountRelative.ts │ ├── EditorRelative.ts │ ├── HomeRelative.ts │ ├── OrganizationRelative.ts │ ├── RepositoryRelative.tsx │ ├── StatusRelative.ts │ ├── effects │ │ ├── commonSagas.ts │ │ ├── interface.ts │ │ ├── module.ts │ │ ├── organization.ts │ │ ├── property.ts │ │ └── repository.ts │ └── services │ │ ├── Account.ts │ │ ├── Editor.ts │ │ ├── Organization.ts │ │ ├── Repository.ts │ │ ├── Status.ts │ │ └── constant.ts ├── routes.tsx ├── selectors │ ├── interface.ts │ └── router.ts ├── types │ ├── index.d.ts │ └── redux-api-middleware.d.ts └── utils │ ├── DateUtility.ts │ ├── ElementInViewport.ts │ ├── ImageUtils.ts │ ├── URLUtils.ts │ └── consts.ts ├── tsconfig.json └── tslint.json /.dockerignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # misc 10 | .DS_Store 11 | .env 12 | npm-debug.log* 13 | yarn-debug.log* 14 | yarn-error.log* 15 | 16 | # css 17 | src/**/*.css 18 | build 19 | build.zip 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # misc 10 | .DS_Store 11 | .env 12 | npm-debug.log* 13 | yarn-debug.log* 14 | yarn-error.log* 15 | 16 | # css 17 | src/**/*.css 18 | build 19 | build.zip 20 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | cache: 4 | directories: 5 | - node_modules 6 | - $HOME/.npm 7 | 8 | notifications: 9 | email: false 10 | 11 | node_js: 12 | - '8' 13 | 14 | before_install: 15 | - npm i -g npm@^5.5.1 16 | 17 | script: 18 | - npm install 19 | - npm run build 20 | - npm run test 21 | 22 | after_success: 23 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # BUILDING 2 | FROM node:lts-alpine AS builder 3 | 4 | WORKDIR /app 5 | 6 | COPY . ./ 7 | 8 | # 替换后端端口地址配置文件 9 | COPY docker/config.prod.ts ./src/config/config.prod.ts 10 | 11 | # 在国内打开下面一行加速 12 | #RUN npm config set registry https://registry.npmmirror.com/ && npm config set sass-binary-site http://npm.taobao.org/mirrors/node-sass 13 | 14 | RUN npm install && \ 15 | npm install typescript -g && \ 16 | npm run lint && \ 17 | npm run build 18 | 19 | # nginx 20 | FROM nginx:stable-alpine 21 | 22 | COPY --from=builder app/build /dolores 23 | RUN rm /etc/nginx/conf.d/default.conf 24 | COPY docker/nginx.conf /etc/nginx/conf.d/ -------------------------------------------------------------------------------- /LICENCE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2018 Alibaba 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RAP2-DOLORES CE version (front-end static build) 2 | 3 | [![Build Status](https://travis-ci.org/thx/rap2-dolores.svg?branch=master)](https://travis-ci.org/thx/rap2-dolores) 4 | 5 | ### Intro 6 | 7 | RAP2 is a new project based on [RAP1](https://github.com/thx/RAP). It has two components: 8 | RAP2是在RAP1基础上重做的新项目,它包含两个组件(对应两个Github Repository)。 9 | 10 | * rap2-delos: back-end data API server based on Koa + MySQL [link](http://github.com/thx/rap2-delos) 11 | * rap2-dolores: front-end static build based on React [link](http://github.com/thx/rap2-dolores) 12 | 13 | * rap2-delos: 后端数据API服务器,基于Koa + MySQL[link](http://github.com/thx/rap2-delos) 14 | * rap2-dolores: 前端静态资源,基于React [link](http://github.com/thx/rap2-dolores) 15 | 16 | ### Resources 17 | 18 | * [Official Site 官网: rap2.taobao.org](http://rap2.taobao.org) 19 | * DingDing Group ID 钉钉群: 31626736 (二群,一群已满) 20 | 21 | ## Deployment 部署 22 | 23 | ### development 开发模式 24 | 25 | ```sh 26 | 27 | # initialize 初始化 28 | npm install 29 | 30 | # config development mode server API path in /src/config/config.dev.js 31 | # 配置开发模式后端服务器的地址。 /src/config/config.dev.js 32 | 33 | # test cases 测试用例 34 | npm run test 35 | 36 | # will watch & serve automatically 会自动监视改变后重新编译 37 | npm run dev 38 | 39 | ``` 40 | 41 | ### production 42 | 43 | ```sh 44 | # 1. config server API path in /src/config/config.prod.js(production config file) 45 | # 1. 配置后端服务器的地址。 /src/config/config.prod.js(生产模式配置文件) 46 | 47 | # 2. produce react production package 48 | # 2. 编译React生产包 49 | npm run build 50 | 51 | # 3. use serve or nginx to serve the static build directory 52 | # 3. 用serve命令或nginx服务器路由到编译产出的build文件夹作为静态服务器即可 53 | 54 | serve -s ./build -p 80 55 | ``` 56 | 57 | ## Author 58 | 59 | * Owner: Alimama FE Team 60 | * Author: 61 | * Before v2.3: all by [@Nuysoft](https://github.com/nuysoft/), creator of [mockjs](mockjs.com). 62 | * v2.4+ / CE version: [Bosn](http://github.com/bosn/)(creator of [RAP1](https://github.com/thx/RAP)) [Nuysoft](https://github.com/nuysoft/) 63 | * We are looking for more and more contributors :) 64 | 65 | 66 | ### Tech Arch 67 | 68 | * Front-end (rap2-dolores) 69 | * React / Redux / Saga / Router 70 | * Mock.js 71 | * SASS / Bootstrap 4 beta 72 | * server: nginx 73 | * Back-end (rap2-delos) 74 | * Koa 75 | * Sequelize 76 | * MySQL 77 | * Server 78 | * server: node 79 | -------------------------------------------------------------------------------- /changeLog.md: -------------------------------------------------------------------------------- 1 | ### 2021-01-28 2 | 3 | * 修复TS错误 4 | * 增加`content-type`的显示 关联 [issue #766](https://github.com/thx/rap2-delos/issues/766) 5 | * 增加接口导出功能,导出后可导入到任何仓库 6 | * 修复社区中的各种问题 7 | -------------------------------------------------------------------------------- /dispatch.js: -------------------------------------------------------------------------------- 1 | process.env.NODE_ENV = 'production' 2 | 3 | // https://nodejs.org/api/cluster.html 4 | // https://github.com/node-modules/graceful/blob/master/example/express_with_cluster/dispatch.js 5 | // http://gitlab.alibaba-inc.com/mm/fb/blob/master/dispatch.js 6 | 7 | let cluster = require('cluster') 8 | let path = require('path') 9 | let now = () => new Date().toISOString().replace(/T/, ' ').replace(/Z/, '') 10 | 11 | cluster.setupMaster({ 12 | exec: path.join(__dirname, 'scripts/worker.js') 13 | }) 14 | 15 | if (cluster.isMaster) { 16 | const maxSize = +process.env.SIGMA_MAX_PROCESSORS_LIMIT || +process.env.AJDK_MAX_PROCESSORS_LIMIT || require('os').cpus().length 17 | for (let i = 0; i < maxSize; i++) { 18 | cluster.fork() 19 | } 20 | cluster.on('listening', (worker, address) => { 21 | console.error(`[${now()}] master#${process.pid} worker#${worker.process.pid} is now connected to ${address.address}:${address.port}.`) 22 | }) 23 | cluster.on('disconnect', (worker) => { 24 | console.error(`[${now()}] master#${process.pid} worker#${worker.process.pid} has disconnected.`) 25 | }) 26 | cluster.on('exit', (worker, code, signal) => { 27 | console.error(`[${now()}] master#${process.pid} worker#${worker.process.pid} died (${signal || code}). restarting...`) 28 | cluster.fork() 29 | }) 30 | } 31 | -------------------------------------------------------------------------------- /docker/config.prod.ts: -------------------------------------------------------------------------------- 1 | const config: IConfig = { 2 | serve: `http://${window.location.hostname}:38080`, 3 | keys: ['some secret hurr'], 4 | session: { 5 | key: 'koa:sess', 6 | }, 7 | } 8 | 9 | export default config 10 | -------------------------------------------------------------------------------- /docker/nginx.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 38081; 3 | server_name localhost; 4 | 5 | root /dolores; 6 | 7 | location / { 8 | try_files $uri /index.html; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thx/rap2-dolores/f0c2390be22a9bc92a74399465e3ee2e764be58b/public/favicon.ico -------------------------------------------------------------------------------- /public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thx/rap2-dolores/f0c2390be22a9bc92a74399465e3ee2e764be58b/public/favicon.png -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 16 | RAP接口管理平台 17 | 18 | 19 |
20 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /rap2-dolores.release: -------------------------------------------------------------------------------- 1 | # 1. 你可以直接编辑本文件的内容,或者通过工具来帮你校验合法性和自动生成,请点击:http://aliwing.alibaba-inc.com/apprelease/home.htm 2 | # 2. 更多关于Release文件的规范和约定,请点击: http://docs.alibaba-inc.com/pages/viewpage.action?pageId=252891532 3 | 4 | # 构建源码语言类型 5 | code.language=nodejs 6 | 7 | -------------------------------------------------------------------------------- /scripts/app.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const Koa = require('koa') 3 | const serve = require('koa-static') 4 | const Router = require('koa-router') 5 | const session = require('koa-session') 6 | const config = require('../src/config') 7 | const app = new Koa() 8 | 9 | app.keys = config.keys 10 | app.use(session(config.session, app)) 11 | 12 | app.use(async (ctx, next) => { 13 | const start = new Date() 14 | await next() 15 | const ms = new Date() - start 16 | console.log(`${ctx.method} ${ctx.url} - ${ms}ms`) 17 | }) 18 | app.use(async (ctx, next) => { 19 | await next() 20 | if (ctx.response.body && ctx.response.body.url) { 21 | ctx.response.body = JSON.stringify(ctx.response.body, null, 4) 22 | } 23 | }) 24 | 25 | app.use(serve('build')) 26 | 27 | let router = new Router() 28 | 29 | router.get('/check.node', (ctx) => { 30 | ctx.body = 'success' 31 | }) 32 | 33 | router.get('/status.taobao', (ctx) => { 34 | ctx.body = 'success' 35 | }) 36 | 37 | router.get('/test/test.status', (ctx) => { 38 | ctx.body = 'success' 39 | }) 40 | 41 | router.get('/env', (ctx, next) => { 42 | ctx.body = process.env.NODE_ENV 43 | }) 44 | 45 | router.get('/delos', (ctx, next) => { 46 | ctx.body = process.env.RAP2_DELOS 47 | }) 48 | router.get('/account/info', (ctx) => { 49 | ctx.body = { 50 | url: ctx.request.url, 51 | data: ctx.session.id ? { 52 | id: ctx.session.id, 53 | empId: ctx.session.empId, 54 | fullname: ctx.session.fullname, 55 | email: ctx.session.email 56 | } : undefined 57 | } 58 | }) 59 | 60 | router.get('/*', (ctx) => { 61 | ctx.type = 'html' 62 | ctx.body = fs.createReadStream('build/index.html') 63 | }) 64 | 65 | app.use(router.routes()) 66 | 67 | module.exports = app 68 | -------------------------------------------------------------------------------- /scripts/openChrome.applescript: -------------------------------------------------------------------------------- 1 | (* 2 | Copyright (c) 2015-present, Facebook, Inc. 3 | All rights reserved. 4 | 5 | This source code is licensed under the BSD-style license found in the 6 | -- LICENSE file in the root directory of this source tree. An additional grant 7 | of patent rights can be found in the PATENTS file in the same directory. 8 | *) 9 | 10 | property targetTab: null 11 | property targetTabIndex: -1 12 | property targetWindow: null 13 | 14 | on run argv 15 | set theURL to item 1 of argv 16 | 17 | tell application "Chrome" 18 | 19 | if (count every window) = 0 then 20 | make new window 21 | end if 22 | 23 | -- 1: Looking for tab running debugger 24 | -- then, Reload debugging tab if found 25 | -- then return 26 | set found to my lookupTabWithUrl(theURL) 27 | if found then 28 | set targetWindow's active tab index to targetTabIndex 29 | tell targetTab to reload 30 | tell targetWindow to activate 31 | set index of targetWindow to 1 32 | return 33 | end if 34 | 35 | -- 2: Looking for Empty tab 36 | -- In case debugging tab was not found 37 | -- We try to find an empty tab instead 38 | set found to my lookupTabWithUrl("chrome://newtab/") 39 | if found then 40 | set targetWindow's active tab index to targetTabIndex 41 | set URL of targetTab to theURL 42 | tell targetWindow to activate 43 | return 44 | end if 45 | 46 | -- 3: Create new tab 47 | -- both debugging and empty tab were not found 48 | -- make a new tab with url 49 | tell window 1 50 | activate 51 | make new tab with properties {URL:theURL} 52 | end tell 53 | end tell 54 | end run 55 | 56 | -- Function: 57 | -- Lookup tab with given url 58 | -- if found, store tab, index, and window in properties 59 | -- (properties were declared on top of file) 60 | on lookupTabWithUrl(lookupUrl) 61 | tell application "Chrome" 62 | -- Find a tab with the given url 63 | set found to false 64 | set theTabIndex to -1 65 | repeat with theWindow in every window 66 | set theTabIndex to 0 67 | repeat with theTab in every tab of theWindow 68 | set theTabIndex to theTabIndex + 1 69 | if (theTab's URL as string) contains lookupUrl then 70 | -- assign tab, tab index, and window to properties 71 | set targetTab to theTab 72 | set targetTabIndex to theTabIndex 73 | set targetWindow to theWindow 74 | set found to true 75 | exit repeat 76 | end if 77 | end repeat 78 | 79 | if found then 80 | exit repeat 81 | end if 82 | end repeat 83 | end tell 84 | return found 85 | end lookupTabWithUrl 86 | -------------------------------------------------------------------------------- /scripts/worker.js: -------------------------------------------------------------------------------- 1 | // https://github.com/node-modules/graceful 2 | let graceful = require('graceful') 3 | let now = () => new Date().toISOString().replace(/T/, ' ').replace(/Z/, '') 4 | let app = require('./app') 5 | let PORT = 8080 6 | let server = app.listen(PORT, () => { 7 | console.log(`[${now()}] worker#${process.pid} rap2-dolores is running as ${PORT}`) 8 | }) 9 | 10 | graceful({ 11 | servers: [server], 12 | killTimeout: '10s', 13 | error: (err, throwErrorCount) => { 14 | if (err.message) err.message += ` (uncaughtException throw ${throwErrorCount} times on pid:${process.pid})` 15 | console.error(`[${now()}] worker#${process.pid}] ${err.message}`) 16 | } 17 | }) 18 | -------------------------------------------------------------------------------- /src/actions/analytics.ts: -------------------------------------------------------------------------------- 1 | // 获取平台计数信息 2 | export const fetchCounter = () => ({ type: 'ANALYTICS_COUNTER_FETCH' }) 3 | export const fetchCounterSucceeded = (counter: any) => ({ type: 'ANALYTICS_COUNTER_FETCH_SUCCEEDED', counter }) 4 | export const fetchCounterFailed = (message: any) => ({ type: 'ANALYTICS_COUNTER_FETCH_FAILED', message }) 5 | 6 | export const fetchAnalyticsRepositoriesCreated = ( 7 | { start, end } = { start: '', end: '' } 8 | ) => ({ type: 'ANALYTICS_REPOSITORIES_CREATED', start, end }) 9 | export const fetchAnalyticsRepositoriesCreatedSucceeded = (analytics: any) => ({ type: 'ANALYTICS_REPOSITORIES_CREATED_SUCCEEDED', analytics }) 10 | export const fetchAnalyticsRepositoriesCreatedFailed = (message: any) => ({ type: 'ANALYTICS_REPOSITORIES_CREATED_FAILED', message }) 11 | 12 | export const fetchAnalyticsRepositoriesUpdated = ( 13 | { start, end } = { start: '', end: '' } 14 | ) => ({ type: 'ANALYTICS_REPOSITORIES_UPDATED', start, end }) 15 | export const fetchAnalyticsRepositoriesUpdatedSucceeded = (analytics: any) => ({ type: 'ANALYTICS_REPOSITORIES_UPDATED_SUCCEEDED', analytics }) 16 | export const fetchAnalyticsRepositoriesUpdatedFailed = (message: any) => ({ type: 'ANALYTICS_REPOSITORIES_UPDATED_FAILED', message }) 17 | 18 | export const fetchAnalyticsUsersActivation = ( 19 | { start, end } = { start: '', end: '' } 20 | ) => ({ type: 'ANALYTICS_USERS_ACTIVATION', start, end }) 21 | export const fetchAnalyticsUsersActivationSucceeded = (analytics: any) => ({ type: 'ANALYTICS_USERS_ACTIVATION_SUCCEEDED', analytics }) 22 | export const fetchAnalyticsUsersActivationFailed = (message: any) => ({ type: 'ANALYTICS_USERS_ACTIVATION_FAILED', message }) 23 | 24 | export const fetchAnalyticsRepositoriesActivation = ( 25 | { start, end } = { start: '', end: '' } 26 | ) => ({ type: 'ANALYTICS_REPOSITORIES_ACTIVATION', start, end }) 27 | export const fetchAnalyticsRepositoriesActivationSucceeded = (analytics: any) => ({ type: 'ANALYTICS_REPOSITORIES_ACTIVATION_SUCCEEDED', analytics }) 28 | export const fetchAnalyticsRepositoriesActivationFailed = (message: any) => ({ type: 'ANALYTICS_REPOSITORIES_ACTIVATION_FAILED', message }) 29 | -------------------------------------------------------------------------------- /src/actions/common.ts: -------------------------------------------------------------------------------- 1 | import { MSG_TYPE } from '../components/common/Message' 2 | 3 | export const refresh = () => ({ type: 'REFRESH' }) 4 | export type SHOW_MESSAGE = 'shared/SHOW_MESSAGE' 5 | export const SHOW_MESSAGE: SHOW_MESSAGE = 'shared/SHOW_MESSAGE' 6 | 7 | export function showMessage(message: string, type?: MSG_TYPE): ShowMessageAction { 8 | let t: MSG_TYPE 9 | if (type === undefined) { 10 | t = MSG_TYPE.INFO 11 | } else { 12 | t = type 13 | } 14 | 15 | const result = { 16 | type: SHOW_MESSAGE, 17 | payload: { 18 | message, 19 | type: t, 20 | }, 21 | } 22 | return result 23 | } 24 | 25 | export { MSG_TYPE } from 'components/common/Message' 26 | 27 | export interface ShowMessageAction { 28 | type: SHOW_MESSAGE 29 | payload: { 30 | message: string 31 | type: MSG_TYPE 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/actions/interface.ts: -------------------------------------------------------------------------------- 1 | export const addInterface = (itf: any, onResolved: any) => ({ 2 | type: 'INTERFACE_ADD', 3 | interface: itf, 4 | onResolved, 5 | }) 6 | 7 | export const addInterfaceSucceeded = (payload: any) => ({ 8 | type: 'INTERFACE_ADD_SUCCEEDED', 9 | payload, 10 | }) 11 | export const addInterfaceFailed = (message: any) => ({ 12 | type: 'INTERFACE_ADD_FAILED', 13 | message, 14 | }) 15 | 16 | export const fetchInterface = (id: number, onResolved: any) => ({ 17 | type: 'INTERFACE_FETCH', 18 | id, 19 | onResolved, 20 | }) 21 | 22 | export const fetchInterfaceSucceeded = (payload: any) => ({ 23 | type: 'INTERFACE_FETCH_SUCCEEDED', 24 | payload, 25 | }) 26 | export const fetchInterfaceFailed = (message: any) => ({ 27 | type: 'INTERFACE_FETCH_FAILED', 28 | message, 29 | }) 30 | 31 | export const updateInterface = (itf: any, onResolved: any) => ({ 32 | type: 'INTERFACE_UPDATE', 33 | interface: itf, 34 | onResolved, 35 | }) 36 | export const updateInterfaceSucceeded = (payload: any) => ({ 37 | type: 'INTERFACE_UPDATE_SUCCEEDED', 38 | payload, 39 | }) 40 | export const updateInterfaceFailed = (message: any) => ({ 41 | type: 'INTERFACE_UPDATE_FAILED', 42 | message, 43 | }) 44 | 45 | export const moveInterface = (params: any, onResolved: any) => ({ 46 | type: 'INTERFACE_MOVE', 47 | params, 48 | onResolved, 49 | }) 50 | export const moveInterfaceSucceeded = () => ({ 51 | type: 'INTERFACE_MOVE_SUCCEEDED', 52 | }) 53 | export const moveInterfaceFailed = (message: any) => ({ 54 | type: 'INTERFACE_MOVE_FAILED', 55 | message, 56 | }) 57 | 58 | export const deleteInterface = (id: any, onResolved: any) => ({ 59 | type: 'INTERFACE_DELETE', 60 | id, 61 | onResolved, 62 | }) 63 | export const deleteInterfaceSucceeded = (payload: any) => ({ 64 | type: 'INTERFACE_DELETE_SUCCEEDED', 65 | payload, 66 | }) 67 | export const deleteInterfaceFailed = (message: any) => ({ 68 | type: 'INTERFACE_DELETE_FAILED', 69 | message, 70 | }) 71 | 72 | export const fetchInterfaceCount = () => ({ 73 | type: 'INTERFACE_COUNT_FETCH', 74 | }) 75 | export const fetchInterfaceCountSucceeded = (count: any) => ({ 76 | type: 'INTERFACE_COUNT_FETCH_SUCCEEDED', 77 | count, 78 | }) 79 | export const fetchInterfaceCountFailed = (message: any) => ({ 80 | type: 'INTERFACE_COUNT_FETCH_FAILED', 81 | message, 82 | }) 83 | 84 | export const lockInterface = (id: any, onResolved?: any) => ({ 85 | type: 'INTERFACE_LOCK', 86 | id, 87 | onResolved, 88 | }) 89 | export const lockInterfaceSucceeded = (itfId: any, locker: any) => ({ 90 | type: 'INTERFACE_LOCK_SUCCEEDED', 91 | payload: { 92 | itfId, 93 | locker, 94 | }, 95 | }) 96 | export const lockInterfaceFailed = (message: any) => ({ 97 | type: 'INTERFACE_LOCK_FAILED', 98 | message, 99 | }) 100 | 101 | export const unlockInterface = (id: any, onResolved?: any) => ({ 102 | type: 'INTERFACE_UNLOCK', 103 | id, 104 | onResolved, 105 | }) 106 | export const unlockInterfaceSucceeded = (itfId: any) => ({ 107 | type: 'INTERFACE_UNLOCK_SUCCEEDED', 108 | payload: { 109 | itfId, 110 | }, 111 | }) 112 | export const unlockInterfaceFailed = (message: any) => ({ 113 | type: 'INTERFACE_UNLOCK_FAILED', 114 | message, 115 | }) 116 | 117 | export const sortInterfaceList = (ids: any, moduleId: number, onResolved: any) => ({ 118 | type: 'INTERFACE_LIST_SORT', 119 | ids, 120 | moduleId, 121 | onResolved, 122 | }) 123 | export const sortInterfaceListSucceeded = (count: any, ids: any, moduleId: number) => ({ 124 | type: 'INTERFACE_LIST_SORT_SUCCEEDED', 125 | count, 126 | ids, 127 | moduleId, 128 | }) 129 | export const sortInterfaceListFailed = (message: any) => ({ 130 | type: 'INTERFACE_LIST_SORT_FAILED', 131 | message, 132 | }) 133 | -------------------------------------------------------------------------------- /src/actions/module.ts: -------------------------------------------------------------------------------- 1 | export const addModule = (module: any, onResolved: any) => ({ 2 | type: 'MODULE_ADD', 3 | module, 4 | onResolved, 5 | }) 6 | export const addModuleSucceeded = (module: any) => ({ 7 | type: 'MODULE_ADD_SUCCEEDED', 8 | module, 9 | }) 10 | export const addModuleFailed = (message: any) => ({ 11 | type: 'MODULE_ADD_FAILED', 12 | message, 13 | }) 14 | 15 | export const updateModule = (module: any, onResolved: any) => ({ 16 | type: 'MODULE_UPDATE', 17 | module, 18 | onResolved, 19 | }) 20 | export const updateModuleSucceeded = (payload: any) => ({ 21 | type: 'MODULE_UPDATE_SUCCEEDED', 22 | payload, 23 | }) 24 | export const updateModuleFailed = (message: any) => ({ 25 | type: 'MODULE_UPDATE_FAILED', 26 | message, 27 | }) 28 | 29 | export const moveModule = (params: any, onResolved: any) => ({ 30 | type: 'MODULE_MOVE', 31 | params, 32 | onResolved, 33 | }) 34 | export const moveModuleSucceeded = (payload: any) => ({ 35 | type: 'MODULE_MOVE_SUCCEEDED', 36 | payload, 37 | }) 38 | export const moveModuleFailed = (message: any) => ({ 39 | type: 'MODULE_MOVE_FAILED', 40 | message, 41 | }) 42 | 43 | export const deleteModule = (id: any, onResolved: any, repoId: any) => ({ 44 | type: 'MODULE_DELETE', 45 | id, 46 | onResolved, 47 | repoId, 48 | }) 49 | export const deleteModuleSucceeded = (id: any) => ({ 50 | type: 'MODULE_DELETE_SUCCEEDED', 51 | id, 52 | }) 53 | export const deleteModuleFailed = (message: any) => ({ 54 | type: 'MODULE_DELETE_FAILED', 55 | message, 56 | }) 57 | 58 | export const sortModuleList = (ids: any, onResolved: any) => ({ 59 | type: 'MODULE_LIST_SORT', 60 | ids, 61 | onResolved, 62 | }) 63 | export const sortModuleListSucceeded = (count: any, ids: any) => ({ 64 | type: 'MODULE_LIST_SORT_SUCCEEDED', 65 | count, 66 | ids, 67 | }) 68 | export const sortModuleListFailed = (message: any) => ({ 69 | type: 'MODULE_LIST_SORT_FAILED', 70 | message, 71 | }) 72 | -------------------------------------------------------------------------------- /src/actions/organization.ts: -------------------------------------------------------------------------------- 1 | export const addOrganization = (organization: any, onResolved: any) => ({ type: 'ORGANIZATION_ADD', organization, onResolved }) 2 | export const addOrganizationSucceeded = (organization: any) => ({ type: 'ORGANIZATION_ADD_SUCCEEDED', organization }) 3 | export const addOrganizationFailed = (message: any) => ({ type: 'ORGANIZATION_ADD_FAILED', message }) 4 | 5 | export const updateOrganization = (organization: any, onResolved: any) => ({ type: 'ORGANIZATION_UPDATE', organization, onResolved }) 6 | export const updateOrganizationSucceeded = (organization: any) => ({ type: 'ORGANIZATION_UPDATE_SUCCEEDED', organization }) 7 | export const updateOrganizationFailed = (message: any) => ({ type: 'ORGANIZATION_UPDATE_FAILED', message }) 8 | 9 | export const deleteOrganization = (id: any, onResolved: any) => ({ type: 'ORGANIZATION_DELETE', id, onResolved }) 10 | export const deleteOrganizationSucceeded = (id: any) => ({ type: 'ORGANIZATION_DELETE_SUCCEEDED', id }) 11 | export const deleteOrganizationFailed = (message: any) => ({ type: 'ORGANIZATION_DELETE_FAILED', message }) 12 | 13 | export const fetchOrganization = ({ id, organization } = { id: '', organization: ''}) => ({ type: 'ORGANIZATION_FETCH', id, organization }) 14 | export const fetchOrganizationSucceeded = (organization: any) => ({ type: 'ORGANIZATION_FETCH_SUCCEEDED', organization }) 15 | export const fetchOrganizationFailed = (message: any) => ({ type: 'ORGANIZATION_FETCH_FAILED', message }) 16 | 17 | export const fetchOrganizationCount = () => ({ type: 'ORGANIZATION_COUNT_FETCH' }) 18 | export const fetchOrganizationCountSucceeded = (count: any) => ({ type: 'ORGANIZATION_COUNT_FETCH_SUCCEEDED', count }) 19 | export const fetchOrganizationCountFailed = (message: any) => ({ type: 'ORGANIZATION_COUNT_FETCH_FAILED', message }) 20 | 21 | export const fetchOwnedOrganizationList = ({ name } = { name: ''}) => ({ type: 'OWNED_ORGANIZATION_LIST_FETCH', name }) 22 | export const fetchOwnedOrganizationListSucceeded = (organizations: any) => ({ type: 'OWNED_ORGANIZATION_LIST_FETCH_SUCCEEDED', organizations }) 23 | export const fetchOwnedOrganizationListFailed = (message: any) => ({ type: 'OWNED_ORGANIZATION_LIST_FETCH_FAILED', message }) 24 | 25 | export const fetchJoinedOrganizationList = ({ name } = { name: ''}) => ({ type: 'JOINED_ORGANIZATION_LIST_FETCH', name }) 26 | export const fetchJoinedOrganizationListSucceeded = (organizations: any) => ({ type: 'JOINED_ORGANIZATION_LIST_FETCH_SUCCEEDED', organizations }) 27 | export const fetchJoinedOrganizationListFailed = (message: any) => ({ type: 'JOINED_ORGANIZATION_LIST_FETCH_FAILED', message }) 28 | 29 | export const fetchOrganizationList = ( 30 | { name, cursor, limit } = { name: '', cursor: '', limit: '' } 31 | ) => ({ type: 'ORGANIZATION_LIST_FETCH', name, cursor, limit }) 32 | export const fetchOrganizationListSucceeded = (organizations: any) => ({ type: 'ORGANIZATION_LIST_FETCH_SUCCEEDED', organizations }) 33 | export const fetchOrganizationListFailed = (message: any) => ({ type: 'ORGANIZATION_LIST_FETCH_FAILED', message }) 34 | -------------------------------------------------------------------------------- /src/actions/property.ts: -------------------------------------------------------------------------------- 1 | export const addProperty = (property: any, onResolved: any) => ({ 2 | type: 'PROPERTY_ADD', 3 | property, 4 | onResolved, 5 | }) 6 | export const addPropertySucceeded = (property: any) => ({ 7 | type: 'PROPERTY_ADD_SUCCEEDED', 8 | property, 9 | }) 10 | export const addPropertyFailed = (message: any) => ({ 11 | type: 'PROPERTY_ADD_FAILED', 12 | message, 13 | }) 14 | 15 | export const updateProperty = (property: any, onResolved: any) => ({ 16 | type: 'PROPERTY_UPDATE', 17 | property, 18 | onResolved, 19 | }) 20 | export const updatePropertySucceeded = (property: any) => ({ 21 | type: 'PROPERTY_UPDATE_SUCCEEDED', 22 | property, 23 | }) 24 | export const updatePropertyFailed = (message: any) => ({ 25 | type: 'PROPERTY_UPDATE_FAILED', 26 | message, 27 | }) 28 | 29 | export const updateProperties = (itf: any, properties: any, summary: any, onResolved: any) => ({ 30 | type: 'PROPERTIES_UPDATE', 31 | itf, 32 | properties, 33 | summary, 34 | onResolved, 35 | }) 36 | export const updatePropertiesSucceeded = (payload: any) => ({ 37 | type: 'PROPERTIES_UPDATE_SUCCEEDED', 38 | payload, 39 | }) 40 | export const updatePropertiesFailed = (message: any) => ({ 41 | type: 'PROPERTIES_UPDATE_FAILED', 42 | message, 43 | }) 44 | 45 | export const deleteProperty = (id: any, onResolved: any) => ({ 46 | type: 'PROPERTY_DELETE', 47 | id, 48 | onResolved, 49 | }) 50 | export const deletePropertySucceeded = (id: any) => ({ 51 | type: 'PROPERTY_DELETE_SUCCEEDED', 52 | id, 53 | }) 54 | export const deletePropertyFailed = (message: any) => ({ 55 | type: 'PROPERTY_DELETE_FAILED', 56 | message, 57 | }) 58 | 59 | export const sortPropertyList = (ids: any, onResolved: any) => ({ 60 | type: 'PROPERTY_LIST_SORT', 61 | ids, 62 | onResolved, 63 | }) 64 | export const sortPropertyListSucceeded = (count: any) => ({ 65 | type: 'PROPERTY_LIST_SORT_SUCCEEDED', 66 | count, 67 | }) 68 | export const sortPropertyListFailed = (message: any) => ({ 69 | type: 'PROPERTY_LIST_SORT_FAILED', 70 | message, 71 | }) 72 | -------------------------------------------------------------------------------- /src/actions/rootAction.ts: -------------------------------------------------------------------------------- 1 | import { ApiError, IRSAA } from 'redux-api-middleware' 2 | 3 | export interface CommonFetchFailureAction { 4 | payload: ApiError 5 | error: true 6 | } 7 | 8 | const RSAA_BASE: Partial = { 9 | credentials: 'include', 10 | method: 'GET', 11 | headers: { 'Content-Type': 'application/json' }, 12 | } 13 | 14 | export const mergeRSAABase = (options: Partial) => { 15 | return { 16 | ...RSAA_BASE, 17 | ...options, 18 | } as IRSAA 19 | } 20 | -------------------------------------------------------------------------------- /src/assets/README.md: -------------------------------------------------------------------------------- 1 | ## 支持 Sasss 2 | 3 | [Adding a CSS Preprocessor (Sass, Less etc.)](https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/template/README.md#adding-a-css-preprocessor-sass-less-etc) 4 | 5 | ## CSS 规约 6 | 7 | [集团开发规约 - CSS 规约](http://groups.alidemo.cn/f2e-specs/style-guide/_book/1.coding/2.css-style-guide.html) 8 | [网易前端 - CSS 规范](http://nec.netease.com/standard/css-sort.html) 9 | [ecomfe - CSS编码规范](https://github.com/ecomfe/spec/blob/master/css-style-guide.md) 10 | 11 | 12 | ## 参考 13 | * [常用的CSS命名规则](https://www.zhihu.com/question/19586885) 14 | -------------------------------------------------------------------------------- /src/assets/components.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sourceRoot":"","sources":["components.sass","variables.sass"],"names":[],"mappings":"AAOA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AACA;EACE,cCdU;EDeV;;;AAEJ;AAAA;EAEE;;;AAEF;AAAA;EAEE;;;AAGA;EACE;EACA;;AACF;EACE;EACA;EACA;;AACA;EACE;;;AAEN;EAEI;IACE;;;AAEN;EAEI;IACE;;;AAMN;EACE;;AACA;EACE;EACA;;;AACJ;EACE;;;AAoCI;EACE;EACA;EACA;;AAGF;EACE;;AACA;EACE;;AAGF;EACE;;;AAyBV;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AACA;EACE;EACA;;;AAGJ;EACE;EACA;EACA;EACA;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;AACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AACF;EACE;;;AAEJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAEF;EACE;EACA;;;AAEF;EACE;EACA;;;AAEF;EACE;IACE;IACA;;;EACF;IACE;IACA;;;AAEJ;EACE;IACE;IACA;;;EACF;IACE;IACA;;;AAEJ;EACE;IACE;IACA;;;EACF;IACE;IACA;;;AAEJ;EACE;IACE;IACA;;;EACF;IACE;IACA;;;AAGF;EACE;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AACF;EACE;;;AAGJ;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AACF;EACE;;AACF;EACE;;;AAGJ;EACE;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;;AACF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AACF;EACE;;AACF;EACE;;;AAGJ;EACE;EACA;;;AAEJ;EACE;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AACA;EACE;EACA;EACA;;AACF;EACE;EACA;EACA;;AACF;EACE;EACA;EACA;;;AAEJ;EACE;;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAEF;EACE;EACA;EACA","file":"components.css"} -------------------------------------------------------------------------------- /src/assets/fonts.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sourceRoot":"","sources":["fonts.sass"],"names":[],"mappings":"AAIA;AACE;EACA;EACA;EACA;;AACF;EACE;;;AAEF;AACE;EACA;EACA;EACA;;AACF;EACE;;;AAGF;EACE;EACA;EACA;;AACF;EACE","file":"fonts.css"} -------------------------------------------------------------------------------- /src/assets/fonts.sass: -------------------------------------------------------------------------------- 1 | // ---------------------------------------- 2 | // 字体 3 | // ---------------------------------------- 4 | 5 | @font-face 6 | /* project id 12401 */ 7 | font-family: 'brixfont' 8 | src: url('//at.alicdn.com/t/font_p7lto2nib7h6ko6r.eot') 9 | src: url('//at.alicdn.com/t/font_p7lto2nib7h6ko6r.eot?#iefix') format('embedded-opentype'), url('//at.alicdn.com/t/font_p7lto2nib7h6ko6r.woff') format('woff'), url('//at.alicdn.com/t/font_p7lto2nib7h6ko6r.ttf') format('truetype'), url('//at.alicdn.com/t/font_p7lto2nib7h6ko6r.svg#iconfont') format('svg') 10 | .brixfont 11 | font-family: "brixfont" !important 12 | 13 | @font-face 14 | /* project id 182314 */ 15 | font-family: 'rapfont' 16 | src: url('//at.alicdn.com/t/font_afztm7sue48wipb9.eot') 17 | src: url('//at.alicdn.com/t/font_afztm7sue48wipb9.eot?#iefix') format('embedded-opentype'), url('//at.alicdn.com/t/font_afztm7sue48wipb9.woff') format('woff'), url('//at.alicdn.com/t/font_afztm7sue48wipb9.ttf') format('truetype'), url('//at.alicdn.com/t/font_afztm7sue48wipb9.svg#rapfont') format('svg') 18 | .rapfont 19 | font-family: "rapfont" !important 20 | 21 | 22 | @font-face 23 | font-family: 'techfont' 24 | src: url('//g.alicdn.com/mm/zuanshi/20161214.111214.492/app/lib/Oswald-Bold.ttf') 25 | src: url('//g.alicdn.com/mm/zuanshi/20161214.111214.492/app/lib/Oswald-Bold.ttf?#iefix') format('embedded-opentype'), url('//g.alicdn.com/mm/zuanshi/20161214.111214.492/app/lib/Oswald-Bold.ttf') format('woff'), url('//g.alicdn.com/mm/zuanshi/20161214.111214.492/app/lib/Oswald-Bold.ttf') format('truetype'), url('//g.alicdn.com/mm/zuanshi/20161214.111214.492/app/lib/Oswald-Bold.ttf#FZZDHJW--GB1-0') format('svg') 26 | .techfont 27 | font-family: 'techfont' 28 | -------------------------------------------------------------------------------- /src/assets/shortcuts.sass: -------------------------------------------------------------------------------- 1 | @import "./variables.sass" 2 | 3 | // ---------------------------------------- 4 | // 布局 5 | // ---------------------------------------- 6 | 7 | .hide 8 | display: none !important 9 | 10 | .float-right 11 | float: right 12 | 13 | // ---------------------------------------- 14 | // 功能 15 | // ---------------------------------------- 16 | 17 | .fake-link 18 | color: $brand 19 | cursor: pointer 20 | &:hover 21 | color: $brand 22 | 23 | // ---------------------------------------- 24 | // 颜色 25 | // ---------------------------------------- 26 | 27 | // 文字灰度 28 | .color-3 29 | color: #333 30 | .color-6 31 | color: #666 32 | .color-9 33 | color: #999 34 | .color-c 35 | color: #CCC 36 | .color-f 37 | color: #FFF 38 | 39 | // 色块灰度 40 | .bg-c 41 | background-color: #CCCCCC 42 | .bg-e6 43 | background-color: #E6E6E6 44 | .bg-f0 45 | background-color: #F0F0F0 46 | .bg-f5 47 | background-color: #F5F5F5 48 | .bg-fa 49 | background-color: #FAFAFA 50 | .bg-f 51 | background-color: #FFFFFF 52 | 53 | // ---------------------------------------- 54 | // 字体 55 | // ---------------------------------------- 56 | 57 | @each $i in 12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,60 58 | .fontsize-#{$i} 59 | font-size: $i * 1px 60 | 61 | .font-bold 62 | font-weight: bold 63 | .font-tahoma, 64 | .font-number 65 | font-family: "Tahoma" 66 | .nowrap 67 | white-space: nowrap 68 | .text-center 69 | text-align: center 70 | 71 | // ---------------------------------------- 72 | // 行距 Line Height 73 | // ---------------------------------------- 74 | 75 | @each $i in 0,1,2,3,4,5,6,7,8,9,10,12,15,20,25,30,32,35,40,50,60,80,100 76 | .m#{$i} 77 | margin: $i * 1px 78 | .ml#{$i} 79 | margin-left: $i * 1px 80 | .mr#{$i} 81 | margin-right: $i * 1px 82 | .mt#{$i} 83 | margin-top: $i * 1px 84 | .mb#{$i} 85 | margin-bottom: $i * 1px 86 | .p#{$i} 87 | padding: $i * 1px 88 | .pl#{$i} 89 | padding-left: $i * 1px 90 | .pr#{$i} 91 | padding-right: $i * 1px 92 | .pt#{$i} 93 | padding-top: $i * 1px 94 | .pb#{$i} 95 | padding-bottom: $i * 1px 96 | 97 | @each $i in 50,60,70,80,90,100,110,120,130,140,150,160,170,180,190,200,210,220,230,240,250,260,270,280,290,300,310,320,340,350,360,370,380,390,400,500,600,800 98 | .w#{$i} 99 | width: $i * 1px 100 | .h#{$i} 101 | height: $i * 1px 102 | 103 | // ---------------------------------------- 104 | // 动画 Animation 105 | // ---------------------------------------- 106 | 107 | // .animated { 108 | // -webkit-animation-duration: 1s 109 | // -moz-animation-duration: 1s 110 | // animation-duration: 1s 111 | // -webkit-animation-fill-mode: both 112 | // -moz-animation-fill-mode: both 113 | // animation-fill-mode: both 114 | // } 115 | // .animated.infinite { 116 | // -webkit-animation-iteration-count: infinite 117 | // -moz-animation-iteration-count: infinite 118 | // animation-iteration-count: infinite 119 | // } 120 | -------------------------------------------------------------------------------- /src/assets/theme.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sourceRoot":"","sources":[],"names":[],"mappings":"","file":"theme.css"} -------------------------------------------------------------------------------- /src/assets/theme.sass: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thx/rap2-dolores/f0c2390be22a9bc92a74399465e3ee2e764be58b/src/assets/theme.sass -------------------------------------------------------------------------------- /src/assets/variables.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sourceRoot":"","sources":[],"names":[],"mappings":"","file":"variables.css"} -------------------------------------------------------------------------------- /src/assets/variables.sass: -------------------------------------------------------------------------------- 1 | // ---------------------------------------- 2 | // 颜色 3 | // ---------------------------------------- 4 | 5 | $brand: #4A7BF7 6 | $brand-hover: #4471E3 7 | $nav-color: rgba(255, 255, 255, 0.75) 8 | $nav-hover: rgba(255, 255, 255, 1) 9 | $table-hover: #F0F3FA 10 | $table-th-bg: #FAFAFA 11 | 12 | $bg: #F0F0F0 13 | $border: #d1d5da 14 | $warning: #FFB400 15 | $danger: #A62A22 16 | $success: #6CB12A 17 | $fail: #A62A22 18 | 19 | 20 | // ---------------------------------------- 21 | // 字体 22 | // ---------------------------------------- 23 | 24 | $font-family: "Microsoft YaHei", "微软雅黑", STXihei, "华文细黑", Georgia, "Times New Roman", Arial, sans-serif 25 | -------------------------------------------------------------------------------- /src/components/account/EditMyAccountDialog.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react' 2 | import { useDispatch } from 'react-redux' 3 | import { TextField, Dialog, DialogTitle, DialogContent, DialogActions, Button } from '@material-ui/core' 4 | import { doUpdateAccount } from 'actions/account' 5 | 6 | 7 | function EditMyAccountDialog({ handleClose }: { handleClose: (isOk: boolean) => void }) { 8 | const [pwd, setPwd] = useState('') 9 | const [name, setName] = useState('') 10 | const dispatch = useDispatch() 11 | 12 | const onSubmit = () => { 13 | dispatch(doUpdateAccount({ fullname: name, password: pwd }, isOk => { 14 | if (isOk) { 15 | handleClose(true) 16 | } 17 | })) 18 | } 19 | return ( 20 | handleClose(false)} style={{ width: 600 }}> 21 | 修改资料 22 | 23 | setPwd(e.target.value)} 31 | value={pwd} 32 | /> 33 | setName(e.target.value)} 40 | value={name} 41 | /> 42 | 43 | 44 | 47 | 53 | 54 | 55 | ) 56 | } 57 | 58 | export default EditMyAccountDialog 59 | -------------------------------------------------------------------------------- /src/components/account/FindpwdForm.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sourceRoot":"","sources":["FindpwdForm.sass"],"names":[],"mappings":"AAEA;EACE;EACA;EACA;EACA;;AACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AACA;EACE;EACA;;AACA;EACE;;AACJ;EACE;;AACF;EACE;EACA","file":"FindpwdForm.css"} -------------------------------------------------------------------------------- /src/components/account/FindpwdForm.sass: -------------------------------------------------------------------------------- 1 | @import "../../assets/variables.sass" 2 | // 水平居中 + 垂直居中 3 | .wrapper 4 | background-size: cover 5 | width: 100% 6 | height: 100% 7 | min-height: 800px 8 | .LoginForm 9 | position: fixed 10 | left: 50% 11 | top: 30% 12 | width: 25rem 13 | margin-left: -12.5rem 14 | margin-top: -135px 15 | border: 1px solid #E6E6E6 16 | border-radius: .5rem 17 | .header 18 | padding: 1.5rem 3rem 19 | border-bottom: 1px solid $border 20 | .title 21 | font-size: 2rem 22 | .body 23 | padding: 1.5rem 3rem 24 | .footer 25 | padding: 1.5rem 3rem 26 | border-top: 1px solid $border 27 | 28 | -------------------------------------------------------------------------------- /src/components/account/Index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { connect } from 'react-redux' 3 | import { renderRoutes } from 'react-router-config' 4 | 5 | const Account = ({ route }: any) => ( 6 |
7 | {route && renderRoutes(route.routes)} 8 |
9 | ) 10 | 11 | const mapDispatchToProps = ({}) 12 | 13 | export default connect( 14 | null, 15 | mapDispatchToProps 16 | )(Account) 17 | -------------------------------------------------------------------------------- /src/components/account/LoginForm.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sourceRoot":"","sources":["LoginForm.sass"],"names":[],"mappings":"AAEA;EACE;EACA;EACA;EACA;;AACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AACA;EACE;EACA;;AACA;EACE;;AACJ;EACE;;AACF;EACE;EACA","file":"LoginForm.css"} -------------------------------------------------------------------------------- /src/components/account/LoginForm.sass: -------------------------------------------------------------------------------- 1 | @import "../../assets/variables.sass" 2 | // 水平居中 + 垂直居中 3 | .wrapper 4 | background-size: cover 5 | width: 100% 6 | height: 100% 7 | min-height: 800px 8 | .LoginForm 9 | position: fixed 10 | left: 50% 11 | top: 30% 12 | width: 25rem 13 | margin-left: -12.5rem 14 | margin-top: -135px 15 | border: 1px solid #E6E6E6 16 | border-radius: .5rem 17 | .header 18 | padding: 1.5rem 1.95rem 19 | border-bottom: 1px solid $border 20 | .title 21 | font-size: 1.3rem 22 | .body 23 | padding: 1.5rem 1.95rem 24 | .footer 25 | padding: 1.5rem 1.95rem 26 | border-top: 1px solid $border 27 | 28 | -------------------------------------------------------------------------------- /src/components/account/MyAccountView.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react' 2 | import { useSelector, useDispatch } from 'react-redux' 3 | import { RootState } from 'actions/types' 4 | import { makeStyles, Theme, Card, CardActionArea, CardContent, Typography, CardActions, Button } from '@material-ui/core' 5 | import EditMyAccountDialog from './EditMyAccountDialog' 6 | import { logout, fetchLoginInfo } from 'actions/account' 7 | 8 | const useStyles = makeStyles(({ palette, spacing }: Theme) => ({ 9 | root: { 10 | margin: spacing(2), 11 | }, 12 | dialog: { 13 | }, 14 | card: { 15 | minWidth: 375, 16 | maxWidth: 500, 17 | maxHeight: `calc(100% - ${spacing(4)}px)`, 18 | overflowY: 'auto', 19 | }, 20 | media: { 21 | objectFit: 'cover', 22 | height: 250, 23 | }, 24 | title: { 25 | marginTop: spacing(1), 26 | color: palette.primary.main, 27 | }, 28 | dialogPapaer: { 29 | margin: spacing(2), 30 | }, 31 | })) 32 | 33 | function MyAccountView() { 34 | const me = useSelector((state: RootState) => state.auth) 35 | const classes = useStyles() 36 | const [editing, setEditing] = useState(false) 37 | const dispatch = useDispatch() 38 | const onEditSubmit = (isOk: boolean) => { 39 | setEditing(false) 40 | if (isOk) { 41 | dispatch(fetchLoginInfo()) 42 | } 43 | } 44 | 45 | return ( 46 |
47 | 48 | 49 | 50 | 51 | {me.fullname} 52 | 53 | 54 | 这个家伙很懒还没有写签名....我们也不支持 。。。 55 | 56 | 57 | 昵称 58 | 59 | 60 | {me.fullname} 61 | 62 | 63 | 账号 / 邮箱 64 | 65 | 66 | {me.email} 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | {editing && } 76 |
77 | ) 78 | } 79 | 80 | export default MyAccountView 81 | -------------------------------------------------------------------------------- /src/components/account/MySettings.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react' 2 | import { Paper, Theme, List, ListSubheader, makeStyles, ListItem, ListItemIcon, ListItemText, ListItemSecondaryAction, IconButton } from '@material-ui/core' 3 | import Settings from '@material-ui/icons/Settings' 4 | import Palette from '@material-ui/icons/Palette' 5 | import ThemeChangeOverlay, { THEME_TEMPLATE_KEY } from './ThemeChangeOverlay' 6 | import { CACHE_KEY } from 'utils/consts' 7 | 8 | const useStyles = makeStyles(({ spacing }: Theme) => ({ 9 | root: { 10 | padding: spacing(1), 11 | maxWidth: 400, 12 | }, 13 | })) 14 | 15 | interface Props { 16 | isFetching: boolean 17 | data: { [key: string]: string } 18 | onChange: (key: CACHE_KEY, val: string) => void 19 | } 20 | 21 | function MySettings(props: Props) { 22 | const classes = useStyles() 23 | const { data, onChange, isFetching } = props 24 | const [editingThemeTemplate, setEditingThemeTemplate] = useState(false) 25 | 26 | const themeId = data[CACHE_KEY.THEME_ID] as THEME_TEMPLATE_KEY || THEME_TEMPLATE_KEY.RED 27 | 28 | const handleClose = (themeId?: THEME_TEMPLATE_KEY) => { 29 | setEditingThemeTemplate(false) 30 | themeId && onChange(CACHE_KEY.THEME_ID, themeId) 31 | } 32 | 33 | return ( 34 | 35 | 偏好设置}> 36 | 37 | 38 | 39 | 40 | 41 | 42 | setEditingThemeTemplate(true)}> 43 | 44 | 45 | 46 | 47 | 48 | 53 | 54 | ) 55 | } 56 | 57 | export default MySettings 58 | -------------------------------------------------------------------------------- /src/components/account/MySettingsView.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from 'react' 2 | import { makeStyles } from '@material-ui/styles' 3 | import { useDispatch, useSelector } from 'react-redux' 4 | import { CACHE_KEY } from 'utils/consts' 5 | import MySettings from './MySettings' 6 | import { RootState } from 'actions/types' 7 | import { fetchUserSettings, doUpdateUserSetting } from 'actions/account' 8 | import { Theme } from '@material-ui/core' 9 | 10 | const useStyles = makeStyles(({ spacing }: Theme ) => ({ 11 | root: { 12 | padding: spacing(2), 13 | }, 14 | })) 15 | 16 | const SETTING_KEYS: CACHE_KEY[] = [ 17 | CACHE_KEY.THEME_ID, 18 | ] 19 | 20 | function MySettingsView() { 21 | const classes = useStyles() 22 | const dispatch = useDispatch() 23 | const settings = useSelector((state: RootState) => state.userSettings) 24 | const isFetching = useSelector((state: RootState) => state.userSettingsIsUpdating) 25 | 26 | useEffect(() => { 27 | dispatch(fetchUserSettings(SETTING_KEYS)) 28 | }, [dispatch]) 29 | 30 | const handleSettingChange = (key: CACHE_KEY, val: string) => { 31 | dispatch(doUpdateUserSetting(key, val, isOk => { 32 | if (isOk) { 33 | fetchUserSettings(SETTING_KEYS) 34 | } 35 | })) 36 | } 37 | 38 | return ( 39 |
40 | 45 |
46 | ) 47 | } 48 | 49 | export default MySettingsView 50 | -------------------------------------------------------------------------------- /src/components/account/Navigation.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { NavLink } from 'react-router-dom' 3 | import { connect } from 'react-redux' 4 | 5 | const Nav = () => ( 6 | 11 | ) 12 | 13 | const mapDispatchToProps = ({}) 14 | 15 | export default connect( 16 | null, 17 | mapDispatchToProps 18 | )(Nav) 19 | -------------------------------------------------------------------------------- /src/components/account/RegisterForm.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sourceRoot":"","sources":["RegisterForm.sass"],"names":[],"mappings":"AAEA;EACE;EACA;EACA;EACA;;AACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AACA;EACE;EACA;;AACA;EACE;;AACJ;EACE;;AACF;EACE;EACA","file":"RegisterForm.css"} -------------------------------------------------------------------------------- /src/components/account/RegisterForm.sass: -------------------------------------------------------------------------------- 1 | @import "../../assets/variables.sass" 2 | // 水平居中 + 垂直居中 3 | .wrapper 4 | background-size: cover 5 | width: 100% 6 | height: 100% 7 | min-height: 800p 8 | .RegisterForm 9 | position: fixed 10 | left: 50% 11 | top: 30% 12 | width: 25rem 13 | margin-left: -12.5rem 14 | margin-top: -135px 15 | border: 1px solid #E6E6E6 16 | border-radius: .5rem 17 | .header 18 | padding: 1.5rem 1.95rem 19 | border-bottom: 1px solid $border 20 | .title 21 | font-size: 1.3rem 22 | .body 23 | padding: 1.5rem 1.95rem 24 | .footer 25 | padding: 1.5rem 1.95rem 26 | border-top: 1px solid $border 27 | 28 | -------------------------------------------------------------------------------- /src/components/account/RegisterForm.tsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { connect } from 'react-redux' 3 | import { Link } from 'react-router-dom' 4 | import Mock from 'mockjs' 5 | import { addUser } from '../../actions/account' 6 | import './RegisterForm.css' 7 | import { Button, Card } from '@material-ui/core' 8 | import { getBGImageUrl } from 'utils/ImageUtils' 9 | 10 | type State = { 11 | fullname: string 12 | email: string 13 | password: string 14 | bg: string 15 | } 16 | 17 | type Props = { 18 | history: any 19 | onAddUser: any 20 | } 21 | 22 | // 模拟数据 23 | const mockUser = () => 24 | process.env.NODE_ENV === 'development' 25 | ? Mock.mock({ 26 | fullname: '@CNAME', 27 | email: '@email', 28 | password: '@string(6)', 29 | }) 30 | : { 31 | fullname: '', 32 | email: '', 33 | password: '', 34 | } 35 | 36 | // 展示组件 37 | class RegisterForm extends Component { 38 | constructor(props: any) { 39 | super(props) 40 | this.state = { 41 | ...mockUser(), 42 | bg: getBGImageUrl(), 43 | } 44 | } 45 | render() { 46 | return ( 47 |
48 | 49 |
50 | 注册 51 |
52 |
53 |
54 | 55 | this.setState({ fullname: e.target.value })} 58 | className="form-control" 59 | placeholder="Name" 60 | autoFocus={true} 61 | required={true} 62 | /> 63 |
64 |
65 | 66 | this.setState({ email: e.target.value })} 69 | className="form-control" 70 | placeholder="Email" 71 | required={true} 72 | /> 73 |
74 |
75 | 76 | this.setState({ password: e.target.value })} 79 | type="password" 80 | className="form-control" 81 | placeholder="Password" 82 | required={true} 83 | /> 84 |
85 | 86 | 取消 87 |
88 |
89 |
90 | ) 91 | } 92 | handleSubmit = (e: any) => { 93 | const { onAddUser } = this.props 94 | e.preventDefault() 95 | onAddUser(this.state, (isOk: boolean) => { 96 | if (isOk) { 97 | window.location.href = '/' 98 | } 99 | }) 100 | }; 101 | } 102 | 103 | // 容器组件 104 | const mapDispatchToProps = { 105 | onAddUser: addUser, 106 | } 107 | export default connect( 108 | null, 109 | mapDispatchToProps 110 | )(RegisterForm) 111 | -------------------------------------------------------------------------------- /src/components/account/ResetForm.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sourceRoot":"","sources":["ResetForm.sass"],"names":[],"mappings":"AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AACA;EACE;EACA;;AACA;EACE;;AACJ;EACE;;AACF;EACE;EACA","file":"ResetForm.css"} -------------------------------------------------------------------------------- /src/components/account/ResetForm.sass: -------------------------------------------------------------------------------- 1 | @import "../../assets/variables.sass" 2 | // 水平居中 + 垂直居中 3 | .ResetForm 4 | position: fixed 5 | left: 50% 6 | top: 50% 7 | width: 25rem 8 | margin-left: -12.5rem 9 | margin-top: -135px 10 | border: 1px solid #E6E6E6 11 | border-radius: .5rem 12 | .header 13 | padding: 1.5rem 3rem 14 | border-bottom: 1px solid $border 15 | .title 16 | font-size: 2rem 17 | .body 18 | padding: 1.5rem 3rem 19 | .footer 20 | padding: 1.5rem 3rem 21 | border-top: 1px solid $border 22 | 23 | -------------------------------------------------------------------------------- /src/components/account/UpdateForm.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sourceRoot":"","sources":["UpdateForm.sass"],"names":[],"mappings":"AAAA;EACE;EACA;;AACA;EACE;;AACA;EACE","file":"UpdateForm.css"} -------------------------------------------------------------------------------- /src/components/account/UpdateForm.sass: -------------------------------------------------------------------------------- 1 | .UpdateForm 2 | width: 30rem 3 | margin: 0 auto 4 | .header 5 | margin-bottom: 3rem 6 | .title 7 | font-size: 2rem 8 | .body 9 | .footer -------------------------------------------------------------------------------- /src/components/account/User.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Link } from 'react-router-dom' 3 | 4 | const User = ({ match, id, fullname, email, onDeleteUser }: any) => ( 5 | 6 | {id} 7 | {fullname} 8 | {email} 9 | 10 | onDeleteUser(id)}>X 11 | 12 | 13 | ) 14 | 15 | export default User 16 | -------------------------------------------------------------------------------- /src/components/account/UserList.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sourceRoot":"","sources":["UserList.sass"],"names":[],"mappings":"AAAA;EACE;;AACA;EACE;;AACA;EACE;;AACJ;EACE","file":"UserList.css"} -------------------------------------------------------------------------------- /src/components/account/UserList.sass: -------------------------------------------------------------------------------- 1 | .UserList 2 | padding: 1.3rem 3 | .header 4 | margin-bottom: 1.3rem 5 | .title 6 | font-size: 1.3rem 7 | .toolbar 8 | margin-bottom: 0.65rem 9 | -------------------------------------------------------------------------------- /src/components/account/UserList.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Link } from 'react-router-dom' 3 | import { connect } from 'react-redux' 4 | import Pagination from '../utils/Pagination' 5 | import { addUser, deleteUser, fetchUserList } from '../../actions/account' 6 | import './UserList.css' 7 | import { RootState } from 'actions/types' 8 | 9 | // 展示组件 10 | const UserList = ({ match, location, users, onDeleteUser }: any) => ( 11 |
12 |
13 | 用户管理 14 |
15 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | {users.data.map((user: any) => 34 | 35 | 38 | 39 | 44 | 45 | )} 46 | 47 |
姓名邮箱操作
36 | #{user.id} {user.fullname} 37 | {user.email} 40 | 41 | onDeleteUser(user.id)} className="operation disabled">删除 42 | 43 |
48 |
49 |
50 | 51 |
52 |
53 | ) 54 | 55 | // 容器组件 56 | const mapStateToProps = (state: RootState) => ({ 57 | users: state.users, 58 | }) 59 | const mapDispatchToProps = ({ 60 | onAddUser: addUser, 61 | onDeleteUser: deleteUser, 62 | onFetchUserList: fetchUserList, 63 | }) 64 | export default connect( 65 | mapStateToProps, 66 | mapDispatchToProps 67 | )(UserList) 68 | -------------------------------------------------------------------------------- /src/components/api/API.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sourceRoot":"","sources":["API.sass"],"names":[],"mappings":"AAAA;EACE;EACA;;AACA;EACE;;AACA;EACE;;AAEF;EACE;;AACA;EACE;EACA;;AACF;EACE;;AACA;EACE;;AACA;EACE;;AACN;EACE;;;AACR;EACE;EACA","file":"API.css"} -------------------------------------------------------------------------------- /src/components/api/API.sass: -------------------------------------------------------------------------------- 1 | .APIList 2 | padding: 1.3rem 3 | margin: 16px 4 | > .header 5 | margin-bottom: 1.3rem 6 | .title 7 | font-size: 1.3rem 8 | > .body 9 | > .API 10 | margin-bottom: 1.3rem 11 | > .title 12 | font-size: 1.6rem 13 | margin-bottom: 0.65rem 14 | > ul 15 | padding-left: 1.3rem 16 | li 17 | margin-bottom: .75rem 18 | .label 19 | margin-right: .5rem 20 | code 21 | padding: .5rem 22 | .code-example 23 | padding: 1.3rem 24 | margin: 1.3rem 25 | -------------------------------------------------------------------------------- /src/components/checker/Checker.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sourceRoot":"","sources":["Checker.sass","../../assets/variables.sass"],"names":[],"mappings":"AAEA;EACE;;AAEE;EACE;EACA;EACA;;AACF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AACF;EACE,OCdQ;;ADeZ;EACE;;AACA;EACE;EACA","file":"Checker.css"} -------------------------------------------------------------------------------- /src/components/checker/Checker.sass: -------------------------------------------------------------------------------- 1 | @import "../../assets/variables.sass" 2 | 3 | .Checker 4 | padding: 1.3rem 5 | .card-mods, .card-itfs 6 | .card-title 7 | float: left 8 | width: 3.25rem 9 | font-size: 1rem 10 | a 11 | float: left 12 | margin-right: 0.65rem 13 | width: 10rem 14 | overflow: hidden 15 | white-space: nowrap 16 | text-overflow: ellipsis 17 | color: #666 18 | a.active 19 | color: $brand 20 | .card-result 21 | margin-top: 0.65rem 22 | .card-title 23 | font-size: 1rem 24 | margin-bottom: 0.65rem 25 | -------------------------------------------------------------------------------- /src/components/common/ConfirmDialog.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Button from '@material-ui/core/Button' 3 | import Dialog from '@material-ui/core/Dialog' 4 | import DialogActions from '@material-ui/core/DialogActions' 5 | import DialogContent from '@material-ui/core/DialogContent' 6 | import DialogTitle from '@material-ui/core/DialogTitle' 7 | import { SlideUp } from 'components/common/Transition' 8 | 9 | interface Props { 10 | open: boolean 11 | title?: string 12 | content: React.ReactNode 13 | type: 'alert' | 'confirm' 14 | onConfirm: () => void 15 | onCancel: () => void 16 | } 17 | export default function ConfirmDialog(props: Props) { 18 | const { type, title = '确认' } = props 19 | return ( 20 | 21 | {title} 22 | 23 | {props.content} 24 | 25 | 26 | {type === 'confirm' && ( 27 | 30 | )} 31 | 34 | 35 | 36 | ) 37 | } 38 | -------------------------------------------------------------------------------- /src/components/common/Footer.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sourceRoot":"","sources":["Footer.sass"],"names":[],"mappings":"AAEA;EACE;EACA;EACA;;AACA;EACE;EACA;EACA;;AACA;EACE;EACA","file":"Footer.css"} -------------------------------------------------------------------------------- /src/components/common/Footer.sass: -------------------------------------------------------------------------------- 1 | @import "../../assets/variables.sass" 2 | 3 | .Footer 4 | padding: 1.3rem 0.65rem 0.65rem 0.65rem 5 | border-top: 1px solid $border 6 | text-align: center 7 | ul.friend_links 8 | margin-top: .5rem 9 | list-style: none 10 | padding: 0 11 | li 12 | display: inline-block 13 | margin-right: 0.65rem 14 | 15 | -------------------------------------------------------------------------------- /src/components/common/Footer.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { connect } from 'react-redux' 3 | import './Footer.css' 4 | import { RootState } from 'actions/types' 5 | 6 | const Footer = ({ counter = {} }: { counter: any }) => ( 7 |
8 | {counter && counter.version} 9 | 14 |
15 | ) 16 | 17 | const mapStateToProps = (state: RootState) => ({ 18 | counter: state.counter, 19 | }) 20 | const mapDispatchToProps = ({}) 21 | 22 | export default connect( 23 | mapStateToProps, 24 | mapDispatchToProps 25 | )(Footer) 26 | -------------------------------------------------------------------------------- /src/components/common/GlobalStyles.tsx: -------------------------------------------------------------------------------- 1 | import grey from '@material-ui/core/colors/grey' 2 | import { StyleRules, Theme } from '@material-ui/core/styles' 3 | 4 | const GlobalStyles = (theme: Theme) => ({ 5 | '@global': { 6 | 'body': { 7 | margin: 0, 8 | padding: 0, 9 | backgroundColor: grey[200], 10 | fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif;', 11 | fontSize: '1rem', 12 | }, 13 | '.ml1': { 14 | marginLeft: theme.spacing(1), 15 | }, 16 | '.mr1': { 17 | marginRight: theme.spacing(1), 18 | }, 19 | '.mb1': { 20 | marginBottom: theme.spacing(1), 21 | }, 22 | '.mt1': { 23 | marginTop: theme.spacing(1), 24 | }, 25 | 'ol': { 26 | padding: `0 ${theme.spacing(2)}px`, 27 | }, 28 | 'ul': { 29 | padding: `0 ${theme.spacing(2)}px`, 30 | }, 31 | 'li': { 32 | padding: `${theme.spacing(1)}px 0`, 33 | }, 34 | '.g-link': { 35 | color: theme.palette.primary.main, 36 | cursor: 'pointer', 37 | }, 38 | 'a, a:hover, a:focus, a:active, a:visited': { 39 | color: theme.palette.primary.main, 40 | cursor: 'pointer', 41 | }, 42 | }, 43 | }) as StyleRules 44 | 45 | export default GlobalStyles 46 | -------------------------------------------------------------------------------- /src/components/common/Header.css.map: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "mappings": "AAEA,AAAA,OAAO,CAAC;EACN,gBAAgB,ECGJ,OAAO;EDFnB,KAAK,EAAE,KAAK;EACZ,SAAS,EAAE,MAAM;EACjB,WAAW,EAAE,IAAI;EACjB,cAAc,EAAE,MAAM;EAEtB,OAAO,EAAE,MAAM;CA4BU;;AAnC3B,AAQE,OARK,CAQL,EAAE,AAAA,UAAU,CAAC;EACX,KAAK,EAAE,IAAI;CAAG;;AATlB,AAUE,OAVK,CAUL,EAAE,AAAA,YAAY,CAAC;EACb,KAAK,EAAE,KAAK;CAAG;;AAXnB,AAYE,OAZK,CAYL,EAAE,AAAA,UAAU;AAZd,OAAO,CAaL,EAAE,AAAA,YAAY,CAAC;EACb,MAAM,EAAE,CAAC;EACT,OAAO,EAAE,CAAC;EACV,UAAU,EAAE,IAAI;CAaY;;AA7BhC,AAiBI,OAjBG,CAYL,EAAE,AAAA,UAAU,GAKR,EAAE;AAjBR,OAAO,CAaL,EAAE,AAAA,YAAY,GAIV,EAAE,CAAC;EACH,KAAK,EAAE,IAAI;EACX,OAAO,EAAE,MAAM;CAUS;;AA7B9B,AAoBM,OApBC,CAYL,EAAE,AAAA,UAAU,GAKR,EAAE,GAGA,CAAC;AApBT,OAAO,CAaL,EAAE,AAAA,YAAY,GAIV,EAAE,GAGA,CAAC,CAAC;EACF,KAAK,EAAE,KAAK;EACZ,OAAO,EAAE,GAAG;CAIK;;AA1BzB,AAuBQ,OAvBD,CAYL,EAAE,AAAA,UAAU,GAKR,EAAE,GAGA,CAAC,AAGA,MAAM,EAvBf,OAAO,CAYL,EAAE,AAAA,UAAU,GAKR,EAAE,GAGA,CAAC,AAGS,SAAS;AAvB3B,OAAO,CAaL,EAAE,AAAA,YAAY,GAIV,EAAE,GAGA,CAAC,AAGA,MAAM;AAvBf,OAAO,CAaL,EAAE,AAAA,YAAY,GAIV,EAAE,GAGA,CAAC,AAGS,SAAS,CAAC;EAClB,MAAM,EAAE,IAAI;EACZ,WAAW,EAAE,IAAI;EACjB,OAAO,EAAE,CAAC;CAAG;;AA1BvB,AA2BM,OA3BC,CAYL,EAAE,AAAA,UAAU,GAKR,EAAE,GAUA,CAAC,AAAA,KAAK;AA3Bd,OAAO,CAaL,EAAE,AAAA,YAAY,GAIV,EAAE,GAUA,CAAC,AAAA,KAAK,CAAC;EACP,OAAO,EAAE,CAAC;EACV,WAAW,EAAE,IAAI;CAAG;;AA7B5B,AA8BE,OA9BK,CA8BL,OAAO,CAAC;EACN,KAAK,EAAE,MAAM;EACb,MAAM,EAAE,MAAM;EACd,aAAa,EAAE,GAAG;CAAG;;AAjCzB,AAkCE,OAlCK,CAkCL,KAAK,CAAC;EACJ,WAAW,EAAE,KAAK;CAAG", 4 | "sources": [ 5 | "Header.sass", 6 | "../../assets/variables.sass" 7 | ], 8 | "names": [], 9 | "file": "Header.css" 10 | } -------------------------------------------------------------------------------- /src/components/common/Header.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { connect } from 'react-redux' 3 | import NProgress from 'nprogress' 4 | import 'nprogress/nprogress.css' 5 | import './nprogress.css' 6 | import MainMenu from 'components/layout/MainMenu' 7 | const Header = ({ fetching, user = {} }: any) => { 8 | if (!user || !user.id) { 9 | return null 10 | } 11 | document.body.style.cursor = fetching ? 'wait' : 'default' // TODO 2.3 应该有更好的方式监听整个 APP 是否有未完成的请求! 12 | fetching ? NProgress.start() : NProgress.done() 13 | return ( 14 |
15 | 18 |
19 | ) 20 | } 21 | 22 | const mapStateToProps = (state: any) => ({ 23 | fetching: (() => { 24 | let fetching = 0 25 | for (const key in state) { 26 | if (state[key] && state[key].fetching) { fetching += 1 } 27 | } 28 | return fetching 29 | })(), // state.fetching 30 | user: state.auth, 31 | }) 32 | 33 | const mapDispatchToProps = ({ 34 | }) 35 | 36 | export default connect( 37 | mapStateToProps, 38 | mapDispatchToProps 39 | )(Header) 40 | -------------------------------------------------------------------------------- /src/components/common/LoadingButton.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Button, makeStyles, createStyles, CircularProgress } from '@material-ui/core' 3 | import { ButtonProps } from '@material-ui/core/Button' 4 | import { green } from '@material-ui/core/colors' 5 | 6 | const useStyles = makeStyles(() => 7 | createStyles({ 8 | root: { 9 | position: 'relative', 10 | display: 'inline', 11 | }, 12 | buttonProgress: { 13 | color: green[500], 14 | position: 'absolute', 15 | top: '50%', 16 | left: '50%', 17 | marginTop: -12, 18 | marginLeft: -12, 19 | }, 20 | }) 21 | ) 22 | 23 | interface Props extends ButtonProps { 24 | label: string 25 | } 26 | 27 | export default React.forwardRef((props: Props, ref: any) => { 28 | const { children, label, ...rest } = props 29 | const classes = useStyles() 30 | const loading = props.disabled 31 | return ( 32 |
33 | 37 | {loading && } 38 |
39 | ) 40 | }) 41 | -------------------------------------------------------------------------------- /src/components/common/MuiTheme.tsx: -------------------------------------------------------------------------------- 1 | import { ThemeOptions, createTheme } from '@material-ui/core/styles' 2 | import { THEME_TEMPLATES, THEME_TEMPLATE_KEY } from 'components/account/ThemeChangeOverlay' 3 | 4 | export const theme = { 5 | palette: THEME_TEMPLATES[THEME_TEMPLATE_KEY.INDIGO].theme, 6 | typography: { 7 | fontSize: 13, 8 | // 告知 Material-UI 此 html 元素的具体字体大小。 9 | htmlFontSize: 12, 10 | }, 11 | overrides: { 12 | MuiTableCell: { 13 | root: { 14 | padding: `8px 16px`, 15 | }, 16 | }, 17 | MuiFormControl: { 18 | root: { 19 | zIndex: 'inherit', 20 | }, 21 | }, 22 | }, 23 | } 24 | 25 | const MuiTheme = (options?: ThemeOptions) => createTheme({ 26 | ...theme as ThemeOptions, 27 | ...(options || {}) 28 | }) 29 | 30 | export default MuiTheme 31 | -------------------------------------------------------------------------------- /src/components/common/Navigation.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { NavLink } from 'react-router-dom' 3 | import { GoHome, GoRepo, GoOrganization, GoPulse, GoPlug } from 'react-icons/go' 4 | 5 | export default () => ( 6 |
    7 |
  • 首页
  • 8 |
  • 仓库
  • 9 |
  • 团队
  • 10 |
  • 接口
  • 11 |
  • 状态
  • 12 |
13 | ) 14 | -------------------------------------------------------------------------------- /src/components/common/NoData.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | function NoData() { 4 | return ( 5 |
6 | 暂无数据 7 |
8 | ) 9 | } 10 | 11 | export default NoData 12 | -------------------------------------------------------------------------------- /src/components/common/Transition.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { TransitionProps } from '@material-ui/core/transitions' 3 | import Slide from '@material-ui/core/Slide' 4 | 5 | export const SlideUp = React.forwardRef( 6 | ( 7 | props: TransitionProps & { children?: React.ReactElement }, 8 | ref: React.Ref, 9 | ) => { 10 | return 11 | }, 12 | ) 13 | -------------------------------------------------------------------------------- /src/components/common/UserList.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { INumItem, User } from '../../actions/types' 3 | import Select from './Select' 4 | 5 | export type SelectedItem = Pick 6 | 7 | interface Props { 8 | loadOptions?: (input: string) => Promise 9 | options?: INumItem[] 10 | isMulti?: boolean 11 | selected?: INumItem[] 12 | value?: INumItem[] 13 | minWidth?: number 14 | onChange: (selected: SelectedItem[]) => void 15 | } 16 | 17 | function UserList(props: Props) { 18 | const { loadOptions, options, isMulti, selected, value, minWidth, onChange } = props 19 | return ( 20 | this.handleSeed(e.target.value)} 43 | ref={$seed => { this.$seed = $seed }} 44 | /> 45 | {this.state.options.length ? ( 46 |
{ this.$options = $options }}> 47 | {this.state.options.map((item: any) => 48 | 55 | )} 56 |
57 | ) : null} 58 | 59 | } 60 | 61 | ) 62 | } 63 | handleSeed = async (seed: any) => { 64 | this.setState({ seed: seed }) 65 | if (!seed) { 66 | this.setState({ options: [] }) 67 | return 68 | } 69 | const users = await AccountService.fetchUserList({ name: seed }) 70 | const options = _.differenceWith(users.data, this.state.value, _.isEqual) 71 | this.setState({ options }) 72 | } 73 | handleSelect = (e: any, selected: any) => { 74 | e.preventDefault() 75 | const nextState = { seed: '', value: [...this.state.value, selected] } 76 | this.setState(nextState, this.handleChange) 77 | } 78 | // √remove vs delete 79 | handleRemove = (removed: any) => { 80 | const nextState = { value: this.state.value.filter((item: any) => item !== removed) } 81 | this.setState(nextState, this.handleChange) 82 | } 83 | // √change vs update 84 | handleChange = () => { 85 | const { onChange } = this.props 86 | onChange(this.state.value) 87 | this.$seed && this.$seed.focus() 88 | this.setState({ 89 | options: [], 90 | }) 91 | } 92 | } 93 | 94 | export default MembersInput 95 | -------------------------------------------------------------------------------- /src/components/utils/Modal.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sourceRoot":"","sources":["Modal.sass"],"names":[],"mappings":"AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AACA;EACE;EACA;;AACF;EACE;;AACJ;EACE;EACA;EACA;;AACA;EACE;EACA;;AACJ;EACE;;AACF;EACE;EACA;EACA;;;AAEJ;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA","file":"Modal.css"} -------------------------------------------------------------------------------- /src/components/utils/Modal.sass: -------------------------------------------------------------------------------- 1 | @import "../../assets/variables.sass" 2 | 3 | .Modal 4 | position: fixed 5 | top: 0 6 | left: 0 7 | max-height: 100% 8 | overflow: scroll 9 | border: none 10 | border-radius: .5rem 11 | box-shadow: none 12 | background-color: white 13 | z-index: 1040 14 | 15 | button.close 16 | position: absolute 17 | right: 0.65rem 18 | top: 0.65rem 19 | border: none 20 | color: #000 21 | background-color: transparent 22 | opacity: .2 23 | &:hover, &:focus 24 | opacity: .5 25 | text-decoration: none 26 | .rapfont 27 | font-size:1.95rem 28 | .modal-header 29 | border-bottom: 1px solid $border 30 | padding: 1.5rem 2.6rem 1.5rem 1.95rem 31 | text-align: left 32 | .modal-title 33 | margin: 0 34 | font-size: 1.8rem 35 | .modal-body 36 | padding: 1.5rem 1.95rem 37 | .modal-footer 38 | text-align: left 39 | border-top: 1px solid $border 40 | padding: 1.5rem 1.95rem 41 | 42 | .modal-backdrop 43 | position: fixed 44 | top: 0 45 | right: 0 46 | left: 0 47 | bottom: 0 48 | background-color: #000 49 | filter: alpha(opacity=50) 50 | opacity: .5 51 | z-index: 1039 52 | -------------------------------------------------------------------------------- /src/components/utils/Modal.tsx: -------------------------------------------------------------------------------- 1 | // DONE 2.x 待解决 context 不完整的问题(引入 react-modal) 2 | import React, { Component } from 'react' 3 | import { PropTypes, render, Provider } from '../../family' 4 | import './Modal.css' 5 | 6 | /* 7 |
8 |

Title

9 |
10 |
Body
11 |
12 | 13 | 14 |
15 | */ 16 | 17 | class Modal extends Component { 18 | static contextTypes = { 19 | store: PropTypes.object.isRequired, 20 | } 21 | static propTypes = {} 22 | static childContextTypes = {} 23 | $modal: any 24 | $backdrop: any 25 | $dialog: any 26 | static rePosition($dialog: any) { 27 | const left = (document.documentElement.clientWidth - $dialog.clientWidth) / 2 28 | const top = (document.documentElement.clientHeight - $dialog.clientHeight) / 2 29 | $dialog.style.left = left + 'px' 30 | $dialog.style.top = top + 'px' 31 | } 32 | render() { 33 | return null 34 | } 35 | componentDidMount() { 36 | document.body.classList.add('modal-open') 37 | document.body.addEventListener('keyup', this.handleEsc) 38 | window.addEventListener('resize', this.rePosition) 39 | 40 | this.withBackdrop() 41 | this.withPortal(() => { 42 | this.rePosition() 43 | }) 44 | } 45 | componentWillUnmount() { 46 | document.body.classList.remove('modal-open') 47 | document.body.removeEventListener('keyup', this.handleEsc) 48 | window.removeEventListener('resize', this.rePosition) 49 | 50 | document.body.removeChild(this.$modal) 51 | document.body.removeChild(this.$backdrop) 52 | } 53 | withPortal(callback: any) { 54 | if (!this.$modal) { 55 | const $modal = document.createElement('div') 56 | $modal.className = 'modal-portal' 57 | document.body.appendChild($modal) 58 | this.$modal = $modal 59 | } 60 | const dialog = ( 61 | 62 |
{ this.$dialog = $dialog }}> 63 | {this.props.children} 64 | 67 |
68 |
69 | ) 70 | render(dialog, this.$modal, callback) 71 | } 72 | withBackdrop() { 73 | if (!this.$backdrop) { 74 | const $backdrop = document.createElement('div') 75 | $backdrop.className = 'modal-backdrop' 76 | document.body.appendChild($backdrop) 77 | this.$backdrop = $backdrop 78 | } 79 | } 80 | rePosition = () => { 81 | Modal.rePosition(this.$dialog) 82 | } 83 | handleEsc = (e: any) => { 84 | if (e.keyCode === 27) { this.props.onClose() } 85 | } 86 | // if (!this.state.visible) { 87 | // if ($backdrop) document.body.removeChild($backdrop) 88 | // return 89 | // } 90 | // open = (e) => { 91 | // if (e) e.preventDefault() 92 | // this.setState({ visible: true }, () => { 93 | // this.withBackdrop() 94 | // this.withPortal(() => { 95 | // this.rePosition() 96 | // }) 97 | // }) 98 | // } 99 | // close = () => { 100 | // this.setState({ visible: false }, () => { 101 | // this.withBackdrop() 102 | // }) 103 | // } 104 | } 105 | 106 | export default Modal 107 | -------------------------------------------------------------------------------- /src/components/utils/ModalExample.tsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { PropTypes, connect } from '../../family' 3 | import Modal from './Modal' 4 | import './Utils.css' 5 | import { RootState } from 'actions/types' 6 | 7 | class ModalContent extends Component { 8 | static contextTypes = { 9 | store: PropTypes.object.isRequired, 10 | } 11 | static propTypes = { 12 | auth: PropTypes.object.isRequired, 13 | } 14 | render() { 15 | return ( 16 |
17 | {JSON.stringify(this.props.auth)} 18 |
19 | ) 20 | } 21 | } 22 | const mapStateToProps = (state: RootState) => ({ 23 | auth: state.auth, 24 | }) 25 | const mapDispatchToProps = ({}) 26 | 27 | const ModalContentContainer = connect( 28 | mapStateToProps, 29 | mapDispatchToProps 30 | )(ModalContent) 31 | 32 | class ModalExample extends Component { 33 | static contextTypes = {} 34 | constructor(props: any) { 35 | super(props) 36 | this.state = { visible: false } 37 | } 38 | render() { 39 | const visible = this.state.visible 40 | return ( 41 |
42 | 43 | {visible && 44 | this.setState({ visible: false })}> 45 | 46 | 47 | 48 | 49 | } 50 |
51 | ) 52 | } 53 | } 54 | 55 | export default ModalExample 56 | -------------------------------------------------------------------------------- /src/components/utils/NoMatch.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export default ({ location }: any) => ( 4 |
5 | No match for {location.pathname} 6 |
7 | ) 8 | -------------------------------------------------------------------------------- /src/components/utils/Pagination.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sourceRoot":"","sources":["Pagination.sass","../../assets/variables.sass"],"names":[],"mappings":"AAEA;EACE;EACA;;AACA;EACE;EACA;EACA;;AACF;EACE;EACA;EACA;EACA;;AACA;EACE;;AACA;EACE;EACA;EACA;;AACA;EACE;EACA,kBCjBI;;ADoBR;EACE;EACA;EACA;;AAGF;EACE;EACA,kBC7BM","file":"Pagination.css"} -------------------------------------------------------------------------------- /src/components/utils/Pagination.sass: -------------------------------------------------------------------------------- 1 | @import "../../assets/variables.sass" 2 | 3 | .Pagination 4 | display: flex 5 | width: 100% 6 | .summary 7 | align-self: center 8 | padding: 0.325rem 0 9 | flex: 1 10 | .page-list 11 | display: flex 12 | margin: 0 13 | padding-left: 0 14 | list-style: none 15 | .page-item 16 | margin: 0 .2rem 17 | .page-link 18 | display: inline-block 19 | padding: 0.325rem 0.65rem 20 | border-radius: 0.4rem 21 | &:hover 22 | color: white 23 | background-color: $brand-hover 24 | .page-item-disabled 25 | @extend .page-item 26 | .page-link 27 | color: #ccc 28 | pointer-events: none 29 | cursor: not-allowed 30 | .page-item-active 31 | @extend .page-item 32 | .page-link 33 | color: white 34 | background-color: $brand 35 | -------------------------------------------------------------------------------- /src/components/utils/Popover.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sourceRoot":"","sources":["Popover.sass","../../assets/variables.sass"],"names":[],"mappings":";AAEA;EACE;;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,aCOY;EDNZ;;AAEA;EACE;;AACF;EACE;;AACF;EACE;;AACF;EACE;;AAEF;EACE;;AAEF;EACE;EACA;EACA;EACA;EACA;EACA;;AAEF;EACE;EACA;EACA;EACA","file":"Popover.css"} -------------------------------------------------------------------------------- /src/components/utils/Popover.sass: -------------------------------------------------------------------------------- 1 | @import "../../assets/variables.sass" 2 | 3 | .Popover 4 | position: relative 5 | 6 | .popover 7 | position: absolute 8 | top: 0 9 | left: 0 10 | z-index: 1060 11 | max-width: 30rem 12 | display: block 13 | padding: 0 14 | border: 1px solid $border 15 | border-radius: 4px 16 | box-shadow: 0 6px 8px rgba(51, 51, 51, 0.08) 17 | font-family: $font-family 18 | background-color: white 19 | 20 | &.top 21 | margin-top: -10px 22 | &.right 23 | margin-left: 10px 24 | &.bottom 25 | margin-top: 10px 26 | &.left 27 | margin-left: -10px 28 | 29 | .arrow 30 | display: none 31 | 32 | .popover-title 33 | margin: 0 34 | padding: 0.325rem 0.65rem // 8px 14px 35 | border-bottom: 1px solid #ebebeb 36 | border-radius: .4rem .4px 0 0 37 | font-size: 14px 38 | background-color: #fafafa 39 | 40 | .popover-content 41 | margin: 0 42 | padding: 0.325rem 0.65rem // 8px 14px 43 | font-size: 12px 44 | line-height: 22px 45 | -------------------------------------------------------------------------------- /src/components/utils/PopoverExample.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Popover from './Popover' 3 | 4 | export default () => ( 5 |
6 | {['top', 'right', 'bottom', 'left'].map(placement => 7 | 14 | Popover on {placement} 15 | 16 | )} 17 |
18 | ) 19 | -------------------------------------------------------------------------------- /src/components/utils/Portal.tsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { render } from 'react-dom' 3 | 4 | // TODO 2.x http://stackoverflow.com/questions/28802179/how-to-create-a-react-modalwhich-is-append-to-body-with-transitions 5 | 6 | let PORTAL_ID = 1 7 | class Portal extends Component { 8 | $portal: any 9 | render() { return null } 10 | componentDidMount() { 11 | const id = 'Portal-' + PORTAL_ID++ 12 | let $portal = document.getElementById(id) 13 | if (!$portal) { 14 | $portal = document.createElement('div') 15 | $portal.id = id 16 | document.body.appendChild($portal) 17 | } 18 | this.$portal = $portal 19 | this.componentDidUpdate() 20 | } 21 | componentWillUnmount() { 22 | document.body.removeChild(this.$portal) 23 | } 24 | componentDidUpdate() { 25 | render(
{this.props.children}
, this.$portal) 26 | } 27 | } 28 | 29 | export default Portal 30 | -------------------------------------------------------------------------------- /src/components/utils/PropertyEditor.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sourceRoot":"","sources":["PropertyEditor.sass"],"names":[],"mappings":"AAGE;EACE;;AACF;EACE;EACA;;AACF;EACE;;AACF;EACE;;AACF;EACE;;AAEF;EACE;;AACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;EAOE;EACA;EACA;EACA;EACA;EACA;EACA;;AACF;EACE","file":"PropertyEditor.css"} -------------------------------------------------------------------------------- /src/components/utils/PropertyEditor.sass: -------------------------------------------------------------------------------- 1 | @import "../../assets/variables.sass" 2 | 3 | .RuleEditor 4 | .type 5 | flex-basis: 10rem 6 | .rule-wrapper 7 | flex-basis: 10rem 8 | padding-right: 0.65rem 9 | .range-wrapper 10 | padding-right: 0.65rem 11 | .drange-wrapper 12 | padding-right: 0.65rem 13 | .value-wrapper 14 | flex-basis: 15rem 15 | 16 | select 17 | width: 10rem 18 | input.value, 19 | input.count, 20 | input.min, 21 | input.max, 22 | input.dcount, 23 | input.dmin, 24 | input.dmax 25 | padding: .5rem .75rem 26 | border: 1px solid $border 27 | border-radius: .4rem 28 | box-shadow: none 29 | outline: none 30 | width: 2.6rem 31 | text-align: center 32 | input.value 33 | width: 8rem 34 | 35 | -------------------------------------------------------------------------------- /src/components/utils/RChart.tsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import PropTypes from 'prop-types' 3 | import Chart from 'chart.js' 4 | 5 | class RChart extends Component { 6 | static propTypes = { 7 | type: PropTypes.string.isRequired, 8 | width: PropTypes.string, // TODO 非必须,有默认值 16 9 | height: PropTypes.string, // TODO 非必须,有默认值 9 10 | data: PropTypes.object.isRequired, 11 | options: PropTypes.object.isRequired, 12 | } 13 | static COLORS = { 14 | red: 'rgb(255, 99, 132)', 15 | orange: 'rgb(255, 159, 64)', 16 | yellow: 'rgb(255, 205, 86)', 17 | green: 'rgb(75, 192, 192)', 18 | blue: 'rgb(54, 162, 235)', 19 | purple: 'rgb(153, 102, 255)', 20 | grey: 'rgb(201, 203, 207)', 21 | } 22 | $canvas: any 23 | $chart: any 24 | render() { 25 | const width = this.props.width || 16 26 | const height = this.props.height || 9 27 | return ( 28 | { this.$canvas = $canvas }} width={width} height={height} /> 29 | ) 30 | } 31 | componentDidMount() { 32 | const ctx = this.$canvas.getContext('2d') 33 | this.$chart = new Chart(ctx, { 34 | type: this.props.type, 35 | data: this.props.data, 36 | options: this.props.options, 37 | }) 38 | } 39 | } 40 | 41 | export default RChart 42 | -------------------------------------------------------------------------------- /src/components/utils/RCodeMirror.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sourceRoot":"","sources":["RCodeMirror.sass"],"names":[],"mappings":"AAAA;EACE","file":"RCodeMirror.css"} -------------------------------------------------------------------------------- /src/components/utils/RCodeMirror.sass: -------------------------------------------------------------------------------- 1 | .CodeMirror 2 | border: 1px solid #d1d5da 3 | -------------------------------------------------------------------------------- /src/components/utils/RCodeMirror.tsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import CodeMirror from 'codemirror' 3 | import 'codemirror/mode/javascript/javascript' 4 | import 'codemirror/lib/codemirror.css' 5 | import './RCodeMirror.css' 6 | 7 | type RCodeMirrorProps = any 8 | type RCodeMirrorState = any 9 | class RCodeMirror extends Component { 10 | $host: any 11 | cm: any 12 | render() { 13 | return ( 14 |