├── .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 | [](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 |
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 |
7 | - User List
8 | - Sign In
9 | - Sign Up
10 |
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 |
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 |
36 | #{user.id} {user.fullname}
37 | |
38 | {user.email} |
39 |
40 |
41 | onDeleteUser(user.id)} className="operation disabled">删除
42 |
43 | |
44 |
45 | )}
46 |
47 |
48 |
49 |
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 |
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 |
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 |