Compare commits

...

364 Commits

Author SHA1 Message Date
caishi 705bfb07bd Merge branch 'develop' 2021-05-08 16:53:26 +08:00
caishi 202081bbeb 样式 2021-05-08 16:53:16 +08:00
caishi d783d998fc 编辑合并请求-url地址错误 2021-05-08 14:36:12 +08:00
caishi af8872176c 编辑合并请求-url地址错误 2021-05-08 14:24:02 +08:00
caishi 037a79de67 detail+同步镜像type=2的才不需要合并请求 2021-05-07 17:33:41 +08:00
caishi 51925542b8 Merge branch 'develop'
# Conflicts:
#	public/css/edu-purge.css
2021-05-07 16:37:21 +08:00
caishi a408d435f3 统一项目简介、项目概览 2021-05-07 16:26:50 +08:00
caishi 016f7f1a7e 去掉Markdown代码块的间隔色、编号等+issue 2021-05-07 16:00:57 +08:00
caishi ff06efe109 merge develop 2021-05-06 17:15:43 +08:00
caishi c33561c212 新建项目-maxlength 2021-05-06 17:14:42 +08:00
caishi 2deb6f8f9d 设置所有标签的marginbottom为0 2021-05-06 17:14:30 +08:00
caishi 63d69a955e 代码库-提交描述未换行 2021-05-06 17:14:19 +08:00
caishi e7eceb5b23 issue-字符限制 2021-05-06 17:12:42 +08:00
caishi c28ae9adb3 Revert "设置所有标签的marginbottom为0"
This reverts commit 227b686046.
2021-05-06 15:15:02 +08:00
caishi 870fbaa2a9 新建项目-maxlength 2021-05-06 14:59:54 +08:00
caishi 227b686046 设置所有标签的marginbottom为0 2021-05-06 10:56:09 +08:00
caishi 582f7a39b3 代码库-提交描述未换行 2021-05-06 10:14:06 +08:00
caishi ac4b7542e2 撤销隐藏-资源库 2021-04-28 20:22:54 +08:00
caishi 3a3a0251aa Merge branch 'undo' into develop
# Conflicts:
#	src/forge/Component/SearchUser.jsx
2021-04-28 20:17:59 +08:00
caishi 2fcb645d42 04-28休假期修改issue --需合并至其它分支(合并请求相关) 2021-04-28 20:17:30 +08:00
caishi 93a53e2c7f 转移项目-bug 2021-04-27 18:44:40 +08:00
caishi 79d8f4e5ad 清空弹窗里的内容 2021-04-27 18:27:56 +08:00
caishi ae34240bfb 通知-跳转 2021-04-27 17:46:05 +08:00
caishi 4d652d238d 不能修改组织账号 2021-04-27 17:25:00 +08:00
caishi efaf0c29b5 不能修改组织账号 2021-04-27 17:24:48 +08:00
caishi 81ad2358f5 不能修改组织账号 2021-04-27 17:23:58 +08:00
caishi 605d5a047d merge undo 2021-04-27 17:15:07 +08:00
caishi 1474f5d3fe 转移项目-bug和修改需求 2021-04-27 17:12:00 +08:00
caishi 8d509f1473 组织地址、website的问题,可合并至develop 2021-04-27 17:11:37 +08:00
caishi 4ba63fd8fa 项目转移-转移权限 2021-04-27 13:50:05 +08:00
caishi e10f9893e0 组织团队-无数据显示错误 2021-04-27 09:46:39 +08:00
caishi 63d7045444 组织团队-无数据显示错误 2021-04-27 09:46:29 +08:00
caishi 6da4dbc165 组织团队-无数据显示错误 2021-04-27 09:45:14 +08:00
caishi c0ddd6eaee 组织-项目列表显示name 2021-04-26 17:20:54 +08:00
caishi f65f4c273a 组织基本设置-正则和新建的页面不一致 2021-04-26 16:32:12 +08:00
caishi 0cdb491433 组织基本设置-正则和新建的页面不一致 2021-04-26 16:32:03 +08:00
caishi ac47ba1b29 组织基本设置-正则和新建的页面不一致 2021-04-26 16:31:26 +08:00
caishi 2bd6f9cb1e 组织-新增地址和网址的显示 2021-04-26 16:17:21 +08:00
caishi 0636e0a925 转移项目-修改1 2021-04-26 16:17:04 +08:00
caishi 631b05dfd6 代码库编辑文件-切换到其它目录后要重新将编辑状态改为显示状态 2021-04-26 15:00:31 +08:00
caishi 4e48b0b363 项目转移--整体数据绑定 2021-04-26 14:59:19 +08:00
caishi 1af504825c 代码库编辑文件-切换到其它目录后要重新将编辑状态改为显示状态 2021-04-25 18:00:05 +08:00
caishi fb41baacc1 代码库编辑文件-切换到其它目录后要重新将编辑状态改为显示状态 2021-04-25 17:46:38 +08:00
caishi 09065383c1 转移项目-前端页面已画完 2021-04-25 17:38:47 +08:00
caishi e94cf68cc5 样式覆盖 2021-04-23 18:04:49 +08:00
caishi c32e215b27 样式覆盖 2021-04-23 18:04:07 +08:00
caishi 5fa2fd99b9 Merge branch 'develop' 2021-04-23 14:51:04 +08:00
caishi 2f6597355c +上 关注后不需要提示 2021-04-23 14:50:52 +08:00
caishi 20ab8a6683 Merge branch 'develop' 2021-04-23 14:47:50 +08:00
caishi 1eb3c20af4 +上 贡献者悬浮框里增加的跳转链接不要新开页 2021-04-23 14:47:32 +08:00
caishi afb599f5be 贡献者-悬浮内容增加跳转链接 2021-04-23 14:46:11 +08:00
caishi a7f709a663 Merge branch 'develop' 2021-04-23 14:16:30 +08:00
caishi d6d6df806d imageUrl + / 2021-04-23 14:14:06 +08:00
caishi 6cc97bd039 个人中心关注-关注或者取消关注未更新状态 2021-04-23 11:49:56 +08:00
caishi 037150a63c 贡献者-悬浮卡片-测试版1 2021-04-23 11:15:14 +08:00
caishi 63c2cfed70 Merge branch 'develop' 2021-04-22 10:58:30 +08:00
caishi 52dc63362b 发布评论者头像路径错误 2021-04-22 10:58:11 +08:00
caishi 29e3f0d59d 新建组织-组织账号正则 2021-04-21 16:55:10 +08:00
caishi 233e6a8226 底部样式+新建组织账号正则 2021-04-21 16:54:47 +08:00
caishi 80cd6fbae0 md文件要用Markdown渲染 2021-04-20 15:33:21 +08:00
caishi 8fa31edaae md文件要用Markdown渲染 2021-04-20 15:31:49 +08:00
caishi 49d3db6746 合并请求-提出申请者头像显示问题 2021-04-20 11:18:44 +08:00
caishi ffbb5ba34e 合并请求-提出申请者头像显示问题 2021-04-20 11:17:54 +08:00
caishi bc11ec68e3 注释 2021-04-20 10:57:46 +08:00
caishi 2d2deec224 Merge branch 'develop' 2021-04-20 10:56:50 +08:00
caishi a67cabbfb4 团队项目-团队项目管理-显示的name和跳转的login 2021-04-20 10:54:20 +08:00
caishi ceb1915939 切换左侧目录,选择不同的文件时,文件详情没有更新 2021-04-20 10:30:47 +08:00
caishi 4c65e1981e all-默认头像(首字母加背景颜色) 2021-04-20 09:36:49 +08:00
caishi 09598d0e2c 个人主页头像url 2021-04-19 19:54:57 +08:00
caishi e09490d424 上线后的getImageURL也不用在前面加/ + 一些小样式修改 2021-04-19 18:19:21 +08:00
caishi a42a670146 头像url--接口会返回所有带images的字段值,所以前端不用加固定的内容了 2021-04-19 17:52:01 +08:00
caishi b8d40259e5 readme-文件增加一个目录下拉icon 2021-04-19 16:58:30 +08:00
caishi 487a2f0495 组织团队-新增一个团队标识 2021-04-19 11:53:19 +08:00
caishi ab34369642 新建团队板块无边框 2021-04-19 10:54:02 +08:00
caishi f12228aa51 组织详情显示nickname 2021-04-19 10:35:20 +08:00
caishi 5477c41f78 资源库不需要按引用次数排序 2021-04-14 10:31:33 +08:00
caishi dc05f9ce35 组织-项目-切换协作者管理和团队管理时会重复调用增加成员接口 2021-04-13 17:12:37 +08:00
caishi b601582d15 资源库数量显示错误 2021-04-13 11:14:04 +08:00
caishi 832b18e7f5 组织-团队列表的头像login为undefined 2021-04-13 11:06:09 +08:00
caishi 8c58f77afb 去掉右侧悬浮手册按钮 2021-04-09 14:18:44 +08:00
caishi 2c363965dd 去掉悬浮手册按钮 2021-04-09 13:58:58 +08:00
caishi 60a7f39c16 forge项目暂时不显示命令行功能 2021-04-09 11:45:04 +08:00
caishi 9811276a7c ssh-3(前端固定参数已调通) 2021-04-09 10:12:39 +08:00
caishi a27c74b9aa ssh-2 2021-04-08 18:14:19 +08:00
caishi 80cae93045 ssh-初步 2021-04-08 17:44:31 +08:00
caishi 78aba67917 项目详情右侧增加实践课程链接的显示 2021-04-08 15:37:01 +08:00
caishi 43223c7787 为2时不支持在线创建、在线上传、在线修改、在线删除、创建合并请求等功能 2021-04-08 14:21:35 +08:00
caishi 961587921a projectDetail.type:0是托管项目,1是镜像项目,2是同步镜像项目(为2时不能上传新建文件、下载zip等) 2021-04-08 10:07:55 +08:00
caishi 2f595d750a entries接口传的branch值为undefined 2021-04-07 18:44:20 +08:00
caishi bcaec7a2db 新增组织账号,组织名称增加新的check条件 2021-04-06 18:40:01 +08:00
caishi 70ea6259ae 仓库设置页面增加资源库配置项 2021-04-06 17:34:37 +08:00
caishi 5d6953f2b3 资源库模块测试版第一次上线 2021-04-06 17:17:01 +08:00
caishi c8eda704e5 列表的type字段为头像跳转到个人中心或者组织的判断依据 2021-04-06 11:45:03 +08:00
caishi 5d6b95ab8f 资源库部分接口调试 2021-04-06 11:36:38 +08:00
caishi 426ea3fece 合并请求分页 2021-04-02 18:55:26 +08:00
caishi ab052ebace 第三方登录-修改邮箱和密码 2021-04-02 18:40:59 +08:00
caishi 648c6e235b 第三方账号密码重置 2021-04-02 17:39:13 +08:00
caishi 96253f3f58 列表接口、上传资源 2021-04-02 17:31:15 +08:00
caishi 101478d924 协作者管理删除按钮没显示 2021-04-02 14:08:59 +08:00
caishi dccbd6735d 构建列表里的提交信息,作者头像错误 2021-04-02 11:57:48 +08:00
caishi a0ebba839e tips 2021-04-01 19:03:56 +08:00
caishi 171f14bd2a noticeurl 2021-04-01 16:25:53 +08:00
caishi c3e09f2672 第三方登录-educoder 2021-04-01 15:35:45 +08:00
caishi 6296434527 清理appconfig文件
资源库所有页面排版、数据未绑
2021-04-01 14:41:13 +08:00
caishi e2dbda3083 工作流author 2021-03-31 17:12:31 +08:00
caishi 02f382e6fb 登录框中的找回密码、注册的url 2021-03-31 11:15:41 +08:00
caishi b568aef34e issue 2021-03-30 15:01:25 +08:00
caishi 2c83221376 按钮 2021-03-30 11:50:25 +08:00
caishi 6a4fe4d277 左侧抽屉 2021-03-30 10:26:02 +08:00
caishi 99f7aea290 资源 2021-03-29 16:48:23 +08:00
caishi 50f39afffa style 2021-03-25 22:06:04 +08:00
caishi d0ccc92cc6 新建项目路由 2021-03-25 22:00:01 +08:00
caishi 2add7911dc readme 2021-03-25 14:38:52 +08:00
caishi ec1ff5d479 简介修改 2021-03-24 14:08:10 +08:00
caishi 55f23dea0d style 2021-03-23 17:58:12 +08:00
caishi 26e74e7ed4 condition 2021-03-23 17:40:23 +08:00
caishi 3384cd2703 style+banner 2021-03-23 09:20:16 +08:00
caishi 0290822ebf 代码库-默认显示 2021-03-22 11:24:07 +08:00
caishi 31edf6ff45 分页 2021-03-22 09:45:30 +08:00
caishi 8a1feed72b 未登录判断 2021-03-19 17:22:02 +08:00
caishi 0c0203a8ef name 2021-03-19 16:34:41 +08:00
caishi 45e69cb14a update 2021-03-19 16:29:43 +08:00
caishi d7f3c766b4 导航栏设置 2021-03-19 15:46:37 +08:00
caishi a3226dca4e banner 2021-03-19 12:11:55 +08:00
caishi d16ee801ec 背景色 2021-03-19 11:35:03 +08:00
caishi c3eb6edddc 项目详情新版 2021-03-18 17:28:53 +08:00
caishi ad8a127170 remove 2021-03-11 18:07:19 +08:00
caishi cbaf72b341 appconfig 2021-03-10 17:32:39 +08:00
caishi a4b5b67da6 diff-查看文件 2021-03-10 10:41:16 +08:00
caishi da31875a5a filedetail 2021-03-09 11:46:41 +08:00
caishi b7a92b17e7 active 2021-03-08 10:26:39 +08:00
caishi f4332db4ad style 2021-03-05 18:35:54 +08:00
caishi 99174c2782 取消上一个commit的修改 2021-03-05 15:59:30 +08:00
caishi f33f1f3ce5 参数管理-权限(仅创建者) 2021-03-05 14:39:59 +08:00
caishi 5d99d63267 style 2021-03-05 10:47:13 +08:00
caishi 9137b666ea style 2021-03-05 09:56:07 +08:00
caishi 1250a9b10b 删除 2021-03-04 17:05:27 +08:00
caishi 6ea82be73a 工作流-参数管理 2021-03-04 15:08:58 +08:00
caishi 964427b8fc 工作流-参数 2021-03-03 16:43:02 +08:00
caishi afd6904349 loading 2021-03-02 15:43:40 +08:00
caishi 72fcbcd4dd root 2021-03-02 11:40:55 +08:00
caishi 80f1e4d448 查看文件-url 2021-03-02 10:51:50 +08:00
caishi 3071c785bc sync mirror 2021-03-01 16:02:02 +08:00
caishi d01e8e32d4 设置 2021-02-26 15:40:44 +08:00
caishi e469ddae24 删除协作者 2021-02-26 11:57:35 +08:00
caishi f8b9003e15 我关注的-接口错误 2021-02-25 17:06:25 +08:00
caishi 19f66b0bcc 关注和取消关注 2021-02-25 14:08:35 +08:00
caishi 2ceaead909 fork列表 2021-02-24 15:45:48 +08:00
caishi 8d386ff70b tips 2021-02-24 15:27:58 +08:00
caishi d11cb7fc40 small problem 2021-02-24 10:53:17 +08:00
caishi 696fb22a58 class name 2021-02-23 17:26:52 +08:00
caishi 67b510923b 发行版 -loading 2021-02-23 14:45:18 +08:00
caishi ad3c9f837f 新建标签 2021-02-23 11:00:05 +08:00
caishi b8476cec1a nodata tip 2021-02-22 17:50:47 +08:00
caishi fcd859638e spining 2021-02-22 15:27:51 +08:00
caishi 518d341ed5 issues 2021-02-22 10:17:52 +08:00
caishi b4a608bcc3 img-siaze 2021-02-07 16:50:14 +08:00
caishi 658fd1b4f9 权限 2021-02-06 15:30:56 +08:00
caishi 58228e90c7 project 镜像、fork 2021-02-06 10:42:32 +08:00
caishi 10466ac4a2 标签长度 2021-02-06 10:18:05 +08:00
caishi 98d40482f3 issue 2021-02-05 16:19:35 +08:00
caishi 03cd10f599 新建团队 2021-02-04 18:31:27 +08:00
caishi 59836f69d0 f 2021-02-04 18:18:15 +08:00
caishi 591974aa6d 权限 2021-02-04 18:02:37 +08:00
caishi eaa46dbcee 项目-团队管理 2021-02-04 17:47:30 +08:00
caishi 0c5dd61fdc new 2021-02-04 14:54:26 +08:00
caishi 26d2e0f541 fix 2021-02-03 18:41:01 +08:00
caishi daa5cc212c 用户 url 2021-02-03 17:00:46 +08:00
caishi 7a8cbac912 Merge branch 'develop' into dev_orgnize 2021-02-03 15:53:24 +08:00
caishi 3b208ba751 组织 all over 2021-02-03 15:53:15 +08:00
caishi 9380c0172c meg 2021-02-02 18:26:55 +08:00
caishi 34ba476011 bug 2021-02-02 14:20:31 +08:00
caishi 185228d4b6 dispose 2021-02-02 13:46:22 +08:00
caishi cae10cec2a new 2021-02-02 12:22:47 +08:00
caishi 006ceff8fc bug 2021-02-02 10:05:16 +08:00
caishi c71d8512df issue 2021-02-02 09:49:03 +08:00
caishi 3b85567a1a new page 2021-02-02 09:31:15 +08:00
caishi ea77a13b6f url 2021-02-01 16:53:33 +08:00
caishi fcf03f2631 团队设置 2021-02-01 16:43:25 +08:00
caishi e65a1debc5 参数 2021-02-01 15:28:24 +08:00
caishi a2406bbf4b 组织团队 2021-02-01 15:20:38 +08:00
caishi eee8d4659c bug 2021-02-01 11:10:51 +08:00
Sylor-huang 7eef81b91a add team codes 2021-01-31 22:24:46 +08:00
Sylor-huang bd85703412 add group setting pages 2021-01-30 22:06:52 +08:00
Sylor-huang 7a2d1b7db1 add group setting 2021-01-30 21:12:26 +08:00
caishi 828cc2470d 个人中心-我的组织 2021-01-29 17:26:08 +08:00
caishi 7b7b206741 Merge branch 'develop' into dev_orgnize 2021-01-29 14:45:34 +08:00
caishi 5181d636d9 工作流配置-模板管理 2021-01-29 14:17:49 +08:00
caishi f68842beff 组织-基本管理 2021-01-28 11:48:21 +08:00
caishi 6deb8db08f Merge branch 'develop' into dev_orgnize 2021-01-25 16:01:49 +08:00
caishi 3a2d93c3a6 version 2021-01-25 16:01:18 +08:00
caishi b71980f6dc issue 2021-01-25 15:22:45 +08:00
caishi 586d9e0c05 新建组织 2021-01-25 10:49:39 +08:00
caishi 029bb89b11 新建 2021-01-21 18:01:59 +08:00
caishi 2278d03c47 iconfnt 2021-01-20 20:14:39 +08:00
caishi a22b5b3701 合并develop 2021-01-20 15:22:37 +08:00
caishi df438212c1 Merge branch 'develop' into dev_devopsDispose 2021-01-20 15:21:12 +08:00
caishi e1164875b0 update bug 2021-01-20 11:39:00 +08:00
caishi c53de4ad15 stage 2021-01-20 10:47:59 +08:00
caishi ef22be7e96 remove debug 2021-01-20 10:13:18 +08:00
caishi a235879dd0 update 2021-01-20 10:12:35 +08:00
caishi 0b007b35d9 new 2021-01-19 18:11:38 +08:00
caishi 68935245f0 pulls 权限 2021-01-13 15:46:45 +08:00
caishi f7fe479859 new 2021-01-13 15:46:17 +08:00
caishi 9d0adc0747 pulls 2021-01-13 14:16:18 +08:00
caishi 0e0eee8aaf pulls 2021-01-13 09:49:54 +08:00
caishi 7e47cad744 pullrequest 2021-01-12 17:36:30 +08:00
caishi 5e7fedb471 dispose 2021-01-12 17:25:22 +08:00
caishi 4ef05163d7 about page 2021-01-11 17:18:12 +08:00
caishi 4d9567bb94 Merge branch 'master' into dev_devopsDispose 2021-01-06 16:34:43 +08:00
caishi 246782f961 link 2021-01-06 16:23:59 +08:00
caishi e5d9728807 Merge branch 'develop' 2021-01-06 16:04:09 +08:00
caishi dd8856f7ac forge-工作流配置页改版-分支 2021-01-06 16:03:50 +08:00
caishi 502dfde9a2 详情顶部-为0时不显示 2021-01-05 15:31:26 +08:00
caishi 05ded94662 save 2021-01-05 14:27:35 +08:00
caishi bbe3766a40 工作流已开启和未开启两种状态链接跳转 2021-01-05 10:32:50 +08:00
caishi 05080e7948 工作流 2020-12-31 13:58:44 +08:00
caishi b59e83ee00 Merge branch 'master' of https://git.trustie.net/jasder/forgeplus-react
# Conflicts:
#	package-lock.json
2020-12-30 10:25:21 +08:00
caishi 0a67b9606a update webpack 2020-12-24 14:41:17 +08:00
caishi 2b063bb8f7 动态-user_login 2020-12-24 10:20:29 +08:00
caishi 2905bb41a7 md编辑器的高度 2020-12-24 09:36:02 +08:00
caishi d66b0580b7 issue 2020-12-23 17:39:50 +08:00
caishi d7e0d5b246 name 2020-12-22 10:31:10 +08:00
caishi fac62fc99e remove 2020-12-21 17:59:40 +08:00
caishi e294b14015 readme文件更新 2020-12-21 09:53:36 +08:00
caishi 59a0834300 readme更新 2020-12-21 09:51:59 +08:00
caishi 21b1c8cba3 readme文件内容 2020-12-18 18:24:01 +08:00
caishi 0929200f43 readme文件 2020-12-18 18:20:05 +08:00
caishi 8df79a85d2 Delete 'README.md' 2020-12-18 17:20:45 +08:00
caishi 94a2946d52 readme文件 2020-12-18 17:20:22 +08:00
caishi 5c91569bac c 2020-12-18 17:14:51 +08:00
caishi a4dbda8c5d 分支设置下拉列表不可选择标签 2020-12-18 14:01:38 +08:00
caishi e3c1e7b82f markdown 2020-12-17 17:59:30 +08:00
caishi 7795fe1d04 markdown 2020-12-17 14:35:36 +08:00
caishi 5d0afb265b 镜像设置相关 2020-12-16 13:52:44 +08:00
caishi 45fc4dcdcd position 2020-12-16 11:37:56 +08:00
caishi 2129a222e5 锚点跳转 2020-12-15 18:01:16 +08:00
caishi 68eb499a8c CI服务 2020-12-14 17:04:58 +08:00
caishi 5f36f9306a tag color 2020-12-14 14:12:41 +08:00
caishi e95ef11058 style 2020-12-11 18:14:25 +08:00
caishi 851afbc6c4 小修 2020-12-09 14:19:55 +08:00
caishi ee79efa6de bug 2020-12-08 17:16:07 +08:00
caishi 6b203d9d24 分支设置 2020-12-04 20:30:23 +08:00
caishi 0d1345f957 分支设置 2020-12-04 19:26:14 +08:00
caishi 57363291f1 change 2020-12-01 16:49:24 +08:00
caishi 2ba469f210 分支设置 2020-11-30 16:14:55 +08:00
caishi 06f0c53d3b 工作流分页 2020-11-27 16:29:08 +08:00
caishi 9005106332 clear 2020-11-27 15:43:55 +08:00
caishi 89b78bc046 修改和新建文件branch 2020-11-27 11:59:21 +08:00
caishi a38b74041e babelrc-runtime 2020-11-26 15:45:54 +08:00
caishi ccb5eb8ae5 Merge commit 'ef6559400411d4e9de4072441c9865e226936ba7' into dev_bei
# Conflicts:
#	src/AppConfig.js
2020-11-26 11:21:48 +08:00
caishi ef65594004 babel 2020-11-25 17:25:59 +08:00
caishi b27f0e796d === 2020-11-25 12:39:59 +08:00
caishi 92699347ec 分支设置 2020-11-24 18:00:34 +08:00
caishi 0062e84a45 Merge branch 'dev_bei' into dev_local 2020-11-24 10:47:05 +08:00
caishi 5827e96a53 branch router 2020-11-24 10:46:27 +08:00
caishi 8cc13f77e1 工作流-无权限提示 2020-11-23 15:23:19 +08:00
caishi ac5b50c26d detail 2020-11-23 10:14:29 +08:00
caishi b2eca51bd8 merge.css not found 2020-11-19 09:45:54 +08:00
caishi cbfb9c3ffe 本地版本-注册页面 2020-11-18 11:31:52 +08:00
caishi 1867497d52 detail 2020-11-17 14:08:21 +08:00
caishi d6fa304d01 detail 2020-11-17 09:48:33 +08:00
caishi bf84063a3c root 2020-11-16 16:17:03 +08:00
caishi 43fc24e114 没有数据时tab也不会显示 2020-11-16 14:18:41 +08:00
caishi a2e1b2abd1 version style 2020-11-13 14:26:06 +08:00
caishi 4edef931d5 style 2020-11-13 14:14:49 +08:00
caishi 49795b0682 && 2020-11-12 14:43:33 +08:00
caishi 0c59855e9c bug 2020-11-11 16:09:57 +08:00
caishi ef19107fcd sha link 2020-11-10 18:09:38 +08:00
caishi 0712904506 小bug 2020-11-10 16:56:05 +08:00
caishi 2f755e8d65 diff页面 2020-11-10 16:42:32 +08:00
caishi 0dd33faeb5 合并请求编辑权限 2020-11-09 09:57:15 +08:00
caishi 0dd722d898 router 2020-11-06 22:35:28 +08:00
caishi 2e04851b66 update 2020-11-06 18:41:23 +08:00
caishi f9588407b8 合并请求 2020-11-06 16:30:01 +08:00
caishi e9fef026a6 pr 2020-11-05 11:31:26 +08:00
caishi 5e36abb259 清除选中项-任务 2020-11-02 09:58:19 +08:00
caishi 0cb6986aed 无数据提示 2020-10-30 10:42:02 +08:00
caishi 80ef857048 box top 2020-10-30 10:13:08 +08:00
caishi 5bc172a492 update 2020-10-29 15:40:30 +08:00
caishi e42de09b99 pullrequest 2020-10-28 16:07:45 +08:00
caishi 3591666e5e 搜索时清除选中状态 2020-10-27 16:47:14 +08:00
caishi eb8cae5fb3 细节修改 2020-10-27 14:38:44 +08:00
caishi 8645eb8e1b merge 2020-10-23 10:34:03 +08:00
caishi 02f286ffad Merge branch 'dev_devOps' of https://git.trustie.net/jasder/forgeplus-react into dev_devOps 2020-10-23 10:15:48 +08:00
caishi ee6356daa0 style 2020-10-23 10:15:40 +08:00
caishi 62b99c7921 Merge branch 'dev_chain' of https://git.trustie.net/jasder/forgeplus-react into dev_devOps
# Conflicts:
#	src/forge/Merge/UpdateMerge.js
#	src/forge/Order/Detail.js
#	src/forge/Order/OrderItem.js
#	src/forge/Order/order_form.js
2020-10-22 22:41:16 +08:00
caishi 4ce8e4edd1 文件详情 2020-10-22 22:24:49 +08:00
caishi bba939094c educoder 项目 2020-10-22 19:34:11 +08:00
caishi 8d3c5c4c06 Merge branch 'newVersion_forge' into dev_devOps 2020-10-22 18:20:54 +08:00
caishi d1e7d2e935 image url 2020-10-22 18:20:42 +08:00
caishi ac2ac26036 Merge branch 'newVersion_forge' into dev_devOps 2020-10-21 17:29:35 +08:00
caishi 42ddb67c0e spin 2020-10-21 17:29:25 +08:00
caishi 849f695a78 Merge branch 'newVersion_forge' into dev_devOps 2020-10-21 16:50:15 +08:00
caishi d80f1d32dc 非trustie则新开页 2020-10-21 16:49:59 +08:00
caishi b6dfe2cd4a Merge branch 'newVersion_forge' into dev_devOps
# Conflicts:
#	src/forge/Main/Detail.js
2020-10-19 15:43:53 +08:00
caishi 7edaa9e09c manager/owner 2020-10-19 15:41:10 +08:00
caishi ded423ee2c ismanager 2020-10-19 11:45:58 +08:00
caishi a5657390fe 工作流权限 2020-10-16 17:29:10 +08:00
sylor_huang@126.com 5a8daf7cfe Change NewHeader active 2020-10-16 17:17:14 +08:00
caishi 51c2729916 马上认证 2020-10-16 11:39:12 +08:00
caishi aca923fe07 Merge branch 'newVersion_forge' into dev_devOps 2020-10-16 10:36:04 +08:00
caishi 3949584549 编辑文件-提交至 2020-10-16 10:35:51 +08:00
caishi d029a9ab6f devops流程 2020-10-15 19:44:17 +08:00
caishi 46097ee5e1 Merge branch 'newVersion_forge' into dev_devOps 2020-10-10 15:55:58 +08:00
caishi c66717bf1b Merge branch 'newVersion_forge' into dev_devOps 2020-10-10 10:11:58 +08:00
caishi 8b1b923c92 Merge branch 'newVersion_forge' into dev_devOps 2020-10-09 16:32:59 +08:00
caishi 4afa382c7c Merge branch 'newVersion_forge' into dev_devOps 2020-10-09 16:05:00 +08:00
caishi b27f6d5732 Merge branch 'newVersion_forge' into dev_devOps 2020-10-09 11:45:17 +08:00
caishi 4e657a4c15 Merge branch 'newVersion_forge' into dev_devOps 2020-10-09 10:17:20 +08:00
caishi 229b5a704e Merge branch 'newVersion_forge' into dev_devOps 2020-10-09 09:25:08 +08:00
caishi 69a9137c34 Merge branch 'newVersion_forge' into dev_devOps 2020-10-06 13:25:21 +08:00
caishi 8cee70c195 Merge branch 'newVersion_forge' into dev_devOps
# Conflicts:
#	public/css/iconfont.css
#	public/css/iconfont.eot
#	public/css/iconfont.js
#	public/css/iconfont.json
#	public/css/iconfont.svg
#	public/css/iconfont.ttf
#	public/css/iconfont.woff
#	public/css/iconfont.woff2
2020-10-05 18:03:32 +08:00
caishi f7adc17b5d Merge branch 'newVersion_forge' into dev_devOps 2020-09-30 16:54:43 +08:00
caishi 48d9580e78 Merge branch 'newVersion_forge' into dev_devOps 2020-09-30 16:34:14 +08:00
caishi f3d6e8c6dc Merge branch 'newVersion_forge' into dev_devOps 2020-09-29 11:21:13 +08:00
caishi a14b125d34 Merge branch 'newVersion_forge' into dev_devOps 2020-09-29 10:41:17 +08:00
caishi 593f76bba0 update 2020-09-28 17:56:27 +08:00
caishi 45273782c5 工作流流程更改 2020-09-28 14:51:24 +08:00
caishi c3ed52bc32 Merge branch 'newVersion_forge' into dev_devOps 2020-09-27 13:59:04 +08:00
caishi 8397daec22 Merge branch 'newVersion_forge' into dev_devOps 2020-09-24 10:34:22 +08:00
caishi 1e80457885 Merge branch 'newVersion_forge' into dev_devOps 2020-09-23 21:33:00 +08:00
caishi c052cf715b Merge branch 'newVersion_forge' into dev_devOps 2020-09-23 16:19:21 +08:00
caishi 53e444d85e Merge branch 'newVersion_forge' into dev_devOps 2020-09-16 18:28:03 +08:00
caishi cd6540a84c Merge branch 'newVersion_forge' into dev_devOps 2020-09-16 18:00:07 +08:00
caishi 10d4ad7221 Merge branch 'newVersion_forge' into dev_devOps 2020-09-16 17:48:12 +08:00
caishi 440e7cd91e 头部 2020-09-16 17:10:26 +08:00
Jasder 0991fee06a FIX 局部优化 2020-09-11 17:35:05 +08:00
Jasder 8307c014f6 FIX 项目激活ci服务的认证地址根据用户是否认证的状态来显示 2020-09-11 16:51:23 +08:00
Jasder dace62e2de skilled status css color for ci build 2020-09-11 16:44:15 +08:00
caishi 74ea4d504d 细节 2020-09-10 09:47:09 +08:00
caishi 942e88a6ea selectkeys 2020-09-09 16:50:48 +08:00
caishi 87449bde46 暂无-手动创建 2020-09-09 15:35:22 +08:00
caishi 3060c4bb2b Merge branch 'newVersion_forge' into dev_devOps 2020-09-09 14:20:52 +08:00
caishi b6bc59a775 Merge branch 'newVersion_forge' into dev_devOps 2020-09-09 10:46:56 +08:00
caishi 745179adae Merge branch 'newVersion_forge' into dev_devOps 2020-09-08 14:55:29 +08:00
caishi 15bd20122a Merge branch 'newVersion_forge' into dev_devOps
# Conflicts:
#	src/forge/Images/banner_list_old.png
#	src/forge/Main/list.css
2020-09-08 14:37:05 +08:00
caishi afeff6b0af Merge branch 'newVersion_forge' into dev_devOps 2020-09-08 10:23:28 +08:00
caishi b66c1c01de image 2020-09-07 17:15:03 +08:00
caishi ec98b6ad44 status 2020-09-07 15:29:25 +08:00
caishi e252f168f8 Merge branch 'newVersion_forge' into dev_devOps 2020-09-07 15:02:43 +08:00
caishi 6944406c49 status 2020-09-07 15:02:25 +08:00
caishi 2f09ca4315 link 2020-09-07 12:00:07 +08:00
caishi 4329b89ddf 列表 2020-09-07 11:38:43 +08:00
caishi 30f0fd82de devops-个人中心-权限 2020-09-07 11:00:59 +08:00
caishi 6795e61870 个人中心-工作流CI 2020-09-04 18:00:22 +08:00
caishi 3169867415 merge 2020-09-03 14:16:55 +08:00
caishi d697ad24a7 个人中心-devops 2020-09-03 14:14:49 +08:00
caishi f05b6eb804 loading 2020-09-02 18:09:06 +08:00
caishi d702a92e81 about 2020-09-02 11:29:56 +08:00
caishi 11e58a200c input 2020-09-02 11:29:31 +08:00
sylor_huang@126.com 6d478dd911 Merge branch 'newVersion_forge' into dev_devOps 2020-09-01 11:41:59 +08:00
caishi 15d3102c51 Merge branch 'newVersion_forge' into dev_devOps
# Conflicts:
#	src/forge/Main/CoderRootDirectory.js
2020-08-31 16:37:31 +08:00
caishi bac40864eb update 2020-08-31 14:07:09 +08:00
caishi cccdfeab32 build 2020-08-28 11:58:32 +08:00
caishi 3abbaa8899 devops 2020-08-27 15:15:03 +08:00
caishi 42a1418181 path 2020-08-27 10:26:28 +08:00
caishi ec073cdf71 .json 2020-08-26 18:37:15 +08:00
caishi a09b81df3f devops 2020-08-26 17:11:42 +08:00
caishi a411d2c111 devops 2020-08-26 16:09:27 +08:00
caishi 2f1bac24d5 Merge branch 'newVersion_forge' into dev_devOps
# Conflicts:
#	src/forge/Main/Detail.js
2020-08-21 10:29:08 +08:00
caishi 940c9c0253 工作流 2020-08-09 22:39:58 +08:00
caishi dfbcc09e5b devops 2020-07-31 20:15:28 +08:00
837816638@qq.com 40cc47dd93 样式 2020-07-03 16:21:19 +08:00
260 changed files with 22261 additions and 11618 deletions

16
.babelrc Normal file
View File

@ -0,0 +1,16 @@
{
"presets": [
"es2015",
"react",
"stage-2"
],
"plugins": [[
"transform-runtime",
{
"helpers": false,
"polyfill": false,
"regenerator": true,
"moduleName": "babel-runtime"
}
]]
}

16
README.md Normal file
View File

@ -0,0 +1,16 @@
<h3>前端react环境安装</h3>
<p>1、 安装node v6.9.x此安装包含了node和npm。</p>
<p>2、 安装cnpm命令行 npm install -g cnpm --registry=https://registry.npm.taobao.org</p>
<p>3、 安装依赖的js库public/react目录下<即项目package.json所在目录>,开启命令行): cnpm install</p>
<p>4、 如果你的ruby服务使用的是3000端口则需要在package.json中修改"port"参数的值</p>
<p>5、 启动服务(命令行-目录同3 npm start</p>
<p>6、 build初始化 npm run build</p>
<h3>分支信息:</h3>
<p>相关代码提交到对应分支能上线的代码先提交到develop分支上测试版测试通过后合并提交到master分支上线正式版</p>
<p>master:开发环境(正式环境)</p>
<p>develop:测试环境</p>
<p>dev_local:本地版本</p>
<p>dev_chain:含有区块链相关内容的分支</p>
<p>PS:新增加的需求功能先新建新分支开发在测试版测试没问题后再分别合并到develop和master分支</p>

View File

@ -17,16 +17,7 @@ const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const paths = require("./paths"); const paths = require("./paths");
const getClientEnvironment = require("./env"); const getClientEnvironment = require("./env");
// Some apps do not use client-side routing with pushState.
// For these, "homepage" can be set to "." to enable relative asset paths.
let publicPath = "/react/build/"; let publicPath = "/react/build/";
// let nodeEnv = process.env.NODE_ENV
// if (nodeEnv === 'testBuild') {
// publicPath = 'https://testforgeplus.trustie.net/react/build/';
// }
// if (nodeEnv === 'production') {
// publicPath = 'https://forgeplus.trustie.net/react/build/';
// }
const publicUrl = publicPath.slice(0, -1); const publicUrl = publicPath.slice(0, -1);
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== "false"; const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== "false";
const env = getClientEnvironment(publicPath); const env = getClientEnvironment(publicPath);
@ -141,7 +132,6 @@ module.exports = {
name: "static/media/[name].[hash:8].[ext]", name: "static/media/[name].[hash:8].[ext]",
}, },
}, },
// Process JS with Babel.
{ {
test: /\.(js|jsx|mjs)$/, test: /\.(js|jsx|mjs)$/,
include: paths.appSrc, include: paths.appSrc,
@ -161,10 +151,8 @@ module.exports = {
], ],
}, },
}, },
{ {
test: /\.css$/, test: /\.css$/,
use: [ use: [
{ {
loader: MiniCssExtractPlugin.loader, loader: MiniCssExtractPlugin.loader,

488
package-lock.json generated
View File

@ -1,35 +1,40 @@
{ {
"name": "educoder", "name": "forge",
"version": "0.1.0", "version": "0.1.0",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
"@ant-design/colors": { "@ant-design/colors": {
"version": "3.2.2", "version": "3.2.2",
"resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-3.2.2.tgz", "resolved": "https://registry.npm.taobao.org/@ant-design/colors/download/@ant-design/colors-3.2.2.tgz?cache=0&sync_timestamp=1612935637470&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40ant-design%2Fcolors%2Fdownload%2F%40ant-design%2Fcolors-3.2.2.tgz",
"integrity": "sha512-YKgNbG2dlzqMhA9NtI3/pbY16m3Yl/EeWBRa+lB1X1YaYxHrxNexiQYCLTWO/uDvAjLFMEDU+zR901waBtMtjQ==", "integrity": "sha1-WtQ9YZ6RHzSI66wwPWBuZqhCOQM=",
"requires": { "requires": {
"tinycolor2": "^1.4.1" "tinycolor2": "^1.4.1"
} }
}, },
"@ant-design/create-react-context": { "@ant-design/create-react-context": {
"version": "0.2.5", "version": "0.2.5",
"resolved": "https://registry.npmjs.org/@ant-design/create-react-context/-/create-react-context-0.2.5.tgz", "resolved": "https://registry.npm.taobao.org/@ant-design/create-react-context/download/@ant-design/create-react-context-0.2.5.tgz",
"integrity": "sha512-1rMAa4qgP2lfl/QBH9i78+Gjxtj9FTMpMyDGZsEBW5Kih72EuUo9958mV8PgpRkh4uwPSQ7vVZWXeyNZXVAFDg==", "integrity": "sha1-9fWpFjtHcgl3EoNzl60w4i55+Fg=",
"requires": { "requires": {
"gud": "^1.0.0", "gud": "^1.0.0",
"warning": "^4.0.3" "warning": "^4.0.3"
} }
}, },
"@ant-design/css-animation": {
"version": "1.7.3",
"resolved": "https://registry.npm.taobao.org/@ant-design/css-animation/download/@ant-design/css-animation-1.7.3.tgz?cache=0&sync_timestamp=1596106749762&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40ant-design%2Fcss-animation%2Fdownload%2F%40ant-design%2Fcss-animation-1.7.3.tgz",
"integrity": "sha1-YKHJcAFOhrKPlAUQ1p5QPkKPETY="
},
"@ant-design/icons": { "@ant-design/icons": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-2.1.1.tgz", "resolved": "https://registry.npm.taobao.org/@ant-design/icons/download/@ant-design/icons-2.1.1.tgz",
"integrity": "sha512-jCH+k2Vjlno4YWl6g535nHR09PwCEmTBKAG6VqF+rhkrSPRLfgpU2maagwbZPLjaHuU5Jd1DFQ2KJpQuI6uG8w==" "integrity": "sha1-e5wI3/1PXUHbZn2dvl4BB9C9mko="
}, },
"@ant-design/icons-react": { "@ant-design/icons-react": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/@ant-design/icons-react/-/icons-react-2.0.1.tgz", "resolved": "https://registry.npm.taobao.org/@ant-design/icons-react/download/@ant-design/icons-react-2.0.1.tgz",
"integrity": "sha512-r1QfoltMuruJZqdiKcbPim3d8LNsVPB733U0gZEUSxBLuqilwsW28K2rCTWSMTjmFX7Mfpf+v/wdiFe/XCqThw==", "integrity": "sha1-F6JRNXGrMXrKKSfljOol3THlNvs=",
"requires": { "requires": {
"@ant-design/colors": "^3.1.0", "@ant-design/colors": "^3.1.0",
"babel-runtime": "^6.26.0" "babel-runtime": "^6.26.0"
@ -446,8 +451,8 @@
}, },
"@types/react-slick": { "@types/react-slick": {
"version": "0.23.4", "version": "0.23.4",
"resolved": "https://registry.npmjs.org/@types/react-slick/-/react-slick-0.23.4.tgz", "resolved": "https://registry.npm.taobao.org/@types/react-slick/download/@types/react-slick-0.23.4.tgz",
"integrity": "sha512-vXoIy4GUfB7/YgqubR4H7RALo+pRdMYCeLgWwV3MPwl5pggTlEkFBTF19R7u+LJc85uMqC7RfsbkqPLMQ4ab+A==", "integrity": "sha1-yX4qnn49GTPGhZO46CdS+rHozlM=",
"requires": { "requires": {
"@types/react": "*" "@types/react": "*"
} }
@ -863,9 +868,9 @@
} }
}, },
"antd": { "antd": {
"version": "3.26.16", "version": "3.26.20",
"resolved": "https://registry.npmjs.org/antd/-/antd-3.26.16.tgz", "resolved": "https://registry.nlark.com/antd/download/antd-3.26.20.tgz",
"integrity": "sha512-EYRwlEf8FCPCVRk5yDcgjSZOC0exu+m75SwlSQU+Mh17f9wGhLeL2/DV7/Sra1r+BZlfiahFdkgrLY7UgMMBEQ==", "integrity": "sha1-8/Vw76qllQoUSULyHrKqqgiOlAc=",
"requires": { "requires": {
"@ant-design/create-react-context": "^0.2.4", "@ant-design/create-react-context": "^0.2.4",
"@ant-design/icons": "~2.1.1", "@ant-design/icons": "~2.1.1",
@ -925,16 +930,16 @@
"dependencies": { "dependencies": {
"raf": { "raf": {
"version": "3.4.1", "version": "3.4.1",
"resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", "resolved": "https://registry.npm.taobao.org/raf/download/raf-3.4.1.tgz",
"integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", "integrity": "sha1-B0LpmkplUvRF1z4+4DKK8P8e3jk=",
"requires": { "requires": {
"performance-now": "^2.1.0" "performance-now": "^2.1.0"
} }
}, },
"rc-pagination": { "rc-pagination": {
"version": "1.20.14", "version": "1.20.15",
"resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-1.20.14.tgz", "resolved": "https://registry.npm.taobao.org/rc-pagination/download/rc-pagination-1.20.15.tgz",
"integrity": "sha512-sNKwbFrxiqATqcIIShfrFs8BT03n4UUwTAMYae+JhHTmILQmXdvimEnZbVuWcno6G02DAJcLrFpmkn1h2tmEJw==", "integrity": "sha1-zLTNDpvU5H9y8p6kMsA1C/ez2Ac=",
"requires": { "requires": {
"babel-runtime": "6.x", "babel-runtime": "6.x",
"classnames": "^2.2.6", "classnames": "^2.2.6",
@ -944,8 +949,8 @@
}, },
"rc-rate": { "rc-rate": {
"version": "2.5.1", "version": "2.5.1",
"resolved": "https://registry.npmjs.org/rc-rate/-/rc-rate-2.5.1.tgz", "resolved": "https://registry.npm.taobao.org/rc-rate/download/rc-rate-2.5.1.tgz?cache=0&sync_timestamp=1605573559401&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-rate%2Fdownload%2Frc-rate-2.5.1.tgz",
"integrity": "sha512-3iJkNJT8xlHklPCdeZtUZmJmRVUbr6AHRlfSsztfYTXVlHrv2TcPn3XkHsH+12j812WVB7gvilS2j3+ffjUHXg==", "integrity": "sha1-Vfxf0j6p3MciULmoiYA0efSEKWE=",
"requires": { "requires": {
"classnames": "^2.2.5", "classnames": "^2.2.5",
"prop-types": "^15.5.8", "prop-types": "^15.5.8",
@ -955,8 +960,8 @@
}, },
"rc-select": { "rc-select": {
"version": "9.2.3", "version": "9.2.3",
"resolved": "https://registry.npmjs.org/rc-select/-/rc-select-9.2.3.tgz", "resolved": "https://registry.nlark.com/rc-select/download/rc-select-9.2.3.tgz?cache=0&sync_timestamp=1618886345948&other_urls=https%3A%2F%2Fregistry.nlark.com%2Frc-select%2Fdownload%2Frc-select-9.2.3.tgz",
"integrity": "sha512-WhswxOMWiNnkXRbxyrj0kiIvyCfo/BaRPaYbsDetSIAU2yEDwKHF798blCP5u86KLOBKBvtxWLFCkSsQw1so5w==", "integrity": "sha1-ZDQOLW72TovDz8b0aP/ShiVYmsI=",
"requires": { "requires": {
"babel-runtime": "^6.23.0", "babel-runtime": "^6.23.0",
"classnames": "2.x", "classnames": "2.x",
@ -974,8 +979,8 @@
}, },
"rc-tree": { "rc-tree": {
"version": "2.1.4", "version": "2.1.4",
"resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-2.1.4.tgz", "resolved": "https://registry.npm.taobao.org/rc-tree/download/rc-tree-2.1.4.tgz?cache=0&sync_timestamp=1615350038621&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-tree%2Fdownload%2Frc-tree-2.1.4.tgz",
"integrity": "sha512-Xey794Iavgs8YldFlXcZLOhfcIhlX5Oz/yfKufknBXf2AlZCOkc7aHqSM9uTF7fBPtTGPhPxNEfOqHfY7b7xng==", "integrity": "sha1-73WfPnmaIbQ8Hs+ceU6hwU5wtZs=",
"requires": { "requires": {
"@ant-design/create-react-context": "^0.2.4", "@ant-design/create-react-context": "^0.2.4",
"classnames": "2.x", "classnames": "2.x",
@ -1083,8 +1088,8 @@
}, },
"array-tree-filter": { "array-tree-filter": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/array-tree-filter/-/array-tree-filter-2.1.0.tgz", "resolved": "https://registry.npm.taobao.org/array-tree-filter/download/array-tree-filter-2.1.0.tgz",
"integrity": "sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw==" "integrity": "sha1-hzrAD+yDdJ8lWsjdCDgUtPYykZA="
}, },
"array-union": { "array-union": {
"version": "1.0.2", "version": "1.0.2",
@ -1254,6 +1259,55 @@
"ast-types-flow": "0.0.7" "ast-types-flow": "0.0.7"
} }
}, },
"babel-cli": {
"version": "6.26.0",
"resolved": "https://registry.npm.taobao.org/babel-cli/download/babel-cli-6.26.0.tgz",
"integrity": "sha1-UCq1SHTX24itALiHoGODzgPQAvE=",
"dev": true,
"requires": {
"babel-core": "^6.26.0",
"babel-polyfill": "^6.26.0",
"babel-register": "^6.26.0",
"babel-runtime": "^6.26.0",
"chokidar": "^1.6.1",
"commander": "^2.11.0",
"convert-source-map": "^1.5.0",
"fs-readdir-recursive": "^1.0.0",
"glob": "^7.1.2",
"lodash": "^4.17.4",
"output-file-sync": "^1.1.2",
"path-is-absolute": "^1.0.1",
"slash": "^1.0.0",
"source-map": "^0.5.6",
"v8flags": "^2.1.1"
},
"dependencies": {
"chokidar": {
"version": "1.7.0",
"resolved": "https://registry.npm.taobao.org/chokidar/download/chokidar-1.7.0.tgz?cache=0&sync_timestamp=1602585438968&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fchokidar%2Fdownload%2Fchokidar-1.7.0.tgz",
"integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=",
"dev": true,
"optional": true,
"requires": {
"anymatch": "^1.3.0",
"async-each": "^1.0.0",
"fsevents": "^1.0.0",
"glob-parent": "^2.0.0",
"inherits": "^2.0.1",
"is-binary-path": "^1.0.0",
"is-glob": "^2.0.0",
"path-is-absolute": "^1.0.0",
"readdirp": "^2.0.0"
}
},
"source-map": {
"version": "0.5.7",
"resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.5.7.tgz",
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
"dev": true
}
}
},
"babel-code-frame": { "babel-code-frame": {
"version": "6.26.0", "version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
@ -1273,7 +1327,7 @@
}, },
"babel-core": { "babel-core": {
"version": "6.26.0", "version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.0.tgz", "resolved": "https://registry.npm.taobao.org/babel-core/download/babel-core-6.26.0.tgz",
"integrity": "sha1-rzL3izGm/O8RnIew/Y2XU/A6C7g=", "integrity": "sha1-rzL3izGm/O8RnIew/Y2XU/A6C7g=",
"requires": { "requires": {
"babel-code-frame": "^6.26.0", "babel-code-frame": "^6.26.0",
@ -1299,8 +1353,8 @@
"dependencies": { "dependencies": {
"debug": { "debug": {
"version": "2.6.9", "version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "resolved": "https://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz?cache=0&sync_timestamp=1605791507452&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=",
"requires": { "requires": {
"ms": "2.0.0" "ms": "2.0.0"
} }
@ -1345,6 +1399,17 @@
} }
} }
}, },
"babel-helper-bindify-decorators": {
"version": "6.24.1",
"resolved": "https://registry.npm.taobao.org/babel-helper-bindify-decorators/download/babel-helper-bindify-decorators-6.24.1.tgz",
"integrity": "sha1-FMGeXxQte0fxmlJDHlKxzLxAozA=",
"dev": true,
"requires": {
"babel-runtime": "^6.22.0",
"babel-traverse": "^6.24.1",
"babel-types": "^6.24.1"
}
},
"babel-helper-builder-binary-assignment-operator-visitor": { "babel-helper-builder-binary-assignment-operator-visitor": {
"version": "6.24.1", "version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz", "resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz",
@ -1397,6 +1462,18 @@
"babel-types": "^6.24.1" "babel-types": "^6.24.1"
} }
}, },
"babel-helper-explode-class": {
"version": "6.24.1",
"resolved": "https://registry.npm.taobao.org/babel-helper-explode-class/download/babel-helper-explode-class-6.24.1.tgz",
"integrity": "sha1-fcKjkQ3uAHBW4eMdZAztPVTqqes=",
"dev": true,
"requires": {
"babel-helper-bindify-decorators": "^6.24.1",
"babel-runtime": "^6.22.0",
"babel-traverse": "^6.24.1",
"babel-types": "^6.24.1"
}
},
"babel-helper-function-name": { "babel-helper-function-name": {
"version": "6.24.1", "version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz",
@ -1585,11 +1662,23 @@
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz",
"integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=" "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU="
}, },
"babel-plugin-syntax-async-generators": {
"version": "6.13.0",
"resolved": "https://registry.npm.taobao.org/babel-plugin-syntax-async-generators/download/babel-plugin-syntax-async-generators-6.13.0.tgz",
"integrity": "sha1-a8lj67FuzLrmuStZbrfzXDQqi5o=",
"dev": true
},
"babel-plugin-syntax-class-properties": { "babel-plugin-syntax-class-properties": {
"version": "6.13.0", "version": "6.13.0",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz",
"integrity": "sha1-1+sjt5oxf4VDlixQW4J8fWysJ94=" "integrity": "sha1-1+sjt5oxf4VDlixQW4J8fWysJ94="
}, },
"babel-plugin-syntax-decorators": {
"version": "6.13.0",
"resolved": "https://registry.npm.taobao.org/babel-plugin-syntax-decorators/download/babel-plugin-syntax-decorators-6.13.0.tgz",
"integrity": "sha1-MSVjtNvePMgGzuPkFszurd0RrAs=",
"dev": true
},
"babel-plugin-syntax-dynamic-import": { "babel-plugin-syntax-dynamic-import": {
"version": "6.18.0", "version": "6.18.0",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz",
@ -1620,6 +1709,17 @@
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz",
"integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM=" "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM="
}, },
"babel-plugin-transform-async-generator-functions": {
"version": "6.24.1",
"resolved": "https://registry.npm.taobao.org/babel-plugin-transform-async-generator-functions/download/babel-plugin-transform-async-generator-functions-6.24.1.tgz",
"integrity": "sha1-8FiQAUX9PpkHpt3yjaWfIVJYpds=",
"dev": true,
"requires": {
"babel-helper-remap-async-to-generator": "^6.24.1",
"babel-plugin-syntax-async-generators": "^6.5.0",
"babel-runtime": "^6.22.0"
}
},
"babel-plugin-transform-async-to-generator": { "babel-plugin-transform-async-to-generator": {
"version": "6.24.1", "version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz", "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz",
@ -1641,6 +1741,19 @@
"babel-template": "^6.24.1" "babel-template": "^6.24.1"
} }
}, },
"babel-plugin-transform-decorators": {
"version": "6.24.1",
"resolved": "https://registry.npm.taobao.org/babel-plugin-transform-decorators/download/babel-plugin-transform-decorators-6.24.1.tgz",
"integrity": "sha1-eIAT2PjGtSIr33s0Q5Df13Vp4k0=",
"dev": true,
"requires": {
"babel-helper-explode-class": "^6.24.1",
"babel-plugin-syntax-decorators": "^6.13.0",
"babel-runtime": "^6.22.0",
"babel-template": "^6.24.1",
"babel-types": "^6.24.1"
}
},
"babel-plugin-transform-es2015-arrow-functions": { "babel-plugin-transform-es2015-arrow-functions": {
"version": "6.22.0", "version": "6.22.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz",
@ -1935,7 +2048,7 @@
}, },
"babel-plugin-transform-runtime": { "babel-plugin-transform-runtime": {
"version": "6.23.0", "version": "6.23.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-runtime/-/babel-plugin-transform-runtime-6.23.0.tgz", "resolved": "https://registry.npm.taobao.org/babel-plugin-transform-runtime/download/babel-plugin-transform-runtime-6.23.0.tgz",
"integrity": "sha1-iEkNRGUC6puOfvsP4J7E2ZR5se4=", "integrity": "sha1-iEkNRGUC6puOfvsP4J7E2ZR5se4=",
"requires": { "requires": {
"babel-runtime": "^6.22.0" "babel-runtime": "^6.22.0"
@ -1950,6 +2063,25 @@
"babel-types": "^6.24.1" "babel-types": "^6.24.1"
} }
}, },
"babel-polyfill": {
"version": "6.26.0",
"resolved": "https://registry.npm.taobao.org/babel-polyfill/download/babel-polyfill-6.26.0.tgz",
"integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=",
"dev": true,
"requires": {
"babel-runtime": "^6.26.0",
"core-js": "^2.5.0",
"regenerator-runtime": "^0.10.5"
},
"dependencies": {
"regenerator-runtime": {
"version": "0.10.5",
"resolved": "https://registry.npm.taobao.org/regenerator-runtime/download/regenerator-runtime-0.10.5.tgz?cache=0&sync_timestamp=1595456367497&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fregenerator-runtime%2Fdownload%2Fregenerator-runtime-0.10.5.tgz",
"integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=",
"dev": true
}
}
},
"babel-preset-env": { "babel-preset-env": {
"version": "1.6.1", "version": "1.6.1",
"resolved": "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.6.1.tgz", "resolved": "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.6.1.tgz",
@ -1987,6 +2119,38 @@
"semver": "^5.3.0" "semver": "^5.3.0"
} }
}, },
"babel-preset-es2015": {
"version": "6.24.1",
"resolved": "https://registry.npm.taobao.org/babel-preset-es2015/download/babel-preset-es2015-6.24.1.tgz",
"integrity": "sha1-1EBQ1rwsn+6nAqrzjXJ6AhBTiTk=",
"dev": true,
"requires": {
"babel-plugin-check-es2015-constants": "^6.22.0",
"babel-plugin-transform-es2015-arrow-functions": "^6.22.0",
"babel-plugin-transform-es2015-block-scoped-functions": "^6.22.0",
"babel-plugin-transform-es2015-block-scoping": "^6.24.1",
"babel-plugin-transform-es2015-classes": "^6.24.1",
"babel-plugin-transform-es2015-computed-properties": "^6.24.1",
"babel-plugin-transform-es2015-destructuring": "^6.22.0",
"babel-plugin-transform-es2015-duplicate-keys": "^6.24.1",
"babel-plugin-transform-es2015-for-of": "^6.22.0",
"babel-plugin-transform-es2015-function-name": "^6.24.1",
"babel-plugin-transform-es2015-literals": "^6.22.0",
"babel-plugin-transform-es2015-modules-amd": "^6.24.1",
"babel-plugin-transform-es2015-modules-commonjs": "^6.24.1",
"babel-plugin-transform-es2015-modules-systemjs": "^6.24.1",
"babel-plugin-transform-es2015-modules-umd": "^6.24.1",
"babel-plugin-transform-es2015-object-super": "^6.24.1",
"babel-plugin-transform-es2015-parameters": "^6.24.1",
"babel-plugin-transform-es2015-shorthand-properties": "^6.24.1",
"babel-plugin-transform-es2015-spread": "^6.22.0",
"babel-plugin-transform-es2015-sticky-regex": "^6.24.1",
"babel-plugin-transform-es2015-template-literals": "^6.22.0",
"babel-plugin-transform-es2015-typeof-symbol": "^6.22.0",
"babel-plugin-transform-es2015-unicode-regex": "^6.24.1",
"babel-plugin-transform-regenerator": "^6.24.1"
}
},
"babel-preset-flow": { "babel-preset-flow": {
"version": "6.23.0", "version": "6.23.0",
"resolved": "https://registry.npmjs.org/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz", "resolved": "https://registry.npmjs.org/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz",
@ -2005,7 +2169,7 @@
}, },
"babel-preset-react": { "babel-preset-react": {
"version": "6.24.1", "version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-preset-react/-/babel-preset-react-6.24.1.tgz", "resolved": "https://registry.npm.taobao.org/babel-preset-react/download/babel-preset-react-6.24.1.tgz",
"integrity": "sha1-umnfrqRfw+xjm2pOzqbhdwLJE4A=", "integrity": "sha1-umnfrqRfw+xjm2pOzqbhdwLJE4A=",
"requires": { "requires": {
"babel-plugin-syntax-jsx": "^6.3.13", "babel-plugin-syntax-jsx": "^6.3.13",
@ -2036,6 +2200,31 @@
"babel-preset-react": "6.24.1" "babel-preset-react": "6.24.1"
} }
}, },
"babel-preset-stage-2": {
"version": "6.24.1",
"resolved": "https://registry.npm.taobao.org/babel-preset-stage-2/download/babel-preset-stage-2-6.24.1.tgz",
"integrity": "sha1-2eKWD7PXEYfw5k7sYrwHdnIZvcE=",
"dev": true,
"requires": {
"babel-plugin-syntax-dynamic-import": "^6.18.0",
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-plugin-transform-decorators": "^6.24.1",
"babel-preset-stage-3": "^6.24.1"
}
},
"babel-preset-stage-3": {
"version": "6.24.1",
"resolved": "https://registry.npm.taobao.org/babel-preset-stage-3/download/babel-preset-stage-3-6.24.1.tgz",
"integrity": "sha1-g2raCp56f6N8sTj7kyb4eTSkg5U=",
"dev": true,
"requires": {
"babel-plugin-syntax-trailing-function-commas": "^6.22.0",
"babel-plugin-transform-async-generator-functions": "^6.24.1",
"babel-plugin-transform-async-to-generator": "^6.24.1",
"babel-plugin-transform-exponentiation-operator": "^6.24.1",
"babel-plugin-transform-object-rest-spread": "^6.22.0"
}
},
"babel-register": { "babel-register": {
"version": "6.26.0", "version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz",
@ -3576,8 +3765,8 @@
}, },
"copy-to-clipboard": { "copy-to-clipboard": {
"version": "3.3.1", "version": "3.3.1",
"resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz", "resolved": "https://registry.npm.taobao.org/copy-to-clipboard/download/copy-to-clipboard-3.3.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcopy-to-clipboard%2Fdownload%2Fcopy-to-clipboard-3.3.1.tgz",
"integrity": "sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw==", "integrity": "sha1-EVqhqZmP+rYZb5MHatbaO5E2Yq4=",
"requires": { "requires": {
"toggle-selection": "^1.0.6" "toggle-selection": "^1.0.6"
} }
@ -4663,7 +4852,7 @@
}, },
"dom-closest": { "dom-closest": {
"version": "0.2.0", "version": "0.2.0",
"resolved": "https://registry.npmjs.org/dom-closest/-/dom-closest-0.2.0.tgz", "resolved": "https://registry.npm.taobao.org/dom-closest/download/dom-closest-0.2.0.tgz",
"integrity": "sha1-69n5HRvyLo1vR3h2u80+yQIWwM8=", "integrity": "sha1-69n5HRvyLo1vR3h2u80+yQIWwM8=",
"requires": { "requires": {
"dom-matches": ">=1.0.1" "dom-matches": ">=1.0.1"
@ -4707,7 +4896,7 @@
}, },
"dom-matches": { "dom-matches": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/dom-matches/-/dom-matches-2.0.0.tgz", "resolved": "https://registry.npm.taobao.org/dom-matches/download/dom-matches-2.0.0.tgz",
"integrity": "sha1-0nKLQWqHUzmA6wibhI0lPPI6dYw=" "integrity": "sha1-0nKLQWqHUzmA6wibhI0lPPI6dYw="
}, },
"dom-scroll-into-view": { "dom-scroll-into-view": {
@ -4778,6 +4967,11 @@
"domelementtype": "1" "domelementtype": "1"
} }
}, },
"dompurify": {
"version": "2.0.15",
"resolved": "https://registry.npm.taobao.org/dompurify/download/dompurify-2.0.15.tgz?cache=0&sync_timestamp=1607352578938&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdompurify%2Fdownload%2Fdompurify-2.0.15.tgz",
"integrity": "sha1-gOMA/D6JVHvQrxr/LrqIzhf8neo="
},
"domutils": { "domutils": {
"version": "1.5.1", "version": "1.5.1",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
@ -4824,8 +5018,8 @@
}, },
"draft-js": { "draft-js": {
"version": "0.10.5", "version": "0.10.5",
"resolved": "https://registry.npmjs.org/draft-js/-/draft-js-0.10.5.tgz", "resolved": "https://registry.npm.taobao.org/draft-js/download/draft-js-0.10.5.tgz",
"integrity": "sha512-LE6jSCV9nkPhfVX2ggcRLA4FKs6zWq9ceuO/88BpXdNCS7mjRTgs0NsV6piUCJX9YxMsB9An33wnkMmU2sD2Zg==", "integrity": "sha1-v6m+sBj+BTPbsI1mdcNxprCPp0I=",
"requires": { "requires": {
"fbjs": "^0.8.15", "fbjs": "^0.8.15",
"immutable": "~3.7.4", "immutable": "~3.7.4",
@ -4955,7 +5149,7 @@
}, },
"enquire.js": { "enquire.js": {
"version": "2.1.6", "version": "2.1.6",
"resolved": "https://registry.npmjs.org/enquire.js/-/enquire.js-2.1.6.tgz", "resolved": "https://registry.npm.taobao.org/enquire.js/download/enquire.js-2.1.6.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fenquire.js%2Fdownload%2Fenquire.js-2.1.6.tgz",
"integrity": "sha1-PoeAybi4NQhMP2DhZtvDwqPImBQ=" "integrity": "sha1-PoeAybi4NQhMP2DhZtvDwqPImBQ="
}, },
"entities": { "entities": {
@ -5474,7 +5668,7 @@
}, },
"eventlistener": { "eventlistener": {
"version": "0.0.1", "version": "0.0.1",
"resolved": "https://registry.npmjs.org/eventlistener/-/eventlistener-0.0.1.tgz", "resolved": "https://registry.npm.taobao.org/eventlistener/download/eventlistener-0.0.1.tgz",
"integrity": "sha1-7Suqu4UiJ68rz4iRUscsY8pTLrg=" "integrity": "sha1-7Suqu4UiJ68rz4iRUscsY8pTLrg="
}, },
"events": { "events": {
@ -6888,6 +7082,12 @@
"minipass": "^3.0.0" "minipass": "^3.0.0"
} }
}, },
"fs-readdir-recursive": {
"version": "1.1.0",
"resolved": "https://registry.npm.taobao.org/fs-readdir-recursive/download/fs-readdir-recursive-1.1.0.tgz",
"integrity": "sha1-4y/AMKLM7kSmtTcTCNpUvgs5fSc=",
"dev": true
},
"fs-write-stream-atomic": { "fs-write-stream-atomic": {
"version": "1.0.10", "version": "1.0.10",
"resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz",
@ -7725,7 +7925,7 @@
}, },
"hammerjs": { "hammerjs": {
"version": "2.0.8", "version": "2.0.8",
"resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz", "resolved": "https://registry.npm.taobao.org/hammerjs/download/hammerjs-2.0.8.tgz",
"integrity": "sha1-BO93hiz/K7edMPdpIJWTAiK/YPE=" "integrity": "sha1-BO93hiz/K7edMPdpIJWTAiK/YPE="
}, },
"handle-thing": { "handle-thing": {
@ -8566,7 +8766,7 @@
}, },
"immutable": { "immutable": {
"version": "3.7.6", "version": "3.7.6",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz", "resolved": "https://registry.npm.taobao.org/immutable/download/immutable-3.7.6.tgz",
"integrity": "sha1-E7TTyxK++hVIKib+Gy665kAHHks=" "integrity": "sha1-E7TTyxK++hVIKib+Gy665kAHHks="
}, },
"import-fresh": { "import-fresh": {
@ -8980,9 +9180,9 @@
} }
}, },
"is-mobile": { "is-mobile": {
"version": "2.2.1", "version": "2.2.2",
"resolved": "https://registry.npmjs.org/is-mobile/-/is-mobile-2.2.1.tgz", "resolved": "https://registry.nlark.com/is-mobile/download/is-mobile-2.2.2.tgz",
"integrity": "sha512-6zELsfVFr326eq2CI53yvqq6YBanOxKBybwDT+MbMS2laBnK6Ez8m5XHSuTQQbnKRfpDzCod1CMWW5q3wZYMvA==" "integrity": "sha1-9snF1Q7gElTOBec5vdg18e1OmVQ="
}, },
"is-npm": { "is-npm": {
"version": "1.0.0", "version": "1.0.0",
@ -10154,7 +10354,7 @@
}, },
"lodash.throttle": { "lodash.throttle": {
"version": "4.1.1", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", "resolved": "https://registry.npm.taobao.org/lodash.throttle/download/lodash.throttle-4.1.1.tgz",
"integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=" "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ="
}, },
"lodash.uniq": { "lodash.uniq": {
@ -11209,8 +11409,8 @@
}, },
"omit.js": { "omit.js": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/omit.js/-/omit.js-1.0.2.tgz", "resolved": "https://registry.npm.taobao.org/omit.js/download/omit.js-1.0.2.tgz",
"integrity": "sha512-/QPc6G2NS+8d4L/cQhbk6Yit1WTB6Us2g84A7A/1+w9d/eRGHyEqC5kkQtHVoHZ5NFWGG7tUGgrhVZwgZanKrQ==", "integrity": "sha1-kaFPDrqEBm36AVvzDkdMR/MLyFg=",
"requires": { "requires": {
"babel-runtime": "^6.23.0" "babel-runtime": "^6.23.0"
} }
@ -11339,6 +11539,17 @@
"os-tmpdir": "^1.0.0" "os-tmpdir": "^1.0.0"
} }
}, },
"output-file-sync": {
"version": "1.1.2",
"resolved": "https://registry.npm.taobao.org/output-file-sync/download/output-file-sync-1.1.2.tgz",
"integrity": "sha1-0KM+7+YaIF+suQCS6CZZjVJFznY=",
"dev": true,
"requires": {
"graceful-fs": "^4.1.4",
"mkdirp": "^0.5.1",
"object-assign": "^4.1.0"
}
},
"p-defer": { "p-defer": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz",
@ -14002,9 +14213,9 @@
} }
}, },
"rc-calendar": { "rc-calendar": {
"version": "9.15.10", "version": "9.15.11",
"resolved": "https://registry.npmjs.org/rc-calendar/-/rc-calendar-9.15.10.tgz", "resolved": "https://registry.npm.taobao.org/rc-calendar/download/rc-calendar-9.15.11.tgz",
"integrity": "sha512-xh1A3rYejKskAvkjnd9BcHXFbBnAYsHMGHBdtoAkbwp43B6yEieNL0g0Tzz8s1gApDZV2j5vF1jJ9IIpPYFNLw==", "integrity": "sha1-zh5eqOTXdDW+ZqjHfbEvHw+aNF8=",
"requires": { "requires": {
"babel-runtime": "6.x", "babel-runtime": "6.x",
"classnames": "2.x", "classnames": "2.x",
@ -14017,8 +14228,8 @@
}, },
"rc-cascader": { "rc-cascader": {
"version": "0.17.5", "version": "0.17.5",
"resolved": "https://registry.npmjs.org/rc-cascader/-/rc-cascader-0.17.5.tgz", "resolved": "https://registry.npm.taobao.org/rc-cascader/download/rc-cascader-0.17.5.tgz?cache=0&sync_timestamp=1610107054432&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-cascader%2Fdownload%2Frc-cascader-0.17.5.tgz",
"integrity": "sha512-WYMVcxU0+Lj+xLr4YYH0+yXODumvNXDcVEs5i7L1mtpWwYkubPV/zbQpn+jGKFCIW/hOhjkU4J1db8/P/UKE7A==", "integrity": "sha1-T96R0jt2CMQgJjw47unAaH+A99w=",
"requires": { "requires": {
"array-tree-filter": "^2.1.0", "array-tree-filter": "^2.1.0",
"prop-types": "^15.5.8", "prop-types": "^15.5.8",
@ -14031,8 +14242,8 @@
}, },
"rc-checkbox": { "rc-checkbox": {
"version": "2.1.8", "version": "2.1.8",
"resolved": "https://registry.npmjs.org/rc-checkbox/-/rc-checkbox-2.1.8.tgz", "resolved": "https://registry.npm.taobao.org/rc-checkbox/download/rc-checkbox-2.1.8.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-checkbox%2Fdownload%2Frc-checkbox-2.1.8.tgz",
"integrity": "sha512-6qOgh0/by0nVNASx6LZnhRTy17Etcgav+IrI7kL9V9kcDZ/g7K14JFlqrtJ3NjDq/Kyn+BPI1st1XvbkhfaJeg==", "integrity": "sha1-7t2e+cLzr1s7jlzeUlSqia0aiAo=",
"requires": { "requires": {
"babel-runtime": "^6.23.0", "babel-runtime": "^6.23.0",
"classnames": "2.x", "classnames": "2.x",
@ -14042,8 +14253,8 @@
}, },
"rc-collapse": { "rc-collapse": {
"version": "1.11.8", "version": "1.11.8",
"resolved": "https://registry.npmjs.org/rc-collapse/-/rc-collapse-1.11.8.tgz", "resolved": "https://registry.npm.taobao.org/rc-collapse/download/rc-collapse-1.11.8.tgz?cache=0&sync_timestamp=1606217065785&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-collapse%2Fdownload%2Frc-collapse-1.11.8.tgz",
"integrity": "sha512-8EhfPyScTYljkbRuIoHniSwZagD5UPpZ3CToYgoNYWC85L2qCbPYF7+OaC713FOrIkp6NbfNqXsITNxmDAmxog==", "integrity": "sha1-ZqQAidRpUZ6UJACasckn4hQEHYA=",
"requires": { "requires": {
"classnames": "2.x", "classnames": "2.x",
"css-animation": "1.x", "css-animation": "1.x",
@ -14056,8 +14267,8 @@
}, },
"rc-dialog": { "rc-dialog": {
"version": "7.6.1", "version": "7.6.1",
"resolved": "https://registry.npmjs.org/rc-dialog/-/rc-dialog-7.6.1.tgz", "resolved": "https://registry.npm.taobao.org/rc-dialog/download/rc-dialog-7.6.1.tgz?cache=0&sync_timestamp=1614949683544&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-dialog%2Fdownload%2Frc-dialog-7.6.1.tgz",
"integrity": "sha512-KUKf+2eZ4YL+lnXMG3hR4ZtIhC9glfH27NtTVz3gcoDIPAf3uUvaXVRNoDCiSi+OGKLyIb/b6EoidFh6nQC5Wg==", "integrity": "sha1-EVRczAuUWTT6dgeXJuDYU+UtcF8=",
"requires": { "requires": {
"babel-runtime": "6.x", "babel-runtime": "6.x",
"rc-animate": "2.x", "rc-animate": "2.x",
@ -14066,8 +14277,8 @@
}, },
"rc-drawer": { "rc-drawer": {
"version": "3.1.3", "version": "3.1.3",
"resolved": "https://registry.npmjs.org/rc-drawer/-/rc-drawer-3.1.3.tgz", "resolved": "https://registry.npm.taobao.org/rc-drawer/download/rc-drawer-3.1.3.tgz?cache=0&sync_timestamp=1614159639291&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-drawer%2Fdownload%2Frc-drawer-3.1.3.tgz",
"integrity": "sha512-2z+RdxmzXyZde/1OhVMfDR1e/GBswFeWSZ7FS3Fdd0qhgVdpV1wSzILzzxRaT481ItB5hOV+e8pZT07vdJE8kg==", "integrity": "sha1-y8sE1MB/C2by7OEdhH9KG9gOoLc=",
"requires": { "requires": {
"classnames": "^2.2.6", "classnames": "^2.2.6",
"rc-util": "^4.16.1", "rc-util": "^4.16.1",
@ -14076,8 +14287,8 @@
}, },
"rc-dropdown": { "rc-dropdown": {
"version": "2.4.1", "version": "2.4.1",
"resolved": "https://registry.npmjs.org/rc-dropdown/-/rc-dropdown-2.4.1.tgz", "resolved": "https://registry.npm.taobao.org/rc-dropdown/download/rc-dropdown-2.4.1.tgz?cache=0&sync_timestamp=1600332782526&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-dropdown%2Fdownload%2Frc-dropdown-2.4.1.tgz",
"integrity": "sha512-p0XYn0wrOpAZ2fUGE6YJ6U8JBNc5ASijznZ6dkojdaEfQJAeZtV9KMEewhxkVlxGSbbdXe10ptjBlTEW9vEwEg==", "integrity": "sha1-qu9us6UVLN2ZgolcKnjZtfBGzew=",
"requires": { "requires": {
"babel-runtime": "^6.26.0", "babel-runtime": "^6.26.0",
"classnames": "^2.2.6", "classnames": "^2.2.6",
@ -14088,8 +14299,8 @@
}, },
"rc-editor-core": { "rc-editor-core": {
"version": "0.8.10", "version": "0.8.10",
"resolved": "https://registry.npmjs.org/rc-editor-core/-/rc-editor-core-0.8.10.tgz", "resolved": "https://registry.npm.taobao.org/rc-editor-core/download/rc-editor-core-0.8.10.tgz",
"integrity": "sha512-T3aHpeMCIYA1sdAI7ynHHjXy5fqp83uPlD68ovZ0oClTSc3tbHmyCxXlA+Ti4YgmcpCYv7avF6a+TIbAka53kw==", "integrity": "sha1-byFbxd+cM/+p9sWzDKc6favoq3w=",
"requires": { "requires": {
"babel-runtime": "^6.26.0", "babel-runtime": "^6.26.0",
"classnames": "^2.2.5", "classnames": "^2.2.5",
@ -14102,8 +14313,8 @@
}, },
"rc-editor-mention": { "rc-editor-mention": {
"version": "1.1.13", "version": "1.1.13",
"resolved": "https://registry.npmjs.org/rc-editor-mention/-/rc-editor-mention-1.1.13.tgz", "resolved": "https://registry.npm.taobao.org/rc-editor-mention/download/rc-editor-mention-1.1.13.tgz",
"integrity": "sha512-3AOmGir91Fi2ogfRRaXLtqlNuIwQpvla7oUnGHS1+3eo7b+fUp5IlKcagqtwUBB5oDNofoySXkLBxzWvSYNp/Q==", "integrity": "sha1-nxyrEGX4awFSOEAyF5DCqxKsXos=",
"requires": { "requires": {
"babel-runtime": "^6.23.0", "babel-runtime": "^6.23.0",
"classnames": "^2.2.5", "classnames": "^2.2.5",
@ -14131,9 +14342,9 @@
} }
}, },
"rc-hammerjs": { "rc-hammerjs": {
"version": "0.6.9", "version": "0.6.10",
"resolved": "https://registry.npmjs.org/rc-hammerjs/-/rc-hammerjs-0.6.9.tgz", "resolved": "https://registry.npm.taobao.org/rc-hammerjs/download/rc-hammerjs-0.6.10.tgz",
"integrity": "sha512-4llgWO3RgLyVbEqUdGsDfzUDqklRlQW5VEhE3x35IvhV+w//VPRG34SBavK3D2mD/UaLKaohgU41V4agiftC8g==", "integrity": "sha1-GDGjvY8hmXAL/MWtayCjVjCuteA=",
"requires": { "requires": {
"babel-runtime": "6.x", "babel-runtime": "6.x",
"hammerjs": "^2.0.8", "hammerjs": "^2.0.8",
@ -14141,9 +14352,9 @@
} }
}, },
"rc-input-number": { "rc-input-number": {
"version": "4.5.6", "version": "4.5.9",
"resolved": "https://registry.npmjs.org/rc-input-number/-/rc-input-number-4.5.6.tgz", "resolved": "https://registry.nlark.com/rc-input-number/download/rc-input-number-4.5.9.tgz?cache=0&sync_timestamp=1619578110950&other_urls=https%3A%2F%2Fregistry.nlark.com%2Frc-input-number%2Fdownload%2Frc-input-number-4.5.9.tgz",
"integrity": "sha512-AXbL4gtQ1mSQnu6v/JtMv3UbGRCzLvQznmf0a7U/SAtZ8+dCEAqD4JpJhkjv73Wog53eRYhw4l7ApdXflc9ymg==", "integrity": "sha1-HL9zXiT+I8TrmkMBAxcguV8qPj0=",
"requires": { "requires": {
"babel-runtime": "6.x", "babel-runtime": "6.x",
"classnames": "^2.2.0", "classnames": "^2.2.0",
@ -14154,8 +14365,8 @@
}, },
"rc-mentions": { "rc-mentions": {
"version": "0.4.2", "version": "0.4.2",
"resolved": "https://registry.npmjs.org/rc-mentions/-/rc-mentions-0.4.2.tgz", "resolved": "https://registry.npm.taobao.org/rc-mentions/download/rc-mentions-0.4.2.tgz?cache=0&sync_timestamp=1610510822768&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-mentions%2Fdownload%2Frc-mentions-0.4.2.tgz",
"integrity": "sha512-DTZurQzacLXOfVuiHydGzqkq7cFMHXF18l2jZ9PhWUn2cqvOSY3W4osN0Pq29AOMOBpcxdZCzgc7Lb0r/bgkDw==", "integrity": "sha1-wYq3Ae+55LdbOFGgwNLdaYZA4kY=",
"requires": { "requires": {
"@ant-design/create-react-context": "^0.2.4", "@ant-design/create-react-context": "^0.2.4",
"classnames": "^2.2.6", "classnames": "^2.2.6",
@ -14183,8 +14394,8 @@
}, },
"rc-notification": { "rc-notification": {
"version": "3.3.1", "version": "3.3.1",
"resolved": "https://registry.npmjs.org/rc-notification/-/rc-notification-3.3.1.tgz", "resolved": "https://registry.npm.taobao.org/rc-notification/download/rc-notification-3.3.1.tgz?cache=0&sync_timestamp=1614675471156&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-notification%2Fdownload%2Frc-notification-3.3.1.tgz",
"integrity": "sha512-U5+f4BmBVfMSf3OHSLyRagsJ74yKwlrQAtbbL5ijoA0F2C60BufwnOcHG18tVprd7iaIjzZt1TKMmQSYSvgrig==", "integrity": "sha1-C6o+cPjUCrAVzo+njCYMSQ/HvrQ=",
"requires": { "requires": {
"babel-runtime": "6.x", "babel-runtime": "6.x",
"classnames": "2.x", "classnames": "2.x",
@ -14205,9 +14416,9 @@
} }
}, },
"rc-progress": { "rc-progress": {
"version": "2.5.2", "version": "2.5.3",
"resolved": "https://registry.npmjs.org/rc-progress/-/rc-progress-2.5.2.tgz", "resolved": "https://registry.npm.taobao.org/rc-progress/download/rc-progress-2.5.3.tgz",
"integrity": "sha512-ajI+MJkbBz9zYDuE9GQsY5gsyqPF7HFioZEDZ9Fmc+ebNZoiSeSJsTJImPFCg0dW/5WiRGUy2F69SX1aPtSJgA==", "integrity": "sha1-APAblb2+GFbTpfgiQgUZAui3qOc=",
"requires": { "requires": {
"babel-runtime": "6.x", "babel-runtime": "6.x",
"prop-types": "^15.5.8" "prop-types": "^15.5.8"
@ -14224,8 +14435,8 @@
}, },
"rc-resize-observer": { "rc-resize-observer": {
"version": "0.1.3", "version": "0.1.3",
"resolved": "https://registry.npmjs.org/rc-resize-observer/-/rc-resize-observer-0.1.3.tgz", "resolved": "https://registry.npm.taobao.org/rc-resize-observer/download/rc-resize-observer-0.1.3.tgz?cache=0&sync_timestamp=1608864858155&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-resize-observer%2Fdownload%2Frc-resize-observer-0.1.3.tgz",
"integrity": "sha512-uzOQEwx83xdQSFOkOAM7x7GHIQKYnrDV4dWxtCxyG1BS1pkfJ4EvDeMfsvAJHSYkQXVBu+sgRHGbRtLG3qiuUg==", "integrity": "sha1-CXGR+cOrGG7ZB7VTum71Zd8Rwkk=",
"requires": { "requires": {
"classnames": "^2.2.1", "classnames": "^2.2.1",
"rc-util": "^4.13.0", "rc-util": "^4.13.0",
@ -14253,8 +14464,8 @@
}, },
"rc-slider": { "rc-slider": {
"version": "8.7.1", "version": "8.7.1",
"resolved": "https://registry.npmjs.org/rc-slider/-/rc-slider-8.7.1.tgz", "resolved": "https://registry.npm.taobao.org/rc-slider/download/rc-slider-8.7.1.tgz?cache=0&sync_timestamp=1616675519253&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-slider%2Fdownload%2Frc-slider-8.7.1.tgz",
"integrity": "sha512-WMT5mRFUEcrLWwTxsyS8jYmlaMsTVCZIGENLikHsNv+tE8ThU2lCoPfi/xFNUfJFNFSBFP3MwPez9ZsJmNp13g==", "integrity": "sha1-ntBzYtyTSJo45lSyG4EirXD9PEI=",
"requires": { "requires": {
"babel-runtime": "6.x", "babel-runtime": "6.x",
"classnames": "^2.2.5", "classnames": "^2.2.5",
@ -14268,8 +14479,8 @@
}, },
"rc-steps": { "rc-steps": {
"version": "3.5.0", "version": "3.5.0",
"resolved": "https://registry.npmjs.org/rc-steps/-/rc-steps-3.5.0.tgz", "resolved": "https://registry.npm.taobao.org/rc-steps/download/rc-steps-3.5.0.tgz",
"integrity": "sha512-2Vkkrpa7PZbg7qPsqTNzVDov4u78cmxofjjnIHiGB9+9rqKS8oTLPzbW2uiWDr3Lk+yGwh8rbpGO1E6VAgBCOg==", "integrity": "sha1-NrKn8fSZB7DZA2OISxhiPK+ftgA=",
"requires": { "requires": {
"babel-runtime": "^6.23.0", "babel-runtime": "^6.23.0",
"classnames": "^2.2.3", "classnames": "^2.2.3",
@ -14278,9 +14489,9 @@
} }
}, },
"rc-switch": { "rc-switch": {
"version": "1.9.0", "version": "1.9.2",
"resolved": "https://registry.npmjs.org/rc-switch/-/rc-switch-1.9.0.tgz", "resolved": "https://registry.npm.taobao.org/rc-switch/download/rc-switch-1.9.2.tgz?cache=0&sync_timestamp=1603791200779&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-switch%2Fdownload%2Frc-switch-1.9.2.tgz",
"integrity": "sha512-Isas+egaK6qSk64jaEw4GgPStY4umYDbT7ZY93bZF1Af+b/JEsKsJdNOU2qG3WI0Z6tXo2DDq0kJCv8Yhu0zww==", "integrity": "sha1-eSHHZkEf6aZCZRDDQpAi1rpN/eI=",
"requires": { "requires": {
"classnames": "^2.2.1", "classnames": "^2.2.1",
"prop-types": "^15.5.6", "prop-types": "^15.5.6",
@ -14289,8 +14500,8 @@
}, },
"rc-table": { "rc-table": {
"version": "6.10.15", "version": "6.10.15",
"resolved": "https://registry.npmjs.org/rc-table/-/rc-table-6.10.15.tgz", "resolved": "https://registry.nlark.com/rc-table/download/rc-table-6.10.15.tgz",
"integrity": "sha512-LAr0M/gqt+irOjvPNBLApmQ0CUHNOfKsEBhu1uIuB3OlN1ynA9z+sdoTQyNd9+8NSl0MYnQOOfhtLChAY7nU0A==", "integrity": "sha1-GB9McMT9dPZX7o8jGW5+sIoDZco=",
"requires": { "requires": {
"classnames": "^2.2.5", "classnames": "^2.2.5",
"component-classes": "^1.2.6", "component-classes": "^1.2.6",
@ -14304,8 +14515,8 @@
}, },
"rc-tabs": { "rc-tabs": {
"version": "9.7.0", "version": "9.7.0",
"resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-9.7.0.tgz", "resolved": "https://registry.npm.taobao.org/rc-tabs/download/rc-tabs-9.7.0.tgz?cache=0&sync_timestamp=1608866453009&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-tabs%2Fdownload%2Frc-tabs-9.7.0.tgz",
"integrity": "sha512-kvmgp8/MfLzFZ06hWHignqomFQ5nF7BqKr5O1FfhE4VKsGrep52YSF/1MvS5oe0NPcI9XGNS2p751C5v6cYDpQ==", "integrity": "sha1-rglpW+9ZY9bmTnvBBSHHbf3YRIs=",
"requires": { "requires": {
"@ant-design/create-react-context": "^0.2.4", "@ant-design/create-react-context": "^0.2.4",
"babel-runtime": "6.x", "babel-runtime": "6.x",
@ -14322,8 +14533,8 @@
"dependencies": { "dependencies": {
"raf": { "raf": {
"version": "3.4.1", "version": "3.4.1",
"resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", "resolved": "https://registry.npm.taobao.org/raf/download/raf-3.4.1.tgz",
"integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", "integrity": "sha1-B0LpmkplUvRF1z4+4DKK8P8e3jk=",
"requires": { "requires": {
"performance-now": "^2.1.0" "performance-now": "^2.1.0"
} }
@ -14332,8 +14543,8 @@
}, },
"rc-time-picker": { "rc-time-picker": {
"version": "3.7.3", "version": "3.7.3",
"resolved": "https://registry.npmjs.org/rc-time-picker/-/rc-time-picker-3.7.3.tgz", "resolved": "https://registry.npm.taobao.org/rc-time-picker/download/rc-time-picker-3.7.3.tgz?cache=0&sync_timestamp=1576572941972&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-time-picker%2Fdownload%2Frc-time-picker-3.7.3.tgz",
"integrity": "sha512-Lv1Mvzp9fRXhXEnRLO4nW6GLNxUkfAZ3RsiIBsWjGjXXvMNjdr4BX/ayElHAFK0DoJqOhm7c5tjmIYpEOwcUXg==", "integrity": "sha1-ZajekECTJQrpyCsCpJBeD5leI+I=",
"requires": { "requires": {
"classnames": "2.x", "classnames": "2.x",
"moment": "2.x", "moment": "2.x",
@ -14345,8 +14556,8 @@
"dependencies": { "dependencies": {
"raf": { "raf": {
"version": "3.4.1", "version": "3.4.1",
"resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", "resolved": "https://registry.npm.taobao.org/raf/download/raf-3.4.1.tgz",
"integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", "integrity": "sha1-B0LpmkplUvRF1z4+4DKK8P8e3jk=",
"requires": { "requires": {
"performance-now": "^2.1.0" "performance-now": "^2.1.0"
} }
@ -14355,8 +14566,8 @@
}, },
"rc-tooltip": { "rc-tooltip": {
"version": "3.7.3", "version": "3.7.3",
"resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-3.7.3.tgz", "resolved": "https://registry.npm.taobao.org/rc-tooltip/download/rc-tooltip-3.7.3.tgz?cache=0&sync_timestamp=1614588684791&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-tooltip%2Fdownload%2Frc-tooltip-3.7.3.tgz",
"integrity": "sha512-dE2ibukxxkrde7wH9W8ozHKUO4aQnPZ6qBHtrTH9LoO836PjDdiaWO73fgPB05VfJs9FbZdmGPVEbXCeOP99Ww==", "integrity": "sha1-KArsavyqROjf8EgPuv+eh/wArsw=",
"requires": { "requires": {
"babel-runtime": "6.x", "babel-runtime": "6.x",
"prop-types": "^15.5.8", "prop-types": "^15.5.8",
@ -14404,8 +14615,8 @@
}, },
"rc-tree-select": { "rc-tree-select": {
"version": "2.9.4", "version": "2.9.4",
"resolved": "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-2.9.4.tgz", "resolved": "https://registry.nlark.com/rc-tree-select/download/rc-tree-select-2.9.4.tgz",
"integrity": "sha512-0HQkXAN4XbfBW20CZYh3G+V+VMrjX42XRtDCpyv6PDUm5vikC0Ob682ZBCVS97Ww2a5Hf6Ajmu0ahWEdIEpwhg==", "integrity": "sha1-aqeU4fDmXGbEBqoKKg50/QpVewk=",
"requires": { "requires": {
"classnames": "^2.2.1", "classnames": "^2.2.1",
"dom-scroll-into-view": "^1.2.1", "dom-scroll-into-view": "^1.2.1",
@ -14422,8 +14633,8 @@
"dependencies": { "dependencies": {
"rc-tree": { "rc-tree": {
"version": "2.1.4", "version": "2.1.4",
"resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-2.1.4.tgz", "resolved": "https://registry.npm.taobao.org/rc-tree/download/rc-tree-2.1.4.tgz?cache=0&sync_timestamp=1615350038621&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-tree%2Fdownload%2Frc-tree-2.1.4.tgz",
"integrity": "sha512-Xey794Iavgs8YldFlXcZLOhfcIhlX5Oz/yfKufknBXf2AlZCOkc7aHqSM9uTF7fBPtTGPhPxNEfOqHfY7b7xng==", "integrity": "sha1-73WfPnmaIbQ8Hs+ceU6hwU5wtZs=",
"requires": { "requires": {
"@ant-design/create-react-context": "^0.2.4", "@ant-design/create-react-context": "^0.2.4",
"classnames": "2.x", "classnames": "2.x",
@ -14436,8 +14647,8 @@
}, },
"rc-trigger": { "rc-trigger": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/rc-trigger/-/rc-trigger-3.0.0.tgz", "resolved": "https://registry.nlark.com/rc-trigger/download/rc-trigger-3.0.0.tgz?cache=0&sync_timestamp=1619590696046&other_urls=https%3A%2F%2Fregistry.nlark.com%2Frc-trigger%2Fdownload%2Frc-trigger-3.0.0.tgz",
"integrity": "sha512-hQxbbJpo23E2QnYczfq3Ec5J5tVl2mUDhkqxrEsQAqk16HfADQg+iKNWzEYXyERSncdxfnzYuaBgy764mNRzTA==", "integrity": "sha1-9tmx2oomsrLR2RKgaHbBpIb1mA8=",
"requires": { "requires": {
"babel-runtime": "6.x", "babel-runtime": "6.x",
"classnames": "^2.2.6", "classnames": "^2.2.6",
@ -14449,18 +14660,14 @@
}, },
"dependencies": { "dependencies": {
"rc-animate": { "rc-animate": {
"version": "3.0.0-rc.6", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/rc-animate/-/rc-animate-3.0.0-rc.6.tgz", "resolved": "https://registry.npm.taobao.org/rc-animate/download/rc-animate-3.1.1.tgz?cache=0&sync_timestamp=1601018005635&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-animate%2Fdownload%2Frc-animate-3.1.1.tgz",
"integrity": "sha512-oBLPpiT6Q4t6YvD/pkLcmofBP1p01TX0Otse8Q4+Mxt8J+VSDflLZGIgf62EwkvRwsQUkLPjZVFBsldnPKLzjg==", "integrity": "sha1-3v3YY/VoFsIiU05Nxo/t3s0IE4Y=",
"requires": { "requires": {
"babel-runtime": "6.x", "@ant-design/css-animation": "^1.7.2",
"classnames": "^2.2.5", "classnames": "^2.2.6",
"component-classes": "^1.2.6",
"fbjs": "^0.8.16",
"prop-types": "15.x",
"raf": "^3.4.0", "raf": "^3.4.0",
"rc-util": "^4.5.0", "rc-util": "^4.15.3"
"react-lifecycles-compat": "^3.0.4"
} }
} }
} }
@ -14899,9 +15106,9 @@
} }
}, },
"react-lazy-load": { "react-lazy-load": {
"version": "3.0.13", "version": "3.1.13",
"resolved": "https://registry.npmjs.org/react-lazy-load/-/react-lazy-load-3.0.13.tgz", "resolved": "https://registry.npm.taobao.org/react-lazy-load/download/react-lazy-load-3.1.13.tgz?cache=0&sync_timestamp=1593654792284&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Freact-lazy-load%2Fdownload%2Freact-lazy-load-3.1.13.tgz",
"integrity": "sha1-OwqS0zbUPT8Nc8vm81sXBQsIuCQ=", "integrity": "sha1-I2lD92twhMyEWHFtljKhyYU+pc0=",
"requires": { "requires": {
"eventlistener": "0.0.1", "eventlistener": "0.0.1",
"lodash.debounce": "^4.0.0", "lodash.debounce": "^4.0.0",
@ -15039,8 +15246,8 @@
}, },
"react-slick": { "react-slick": {
"version": "0.25.2", "version": "0.25.2",
"resolved": "https://registry.npmjs.org/react-slick/-/react-slick-0.25.2.tgz", "resolved": "https://registry.nlark.com/react-slick/download/react-slick-0.25.2.tgz",
"integrity": "sha512-8MNH/NFX/R7zF6W/w+FS5VXNyDusF+XDW1OU0SzODEU7wqYB+ZTGAiNJ++zVNAVqCAHdyCybScaUB+FCZOmBBw==", "integrity": "sha1-VjMbZ9R9i8/i3OtqyrHI/VvR9rw=",
"requires": { "requires": {
"classnames": "^2.2.5", "classnames": "^2.2.5",
"enquire.js": "^2.1.6", "enquire.js": "^2.1.6",
@ -15884,8 +16091,8 @@
}, },
"rmc-feedback": { "rmc-feedback": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/rmc-feedback/-/rmc-feedback-2.0.0.tgz", "resolved": "https://registry.npm.taobao.org/rmc-feedback/download/rmc-feedback-2.0.0.tgz",
"integrity": "sha512-5PWOGOW7VXks/l3JzlOU9NIxRpuaSS8d9zA3UULUCuTKnpwBHNvv1jSJzxgbbCQeYzROWUpgKI4za3X4C/mKmQ==", "integrity": "sha1-y8bLOuY8emNe7w4l5PuvWsNm7qo=",
"requires": { "requires": {
"babel-runtime": "6.x", "babel-runtime": "6.x",
"classnames": "^2.2.5" "classnames": "^2.2.5"
@ -16468,8 +16675,8 @@
}, },
"shallow-equal": { "shallow-equal": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.2.1.tgz", "resolved": "https://registry.npm.taobao.org/shallow-equal/download/shallow-equal-1.2.1.tgz",
"integrity": "sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==" "integrity": "sha1-TBar+lYEOqINBQMk76aJQLDaedo="
}, },
"shallowequal": { "shallowequal": {
"version": "1.1.0", "version": "1.1.0",
@ -17010,8 +17217,8 @@
}, },
"source-map-support": { "source-map-support": {
"version": "0.4.18", "version": "0.4.18",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", "resolved": "https://registry.npm.taobao.org/source-map-support/download/source-map-support-0.4.18.tgz?cache=0&sync_timestamp=1587719517036&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsource-map-support%2Fdownload%2Fsource-map-support-0.4.18.tgz",
"integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", "integrity": "sha1-Aoam3ovkJkEzhZTpfM6nXwosWF8=",
"requires": { "requires": {
"source-map": "^0.5.6" "source-map": "^0.5.6"
}, },
@ -18666,6 +18873,12 @@
"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
"integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ=="
}, },
"user-home": {
"version": "1.1.1",
"resolved": "https://registry.npm.taobao.org/user-home/download/user-home-1.1.1.tgz",
"integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=",
"dev": true
},
"util": { "util": {
"version": "0.11.1", "version": "0.11.1",
"resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz",
@ -18717,6 +18930,15 @@
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz",
"integrity": "sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w==" "integrity": "sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w=="
}, },
"v8flags": {
"version": "2.1.1",
"resolved": "https://registry.npm.taobao.org/v8flags/download/v8flags-2.1.1.tgz?cache=0&sync_timestamp=1590964281452&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fv8flags%2Fdownload%2Fv8flags-2.1.1.tgz",
"integrity": "sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ=",
"dev": true,
"requires": {
"user-home": "^1.1.1"
}
},
"validate-npm-package-license": { "validate-npm-package-license": {
"version": "3.0.4", "version": "3.0.4",
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
@ -20254,6 +20476,16 @@
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
"dev": true "dev": true
}, },
"xterm": {
"version": "4.8.1",
"resolved": "https://registry.npm.taobao.org/xterm/download/xterm-4.8.1.tgz",
"integrity": "sha1-FVoXKaQ+Gom0BlJOIsVjQznjnKE="
},
"xterm-addon-fit": {
"version": "0.4.0",
"resolved": "https://registry.npm.taobao.org/xterm-addon-fit/download/xterm-addon-fit-0.4.0.tgz",
"integrity": "sha1-BuDF0KaqrPsAnvVl76HIHpPZAZM="
},
"y18n": { "y18n": {
"version": "3.2.1", "version": "3.2.1",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",

View File

@ -1,5 +1,5 @@
{ {
"name": "educoder", "name": "forge",
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
@ -10,7 +10,6 @@
"array-flatten": "^2.1.2", "array-flatten": "^2.1.2",
"autoprefixer": "7.1.6", "autoprefixer": "7.1.6",
"axios": "^0.18.1", "axios": "^0.18.1",
"babel-core": "6.26.0",
"babel-eslint": "7.2.3", "babel-eslint": "7.2.3",
"babel-jest": "20.0.3", "babel-jest": "20.0.3",
"babel-loader": "7.1.2", "babel-loader": "7.1.2",
@ -27,6 +26,7 @@
"codemirror": "^5.53.0", "codemirror": "^5.53.0",
"connected-react-router": "4.4.1", "connected-react-router": "4.4.1",
"css-loader": "^3.5.2", "css-loader": "^3.5.2",
"dompurify": "^2.0.15",
"dotenv": "4.0.0", "dotenv": "4.0.0",
"dotenv-expand": "4.2.0", "dotenv-expand": "4.2.0",
"echarts": "^4.7.0", "echarts": "^4.7.0",
@ -111,7 +111,9 @@
"webpack-dev-server": "^3.10.3", "webpack-dev-server": "^3.10.3",
"webpack-manifest-plugin": "^2.2.0", "webpack-manifest-plugin": "^2.2.0",
"whatwg-fetch": "2.0.3", "whatwg-fetch": "2.0.3",
"wrap-md-editor": "^0.2.20" "wrap-md-editor": "^0.2.20",
"xterm": "4.8.1",
"xterm-addon-fit": "0.4.0"
}, },
"scripts": { "scripts": {
"start": "node --max_old_space_size=15360 scripts/start.js", "start": "node --max_old_space_size=15360 scripts/start.js",
@ -182,7 +184,13 @@
"port": "3007", "port": "3007",
"devDependencies": { "devDependencies": {
"@babel/runtime": "7.0.0-beta.51", "@babel/runtime": "7.0.0-beta.51",
"babel-cli": "^6.26.0",
"babel-core": "^6.26.0",
"babel-plugin-import": "^1.13.0", "babel-plugin-import": "^1.13.0",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-2": "^6.24.1",
"compression-webpack-plugin": "^1.1.12", "compression-webpack-plugin": "^1.1.12",
"concat": "^1.0.3", "concat": "^1.0.3",
"happypack": "^5.0.1", "happypack": "^5.0.1",

File diff suppressed because one or more lines are too long

View File

@ -2325,6 +2325,9 @@ input::-ms-clear {
background-color: #F5F5F5; background-color: #F5F5F5;
} }
.ant-modal-close{
top:8px!important;
}
.newContainer { .newContainer {
min-height: 100%; min-height: 100%;
@ -2343,7 +2346,6 @@ input::-ms-clear {
/*中间部分宽度固定为1200*/ /*中间部分宽度固定为1200*/
.newMain { .newMain {
margin: 0 auto; margin: 0 auto;
padding-bottom: 110px;
min-width: 1200px; min-width: 1200px;
} }
@ -2658,7 +2660,7 @@ a.color-green:hover {
/*百分比宽度*/ /*百分比宽度*/
.width100 { .width100 {
width: 100%; width: 100% !important;
} }
.width89 { .width89 {
@ -4105,21 +4107,6 @@ em.vertical-line {
/* 右侧内容宽度变化的话需要调整posi-search right的值*/ /* 右侧内容宽度变化的话需要调整posi-search right的值*/
/*底部*/
.newFooter {
max-height: 110px;
}
.newFooter {
position: absolute;
bottom: 0;
width: 100%;
background: #323232;
clear: both;
min-width: 1200px;
z-index: 8;
left: 0px;
}
.footercon { .footercon {
border-bottom: 1px solid #47494d; border-bottom: 1px solid #47494d;
@ -6715,4 +6702,13 @@ ul.count_ul li:not(:last-child):after {
} }
input.ant-input-lg::placeholder{ input.ant-input-lg::placeholder{
font-size: 14px !important; font-size: 14px !important;
}
p{
margin-bottom: 0px!important;
}
.toprightNum{
position: absolute;
right: 0px;
top:4px;
color: #999;
} }

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 584 KiB

After

Width:  |  Height:  |  Size: 733 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

111
public/css/merge.css Executable file
View File

@ -0,0 +1,111 @@
.CodeMirror-merge {
position: relative;
white-space: pre;
}
.CodeMirror-merge, .CodeMirror-merge .CodeMirror {
min-height:50px;
}
.CodeMirror-merge-2pane .CodeMirror-merge-pane { width: 48%; }
.CodeMirror-merge-2pane .CodeMirror-merge-gap { width: 4%; }
.CodeMirror-merge-3pane .CodeMirror-merge-pane { width: 31%; }
.CodeMirror-merge-3pane .CodeMirror-merge-gap { width: 3.5%; }
.CodeMirror-merge-pane {
display: inline-block;
white-space: normal;
vertical-align: top;
}
.CodeMirror-merge-pane-rightmost {
position: absolute;
right: 0px;
z-index: 1;
}
.CodeMirror-merge-gap {
z-index: 2;
display: inline-block;
height: 100%;
-moz-box-sizing: border-box;
box-sizing: border-box;
overflow: hidden;
position: relative;
background: #515151;
}
.CodeMirror-merge-scrolllock-wrap {
position: absolute;
bottom: 0; left: 50%;
}
.CodeMirror-merge-scrolllock {
position: relative;
left: -50%;
cursor: pointer;
color: #d8d8d8;
line-height: 1;
}
.CodeMirror-merge-copybuttons-left, .CodeMirror-merge-copybuttons-right {
position: absolute;
left: 0; top: 0;
right: 0; bottom: 0;
line-height: 1;
}
.CodeMirror-merge-copy {
position: absolute;
cursor: pointer;
color: #ce374b;
z-index: 3;
}
.CodeMirror-merge-copy-reverse {
position: absolute;
cursor: pointer;
color: #44c;
}
.CodeMirror-merge-copybuttons-left .CodeMirror-merge-copy { left: 2px; }
.CodeMirror-merge-copybuttons-right .CodeMirror-merge-copy { right: 2px; }
.CodeMirror-merge-r-inserted, .CodeMirror-merge-l-inserted {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12MwuCXy3+CWyH8GBgYGJgYkAABZbAQ9ELXurwAAAABJRU5ErkJggg==);
background-position: bottom left;
background-repeat: repeat-x;
}
.CodeMirror-merge-r-deleted, .CodeMirror-merge-l-deleted {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12M4Kyb2/6yY2H8GBgYGJgYkAABURgPz6Ks7wQAAAABJRU5ErkJggg==);
background-position: bottom left;
background-repeat: repeat-x;
}
.CodeMirror-merge-r-chunk { background: #9a6868; }
.CodeMirror-merge-r-chunk-start { /*border-top: 1px solid #ee8; */}
.CodeMirror-merge-r-chunk-end {/* border-bottom: 1px solid #ee8; */}
.CodeMirror-merge-r-connect { fill:#9a6868;}
.CodeMirror-merge-l-chunk { background: #eef; }
.CodeMirror-merge-l-chunk-start { border-top: 1px solid #88e; }
.CodeMirror-merge-l-chunk-end { border-bottom: 1px solid #88e; }
.CodeMirror-merge-l-connect { fill: #eef; stroke: #88e; stroke-width: 1px; }
.CodeMirror-merge-l-chunk.CodeMirror-merge-r-chunk { background: #dfd; }
.CodeMirror-merge-l-chunk-start.CodeMirror-merge-r-chunk-start { border-top: 1px solid #4e4; }
.CodeMirror-merge-l-chunk-end.CodeMirror-merge-r-chunk-end { border-bottom: 1px solid #4e4; }
.CodeMirror-merge-collapsed-widget:before {
content: "(...)";
}
.CodeMirror-merge-collapsed-widget {
cursor: pointer;
color: #88b;
background: #eef;
border: 1px solid #ddf;
font-size: 90%;
padding: 0 3px;
border-radius: 4px;
}
.CodeMirror-merge-collapsed-line .CodeMirror-gutter-elt { display: none; }

View File

@ -8,18 +8,9 @@
<meta name=”Description” Content=”持续构建协同、共享、可信的软件创建生态开源创作与软件生产相结合,支持大规模群体开展软件协同创新活动”> <meta name=”Description” Content=”持续构建协同、共享、可信的软件创建生态开源创作与软件生产相结合,支持大规模群体开展软件协同创新活动”>
<meta name="theme-color" content="#000000"> <meta name="theme-color" content="#000000">
<link rel="manifest" href="%PUBLIC_URL%/manifest.json"> <link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<!-- <script type="text/javascript">
window.__isR = true; <link rel="stylesheet" type="text/css" href="%PUBLIC_URL%css/iconfont.css">
if ( <link rel="stylesheet" type="text/css" href="%PUBLIC_URL%css/edu-purge.css">
(navigator.userAgent.indexOf('MSIE 9') != -1
|| navigator.userAgent.indexOf('MSIE 10') != -1)
&&
location.pathname.indexOf("/compatibility") == -1) {
location.href = '/compatibility.html'
}
</script> -->
<link rel=" stylesheet" type="text/css" href="%PUBLIC_URL%css/iconfont.css">
<link rel=" stylesheet" type="text/css" href="%PUBLIC_URL%css/edu-purge.css">
<link rel="stylesheet" type="text/css" href="%PUBLIC_URL%css/editormd.min.css"> <link rel="stylesheet" type="text/css" href="%PUBLIC_URL%css/editormd.min.css">
<link rel="stylesheet" type="text/css" href="%PUBLIC_URL%css/merge.css"> <link rel="stylesheet" type="text/css" href="%PUBLIC_URL%css/merge.css">
<%= htmlWebpackPlugin.tags.headTags %> <%= htmlWebpackPlugin.tags.headTags %>
@ -30,6 +21,7 @@
<div id="root" class="page -layout-v -fit widthunit"></div> <div id="root" class="page -layout-v -fit widthunit"></div>
<div id="picture_display" style="display: none;"></div> <div id="picture_display" style="display: none;"></div>
<script src="%PUBLIC_URL%js/jquery-1.8.3.min.js"></script> <script src="%PUBLIC_URL%js/jquery-1.8.3.min.js"></script>
<script src="%PUBLIC_URL%js/js_min_all.js"></script>
<script src="%PUBLIC_URL%js/codemirror/codemirror.js"></script> <script src="%PUBLIC_URL%js/codemirror/codemirror.js"></script>
<script src="%PUBLIC_URL%js/editormd/editormd.min.js"></script> <script src="%PUBLIC_URL%js/editormd/editormd.min.js"></script>
<script src="%PUBLIC_URL%js/codemirror/merge/merge.js"></script> <script src="%PUBLIC_URL%js/codemirror/merge/merge.js"></script>

View File

@ -9,13 +9,7 @@ import {
} from 'react-router-dom'; } from 'react-router-dom';
import axios from 'axios'; import axios from 'axios';
import LoginDialog from './modules/login/LoginDialog'; import LoginDialog from './modules/login/LoginDialog';
import Notcompletedysl from './modules/user/Notcompletedysl'; import 'babel-polyfill';
import Trialapplicationysl from './modules/login/Trialapplicationysl';
import Trialapplicationreview from './modules/user/Trialapplicationreview';
import AccountProfile from "./modules/user/AccountProfile";
import Accountnewprofile from './modules/user/Accountnewprofile';
import Certifiedprofessional from './modules/modals/Certifiedprofessional';
import Loading from './Loading' import Loading from './Loading'
import Loadable from 'react-loadable'; import Loadable from 'react-loadable';
@ -76,6 +70,10 @@ const OrganizeIndex = Loadable({
loader: () => import('./forge/Team/Index'), loader: () => import('./forge/Team/Index'),
loading: Loading, loading: Loading,
}) })
const EducoderLogin = Loadable({
loader: () => import('./modules/login/EducoderLogin'),
loading: Loading,
})
class App extends Component { class App extends Component {
constructor(props) { constructor(props) {
@ -213,18 +211,12 @@ class App extends Component {
<Provider store={store}> <Provider store={store}>
<ConfigProvider locale={zhCN}> <ConfigProvider locale={zhCN}>
<MuiThemeProvider theme={theme}> <MuiThemeProvider theme={theme}>
{/* <Accountnewprofile {...this.props}{...this.state} /> */}
<LoginDialog {...this.props} {...this.state} Modifyloginvalue={() => this.Modifyloginvalue()}></LoginDialog> <LoginDialog {...this.props} {...this.state} Modifyloginvalue={() => this.Modifyloginvalue()}></LoginDialog>
{/* <Notcompletedysl {...this.props} {...this.state}></Notcompletedysl> */}
{/* <Trialapplicationysl {...this.props} {...this.state}></Trialapplicationysl> */}
{/* <Trialapplicationreview {...this.props} {...this.state}></Trialapplicationreview> */}
{/* <AccountProfile {...this.props} {...this.state} /> */}
{/* <Certifiedprofessional {...this.props} {...this.state} ModalCancelsy={this.ModalCancelsy} ModalshowCancelsy={this.ModalshowCancelsy} /> */}
<Router> <Router>
<Switch> <Switch>
{/*项目*/} {/*项目*/}
<Route <Route
path={"/projects/:projectId/ops/:opsId/detail"} path={"/projects/:owner/:projectId/devops/:opsId/detail"}
render={ render={
(props) => { (props) => {
return (<OpsDetail {...this.props} {...props} {...this.state} />) return (<OpsDetail {...this.props} {...props} {...this.state} />)
@ -240,7 +232,14 @@ class App extends Component {
} }
}> }>
</Route> </Route>
<Route
path="/register"
render={
(props) => {
return (<EducoderLogin {...this.props} {...props} {...this.state} />)
}
}
/>
{/*403*/} {/*403*/}
<Route path="/403" component={Shixunauthority} /> <Route path="/403" component={Shixunauthority} />
@ -248,7 +247,7 @@ class App extends Component {
<Route path={"/organize"} <Route path={"/organize"}
render={ render={
(props) => { (props) => {
return (<OrganizeIndex {...this.props} {...props} {...this.state} />) return (<OrganizeIndex {...props} {...this.props} {...this.state} />)
} }
}> }>
</Route> </Route>

View File

@ -2,19 +2,17 @@ import axios from 'axios';
import { requestProxy } from "./indexEduplus2RequestProxy"; import { requestProxy } from "./indexEduplus2RequestProxy";
import { broadcastChannelOnmessage, isDev, queryString } from 'educoder'; import { broadcastChannelOnmessage, isDev, queryString } from 'educoder';
import { notification } from 'antd'; import { notification } from 'antd';
import cookie from 'react-cookies';
import './index.css';
let message501 = false;
import './index.css';
let message501 = false;
broadcastChannelOnmessage('refreshPage', () => { broadcastChannelOnmessage('refreshPage', () => {
window.location.reload() window.location.reload();
}) })
function locationurl(list) { function locationurl(list) {
if (window.location.port === "3007") { if (window.location.port !== "3007") {
window.location.href = list
} else {
window.location.href = list
} }
} }
// TODO 开发期多个身份切换 // TODO 开发期多个身份切换
@ -26,56 +24,22 @@ if (isDev) {
parsed = queryString.parse(_search); parsed = queryString.parse(_search);
} }
debugType = window.location.search.indexOf('debug=t') !== -1 ? 'teacher' : debugType = window.location.search.indexOf('debug=t') !== -1 ? 'teacher' :
window.location.search.indexOf('debug=s') !== -1 ? 'student' : window.location.search.indexOf('debug=s') !== -1 ? 'student' :
window.location.search.indexOf('debug=a') !== -1 ? 'admin' : parsed.debug || 'admin' window.location.search.indexOf('debug=a') !== -1 ? 'admin' : parsed.debug || 'admin'
} }
function clearAllCookie() {
cookie.remove('_educoder_session', { path: '/' });
cookie.remove('autologin_trustie', { path: '/' });
setpostcookie()
}
clearAllCookie();
function setpostcookie() {
const str = window.location.pathname;
if (str.indexOf("/wxcode") !== -1) {
console.log("123")
cookie.remove('_educoder_session', { path: '/' });
cookie.remove('autologin_trustie', { path: '/' });
const _params = window.location.search;
if (_params) {
let _search = _params.split('?')[1];
let _educoder_sessions = _search.split('&')[0].split('=');
cookie.save('_educoder_session', _educoder_sessions[1], { domain: '.educoder.net', path: '/' });
let autologin_trusties = _search.split('&')[1].split('=');
cookie.save('autologin_trustie', autologin_trusties[1], { domain: '.educoder.net', path: '/' });
}
}
}
setpostcookie();
window._debugType = debugType; window._debugType = debugType;
export function initAxiosInterceptors(props) { export function initAxiosInterceptors(props) {
initOnlineOfflineListener() // 判断网络是否连接
// TODO 避免重复的请求 https://github.com/axios/axios#cancellation initOnlineOfflineListener();
var
proxy = "http://localhost:3000"
proxy = "https://testforgeplus.trustie.net"
const requestMap = {}; var proxy = "https://testforgeplus.trustie.net";
window.setfalseInRequestMap = function (keyName) {
requestMap[keyName] = false;
}
//响应前的设置 //响应前的设置
axios.interceptors.request.use( axios.interceptors.request.use(
config => { config => {
setpostcookie() if(config.url.indexOf("http") !== -1) {
clearAllCookie()
if (config.url.indexOf(proxy) !== -1 || config.url.indexOf(':') !== -1) {
return config return config
} }
requestProxy(config) requestProxy(config);
let url = `/api${config.url}`; let url = `/api${config.url}`;
if (`${config[0]}` !== `true`) { if (`${config[0]}` !== `true`) {
@ -89,18 +53,12 @@ export function initAxiosInterceptors(props) {
} else { } else {
config.url = url; config.url = url;
} }
setpostcookie();
}
if (config.url.indexOf('update_file') === -1) {
requestMap[config.url] = true;
window.setTimeout("setfalseInRequestMap('" + config.url + "')", 900)
} }
return config; return config;
}, },
err => { err => {
return Promise.reject(err); return Promise.reject(err);
}); });
axios.interceptors.response.use(function (response) { axios.interceptors.response.use(function (response) {
if (response === undefined) { if (response === undefined) {
@ -149,8 +107,6 @@ export function initAxiosInterceptors(props) {
message501 = false message501 = false
}, 2000); }, 2000);
} }
requestMap[response.config.url] = false;
setpostcookie();
return response; return response;
}, function (error) { }, function (error) {
return Promise.reject(error); return Promise.reject(error);

View File

@ -1,7 +1,4 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import { Spin } from 'antd'; import { Spin } from 'antd';
class Loading extends Component { class Loading extends Component {
@ -12,7 +9,6 @@ class Loading extends Component {
} }
render() { render() {
// Loading
return ( return (
<div className="App" style={{ minHeight: '800px', width: "100%" }}> <div className="App" style={{ minHeight: '800px', width: "100%" }}>
<style> <style>

View File

@ -11,11 +11,26 @@ export function getImageUrl(path) {
// https://www.educoder.net // https://www.educoder.net
// https://testbdweb.trustie.net // https://testbdweb.trustie.net
// const local = 'http://localhost:3000' // const local = 'http://localhost:3000'
const local = 'https://testforgeplus.trustie.net/' const local = 'https://testforgeplus.trustie.net';
if (isDev) { if (isDev) {
return `${local}/${path}` return `${local}/${path}`
} }
return `/${path}`; return `${path}`;
}
export function getImage(path) {
// https://www.educoder.net
// https://testbdweb.trustie.net
// const local = 'http://localhost:3000'
const local = 'https://testforgeplus.trustie.net/';
if(path.indexOf("http://")===-1){
if (isDev) {
return `${local}/images/${path}`
}
return `/${path}`;
}else{
return path;
}
} }
export function getcdnImageUrl(path) { export function getcdnImageUrl(path) {
@ -147,28 +162,28 @@ export function getmyUrl(geturl) {
} }
export function getUploadActionUrl(path, goTest) { export function getUploadActionUrl(path, goTest) {
return `${getUrl()}/api/attachments.json?debug=${window._debugType || 'admin'}`; return `${getUrl()}/api/attachments.json${isDev ?`${isDev ?`?debug=${window._debugType || 'admin'}` : ""}` : ""}`;
} }
export function getUploadLogoActionUrl() { export function getUploadLogoActionUrl() {
return `${getUrl()}/api/resumes/logo.json?debug=${window._debugType || 'admin'}`; return `${getUrl()}/api/resumes/logo.json${isDev ?`?debug=${window._debugType || 'admin'}` : ""}`;
} }
export function getUploadActionUrltwo(id) { export function getUploadActionUrltwo(id) {
return `${getUrlmys()}/api/shixuns/${id}/upload_data_sets.json?debug=${window._debugType || 'admin'}` return `${getUrlmys()}/api/shixuns/${id}/upload_data_sets.json${isDev ?`?debug=${window._debugType || 'admin'}` : ""}`
} }
export function getUploadActionUrlthree() { export function getUploadActionUrlthree() {
return `${getUrlmys()}/api/jupyters/import_with_tpm.json?debug=${window._debugType || 'admin'}` return `${getUrlmys()}/api/jupyters/import_with_tpm.json${isDev ?`?debug=${window._debugType || 'admin'}` : ""}`
} }
export function getupload_git_file(id) { export function getupload_git_file(id) {
return `${getUrlmys()}/api/shixuns/${id}/upload_git_file.json?debug=${window._debugType || 'admin'}` return `${getUrlmys()}/api/shixuns/${id}/upload_git_file.json${isDev ?`?debug=${window._debugType || 'admin'}` : ""}`
} }
export function getUploadActionUrlOfAuth(id) { export function getUploadActionUrlOfAuth(id) {
return `${getUrl()}/api/users/accounts/${id}/auth_attachment.json?debug=${window._debugType || 'admin'}` return `${getUrl()}/api/users/accounts/${id}/auth_attachment.json${isDev ?`?debug=${window._debugType || 'admin'}` : ""}`
} }
export function getRandomNumber(type) { export function getRandomNumber(type) {

View File

@ -64,7 +64,7 @@ function CommentItem({
const commentAvatar = (author) => ( const commentAvatar = (author) => (
<img <img
className="item-flex flex-image" className="item-flex flex-image"
src={author.image_url ? getImageUrl(`images/${author.image_url}`) : 'https://b-ssl.duitang.com/uploads/item/201511/13/20151113110434_kyReJ.jpeg'} src={author.image_url ? getImageUrl(`/${author.image_url}`) : 'https://b-ssl.duitang.com/uploads/item/201511/13/20151113110434_kyReJ.jpeg'}
alt="" alt=""
/> />
); );

View File

@ -38,13 +38,11 @@ export const formatDelta = (deltas) => {
alt="${alt}" alt="${alt}"
/> />
`; `;
// text = "<img src="+url+" width='60px' height='30px' onclick='' alt="+alt+"/>";
} }
} }
formatted.push(text); formatted.push(text);
}); });
console.log(formatted);
return formatted.join(''); return formatted.join('');
} }

View File

@ -4,7 +4,7 @@
export { export {
getUploadLogoActionUrl as getUploadLogoActionUrl, getUploadLogoActionUrl as getUploadLogoActionUrl,
getImageUrl as getImageUrl, getmyUrl as getmyUrl, getRandomNumber as getRandomNumber, getUrl as getUrl, publicSearchs as publicSearchs, getRandomcode as getRandomcode, getUrlmys as getUrlmys, getUrl2 as getUrl2, setImagesUrl as setImagesUrl getImageUrl as getImageUrl,getImage as getImage, getmyUrl as getmyUrl, getRandomNumber as getRandomNumber, getUrl as getUrl, publicSearchs as publicSearchs, getRandomcode as getRandomcode, getUrlmys as getUrlmys, getUrl2 as getUrl2, setImagesUrl as setImagesUrl
, getUploadActionUrl as getUploadActionUrl, getUploadActionUrltwo as getUploadActionUrltwo, getUploadActionUrlthree as getUploadActionUrlthree, getUploadActionUrlOfAuth as getUploadActionUrlOfAuth , getUploadActionUrl as getUploadActionUrl, getUploadActionUrltwo as getUploadActionUrltwo, getUploadActionUrlthree as getUploadActionUrlthree, getUploadActionUrlOfAuth as getUploadActionUrlOfAuth
, getTaskUrlById as getTaskUrlById, TEST_HOST, htmlEncode as htmlEncode, getupload_git_file as getupload_git_file, getcdnImageUrl as getcdnImageUrl , getTaskUrlById as getTaskUrlById, TEST_HOST, htmlEncode as htmlEncode, getupload_git_file as getupload_git_file, getcdnImageUrl as getcdnImageUrl
} from './UrlTool'; } from './UrlTool';
@ -76,10 +76,4 @@ export { default as AliyunUploader } from './components/media/AliyunUploader'
export { default as ImageLayer2 } from './hooks/ImageLayer2' export { default as ImageLayer2 } from './hooks/ImageLayer2'
// 外部 // 外部
export { default as CBreadcrumb } from '../modules/courses/common/CBreadcrumb'
export { CNotificationHOC as CNotificationHOC } from '../modules/courses/common/CNotificationHOC' export { CNotificationHOC as CNotificationHOC } from '../modules/courses/common/CNotificationHOC'
export { default as ModalWrapper } from '../modules/courses/common/ModalWrapper'
export { default as NoneData } from '../modules/courses/coursesPublic/NoneData'
export { default as WordNumberTextarea } from '../modules/modals/WordNumberTextarea'

View File

@ -48,15 +48,15 @@ function buildToc(coll, k, level, ctx) {
}); });
ctx.push("</ul>") ctx.push("</ul>")
} }
ctx.push("</li>") ctx.push("</li>");
k = buildToc(coll, k, level, ctx) k = buildToc(coll, k, level, ctx)
return k return k
} }
export function getTocContent() { export function getTocContent() {
buildToc(toc, 0, 0, ctx) buildToc(toc, 0, 0, ctx);
ctx.push("</ul>") ctx.push("</ul>");
return ctx.join("") return ctx.join("");
} }
const tokenizer = { const tokenizer = {
@ -157,7 +157,6 @@ renderer.heading = function (text, level, raw) {
}) })
return '<h' + level + ' id="' + anchor + '">' + text + '</h' + level + '>' return '<h' + level + ' id="' + anchor + '">' + text + '</h' + level + '>'
} }
marked.setOptions({ marked.setOptions({
silent: true, silent: true,
smartypants: true, smartypants: true,

View File

@ -1,37 +1,58 @@
import React, { useEffect, useRef, useMemo } from "react"; import React, { useEffect, useRef, useMemo } from 'react'
import "katex/dist/katex.min.css"; import 'katex/dist/katex.min.css'
import { renderToString } from 'katex'; import marked, { getTocContent, cleanToc, getMathExpressions, resetMathExpressions } from '../common/marked';
import marked, { getTocContent, cleanToc, getMathExpressions, resetMathExpressions } from "../common/marked";
import 'code-prettify' import 'code-prettify'
import dompurify from 'dompurify';
import { renderToString } from 'katex'
const preRegex = /<pre[^>]*>/g const preRegex = /<pre[^>]*>/g
function _unescape(str) { function _unescape(str) {
let div = document.createElement('div') let div = document.createElement('div')
div.innerHTML = str div.innerHTML = str
return div.childNodes.length === 0 ? "" : div.childNodes[0].nodeValue; return div.childNodes.length === 0 ? "" : div.childNodes[0].nodeValue
} }
export default ({ value = '', className, style = {} }) => {
let str = String(value)
export default ({
value = '',
className,
style = {},
url
}) => {
let str = String(value);
const html = useMemo(() => { const html = useMemo(() => {
let rs = marked(str) let rs = marked(str);
const math_expressions = getMathExpressions() const math_expressions = getMathExpressions();
if (str.match(/\[TOC\]/)) { if (str.match(/\[TOC\]/)) {
rs = rs.replace("<p>[TOC]</p>", getTocContent()) rs = rs.replace("<p>[TOC]</p>", getTocContent())
cleanToc() cleanToc()
} }
rs = rs.replace(/(__special_katext_id_\d+__)/g, (_match, capture) => { rs = rs.replace(/(__special_katext_id_\d+__)/g, (_match, capture) => {
const { type, expression } = math_expressions[capture] const { type, expression } = math_expressions[capture]
return renderToString(_unescape(expression), { displayMode: type === 'block', throwOnError: false, output: 'html' }) return renderToString(_unescape(expression) || '', { displayMode: type === 'block', throwOnError: false, output: 'html' })
}) })
rs = rs.replace(/▁/g, "▁▁▁") rs = rs.replace(/▁/g, "▁▁▁")
resetMathExpressions() resetMathExpressions()
return rs return dompurify.sanitize(rs)
}, [str]) }, [str]);
const el = useRef() // #id
useEffect(()=>{
if(url && url.hash && html){
let u = url.hash;
if(u){
let id = decodeURIComponent(u.split("#")[1]);
let ele = document.getElementById(id);
if(ele){
window.scrollTo(0, ele.offsetTop + 220);
}
}
}
},[url])
const el = useRef();
function onAncherHandler(e) { function onAncherHandler(e) {
let target = e.target let target = e.target
if (target.tagName.toUpperCase() === 'A') { if (target.tagName.toUpperCase() === 'A') {
@ -40,7 +61,7 @@ export default ({ value = '', className, style = {} }) => {
e.preventDefault() e.preventDefault()
let viewEl = document.getElementById(ancher.replace('#', '')) let viewEl = document.getElementById(ancher.replace('#', ''))
if (viewEl) { if (viewEl) {
viewEl.parentNode.scrollTop = viewEl.offsetTop viewEl.scrollIntoView(true)
} }
} }
} }
@ -61,6 +82,12 @@ export default ({ value = '', className, style = {} }) => {
} }
} }
}, [html, el.current, onAncherHandler]) }, [html, el.current, onAncherHandler])
return (
return (<div ref={el} style={style} className={`${className ? className : ''} markdown-body`} dangerouslySetInnerHTML={{ __html: html }}></div>) <div
ref={el}
style={style}
className={`${className ? className : ''} markdown-body`}
dangerouslySetInnerHTML={{ __html: html }}
></div>
)
} }

View File

@ -67,18 +67,17 @@ function Index(props){
} }
return( return(
<div className="aboutPanels"> <div className="aboutPanels">
<div className="aboutContent"> <div className="aboutContent">
<AlignCenterBetween style={{padding:"14px 0px"}}> <AlignCenterBetween style={{padding:"14px 20px"}}>
<span className="font-16"><i className="iconfont icon-xiangmujianjie mr5 font-16 color-blue"></i>项目简介</span> <span className="font-16"><i className="iconfont icon-xiangmujianjie mr5 font-16 color-blue"></i>项目概览</span>
{ editOpration && <a onClick={editContent} className="color-blue">编辑</a> } { editOpration && !edit && <a onClick={editContent} className="color-blue">编辑</a> }
</AlignCenterBetween> </AlignCenterBetween>
{ {
edit ? edit ?
<div> <div className="padding20">
<MDEditor <MDEditor
placeholder={"请输入描述信息"} placeholder={"请输入描述信息"}
height={200} height={500}
mdID={"order-new-description"} mdID={"order-new-description"}
initValue={content} initValue={content}
onChange={onContentChange} onChange={onContentChange}
@ -114,11 +113,11 @@ function Index(props){
</div> </div>
</div> </div>
: :
<div style={{padding:"20px 0px"}}> <div className="padding20">
{content ? {content ?
<RenderHtml className="break_word_comments imageLayerParent" value={content} /> <RenderHtml className="break_word_comments imageLayerParent" value={content} url={props.history.location}/>
: :
<div>暂无简介~</div> <div>暂无概览~</div>
} }
{attachments && attachments.length > 0 && {attachments && attachments.length > 0 &&
<Attachments <Attachments

View File

@ -4,7 +4,6 @@
.aboutContent{ .aboutContent{
border-radius: 2px; border-radius: 2px;
border: 1px solid #EEEEEE; border: 1px solid #EEEEEE;
padding:0px 30px;
width:100%; width:100%;
background-color: #fff; background-color: #fff;
margin-top:20px; margin-top:20px;

View File

@ -177,7 +177,7 @@ class Activity extends Component{
} }
</div> </div>
: :
<NoneData _html="暂时还没有相关数据!" /> <NoneData _html="暂时还没有相关数据!" />
} }
</Spin> </Spin>
{ {

View File

@ -32,8 +32,8 @@ class ActivityItem extends Component {
</p > </p >
} }
<p className="itemLine mt10"> <p className="itemLine mt10">
<Link to={`/users/${item && item.login}`} className="show-user-link"> <Link to={`/users/${item && item.user_login}`} className="show-user-link">
<img alt="" src={getImageUrl(`images/${item.user_avatar}`)} className="createImage" /> <img alt="" src={getImageUrl(`/${item.user_avatar}`)} className="createImage" />
<span className="mr20">{item.user_name}</span> <span className="mr20">{item.user_name}</span>
</Link> </Link>
{item.created_at && <span className="color-grey-9">创建于<span className="ml2 color-grey-6">{item.created_at}</span></span>} {item.created_at && <span className="color-grey-9">创建于<span className="ml2 color-grey-6">{item.created_at}</span></span>}

View File

@ -4,7 +4,7 @@ import './branch.css';
import { getBranch , getTag } from '../GetData/getData'; import { getBranch , getTag } from '../GetData/getData';
export default (({ projectsId , repo_id , changeBranch , branch , owner })=>{ export default (({ projectsId , branch , owner , changeBranch , branchList , tagflag = true })=>{
const [ showValue , setShowValue ] = useState(branch); const [ showValue , setShowValue ] = useState(branch);
const [ inputValue , setInputValue] = useState(undefined); const [ inputValue , setInputValue] = useState(undefined);
const [ nav , setNav ] = useState(0); const [ nav , setNav ] = useState(0);
@ -17,10 +17,11 @@ export default (({ projectsId , repo_id , changeBranch , branch , owner })=>{
useEffect(()=>{ useEffect(()=>{
setShowValue(branch); setShowValue(branch);
},[branch]) },[branch])
useEffect(()=>{ useEffect(()=>{
document.body.addEventListener('click', e => { document.body.addEventListener('click', e => {
let name = e.target.className; let name = e.target.className;
let turn = name == "ant-input OptionsInput" || name == "navli active"|| name == "navli" || name == "padding10 bor-bottom-greyE"; let turn = name === "ant-input OptionsInput" || name === "navli active"|| name === "navli" || name === "padding10 bor-bottom-greyE";
if(turn){ if(turn){
return; return;
}else{ }else{
@ -30,8 +31,12 @@ export default (({ projectsId , repo_id , changeBranch , branch , owner })=>{
}) })
useEffect(()=>{ useEffect(()=>{
getBranchs(projectsId,owner); if(branchList){
},[projectsId]) setData(branchList);
setDatas(branchList);
setIsSpin(false);
}
},[branchList])
async function getBranchs(id,owner){ async function getBranchs(id,owner){
@ -63,7 +68,7 @@ export default (({ projectsId , repo_id , changeBranch , branch , owner })=>{
} }
} }
function chooseitem(value){ function chooseitem(value){
setShowValue(value); // setShowValue(value);
changeBranch(value); changeBranch(value);
} }
@ -77,8 +82,8 @@ export default (({ projectsId , repo_id , changeBranch , branch , owner })=>{
onChange={changeInputValue} style={{width:"220px"}} onChange={changeInputValue} style={{width:"220px"}}
/> />
<ul className="navUl"> <ul className="navUl">
<li className={nav==0?"navli active":"navli"} onClick={()=>changeNav(0)}><i className="iconfont icon-fenzhi1 font-14 mr3"></i>分支列表</li> <li className={nav === 0?"navli active":"navli"} onClick={()=>changeNav(0)}><i className="iconfont icon-fenzhi1 font-14 mr3"></i>分支列表</li>
<li className={nav==1?"navli active":"navli"} onClick={()=>changeNav(1)}><i className="iconfont icon-biaoqian3 font-14 mr3"></i>标签列表</li> { tagflag && <li className={nav === 1?"navli active":"navli"} onClick={()=>changeNav(1)}><i className="iconfont icon-biaoqian3 font-14 mr3"></i>标签列表</li> }
</ul> </ul>
</div> </div>
<Spin spinning={isSpin}> <Spin spinning={isSpin}>
@ -97,9 +102,10 @@ export default (({ projectsId , repo_id , changeBranch , branch , owner })=>{
</div> </div>
); );
return( return(
<Popover placement="bottom" visible={flag} content={menu} onClick={()=>setFlag(!flag)} overlayClassName="branch-tagBox-list"> <Popover placement='bottomLeft' visible={flag} content={menu} onClick={()=>setFlag(!flag)} overlayClassName="branch-tagBox-list">
<div className="branch-tagBox"> <div className="branch-tagBox">
<span className="color-grey-9 mr3 ml8">{nav === 0 ?"分支":"标签"}:</span> {/* {nav === 0 ?"分支":"标签"} */}
<span className="color-grey-9 mr3 ml8"><i className="iconfont icon-fenzhi2 font-18"></i></span>
<a className="ant-dropdown-link"> <a className="ant-dropdown-link">
{showValue} {showValue}
</a> </a>

View File

@ -51,7 +51,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
cursor: pointer; cursor: pointer;
width: 240px; min-width: 140px;
} }
.branch-tagBox-list .ant-popover-arrow{ .branch-tagBox-list .ant-popover-arrow{
display: none; display: none;

View File

@ -0,0 +1,83 @@
import React, { useEffect, useState } from 'react';
import { AutoComplete , Button , Icon } from 'antd';
import axios from 'axios';
const { Option } = AutoComplete;
function AddGroup({organizeId,getGroupID}){
const [ id , setID ] = useState(undefined);
const [ source , setSource ] = useState(undefined);
const [ searchKey , setSearchKey ] = useState("");
useEffect(()=>{
getUserList();
},[searchKey])
function getUserList(e){
const url = `/organizations/${organizeId}/teams/search.json`;
axios.get(url, {
params: {
search: searchKey,
},
}).then((result) => {
if (result) {
sourceOptions(result.data.teams);
}
})
.catch((error) => {
console.log(error);
});
};
function sourceOptions(userDataSource){
const s = userDataSource && userDataSource.map((item, key) => {
return (
<Option
key={key}
value={`${item.id}`}
name={item.name}
>
{item.name}
</Option>
);
});
setSource(s);
}
function changeInputUser(e){
setSearchKey(e || "");
};
//
function selectInputUser(e, option){
setID(e);
setSearchKey(option.props.name);
};
function addCollaborator(){
getGroupID && getGroupID(id);
}
return(
<div className="addPanel">
<AutoComplete
dataSource={source}
value={searchKey}
style={{ width: 300 }}
onChange={changeInputUser}
onSelect={selectInputUser}
placeholder="搜索需要添加的团队..."
allowClear
/>
<Button
type="primary"
ghost
onClick={addCollaborator}
className="ml15"
>
<Icon type="plus" size="16"></Icon>
添加团队
</Button>
</div>
)
}
export default AddGroup;

View File

@ -0,0 +1,95 @@
import React, { useEffect, useState } from 'react';
import { AutoComplete , Button , Icon } from 'antd';
import axios from 'axios';
import { getImageUrl } from 'educoder';
const { Option } = AutoComplete;
function AddMember({getID,login}){
const [ id , setID ] = useState(undefined);
const [ source , setSource ] = useState(undefined);
const [ searchKey , setSearchKey ] = useState(undefined);
useEffect(()=>{
getUserList();
},[searchKey])
function getUserList(e){
const url = `/users/list.json`;
axios.get(url, {
params: {
search: searchKey,
},
}).then((result) => {
if (result) {
sourceOptions(result.data.users);
}
})
.catch((error) => {
console.log(error);
});
};
function sourceOptions(userDataSource){
const s = userDataSource && userDataSource.map((item, key) => {
return (
<Option
key={key}
value={`${item.user_id}`}
login={`${item.login}`}
name={item.username}
>
<img
className="user_img radius"
width="28"
height="28"
src={getImageUrl(`/${item && item.image_url}`)}
alt=""
/>
<span className="ml10" style={{ "vertical-align": "middle" }}>
{item.username}
<span className="color-grey ml10">({item.login})</span>
</span>
</Option>
);
});
setSource(s);
}
function changeInputUser(e){
setSearchKey(e);
};
//
function selectInputUser(e, option){
setID(login ? e : option.props.login);
setSearchKey(option.props.name);
};
function addCollaborator(){
getID && getID(id);
}
return(
<div className="addPanel">
<AutoComplete
dataSource={source}
value={searchKey}
style={{ width: 300 }}
onChange={changeInputUser}
onSelect={selectInputUser}
placeholder="搜索需要添加的用户..."
allowClear
/>
<Button
type="primary"
ghost
onClick={addCollaborator}
className="ml15"
>
<Icon type="plus" size="16"></Icon>
添加成员
</Button>
</div>
)
}
export default AddMember;

View File

@ -1,19 +1,23 @@
import React from 'react'; import React from 'react';
import { getImageUrl } from 'educoder';
import { Link } from 'react-router-dom';
import './Component.scss'; import './Component.scss';
export default (({img , title, desc , rightBtn})=>{ function Cards({img , title, desc , rightBtn , src , bottomInfos}){
return( return(
<div className="cards"> <div className="cards">
<div className="img"><img src={img} alt=""/></div> {img &&<div className="img"><img src={getImageUrl(`/${img}`)} alt=""/></div>}
<div className="content"> <div className="content">
<p className="titles"> <p className="titles">
<span>{title}</span> <Link to={src}>{title}</Link>
{rightBtn} {rightBtn}
</p> </p>
<div className="desc"> <div className="desc">
{desc} {desc}
</div> </div>
{bottomInfos}
</div> </div>
</div> </div>
) )
}) }
export default Cards;

View File

@ -8,6 +8,10 @@ li.ant-menu-item{
margin:0px!important; margin:0px!important;
border-bottom: 1px solid #eee; border-bottom: 1px solid #eee;
} }
.flags{
border: 1px solid red;
border-radius: 5px;
}
// Cards // Cards
.cards{ .cards{
display: flex; display: flex;
@ -15,6 +19,8 @@ li.ant-menu-item{
padding:20px 34px; padding:20px 34px;
background-color: #fff; background-color: #fff;
margin-bottom:18px; margin-bottom:18px;
min-height: 130px;
border:1px solid #eee;
.img{ .img{
margin-right: 20px; margin-right: 20px;
width: 190px; width: 190px;
@ -23,8 +29,10 @@ li.ant-menu-item{
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
overflow: hidden;
img{ img{
max-width: 100%; max-width: 100%;
max-height: 100%;
} }
} }
.content{ .content{
@ -35,7 +43,9 @@ li.ant-menu-item{
justify-content: space-between; justify-content: space-between;
margin-bottom: 10px!important; margin-bottom: 10px!important;
align-items: center; align-items: center;
&>span{ height: 22px;
line-height: 22px;;
&>a{
font-size:18px ; font-size:18px ;
color: #333; color: #333;
} }
@ -46,11 +56,13 @@ li.ant-menu-item{
display: -webkit-box; display: -webkit-box;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
-webkit-line-clamp: 2; -webkit-line-clamp: 2;
line-height: 20px;
} }
} }
} }
// Tabs // Tabs
.tabsStyle{ .tabsStyle{
border:1px solid #eee;
.ant-tabs-bar.ant-tabs-top-bar{ .ant-tabs-bar.ant-tabs-top-bar{
padding-left: 35px; padding-left: 35px;
margin-bottom: 0px; margin-bottom: 0px;
@ -72,6 +84,7 @@ li.ant-menu-item{
border-radius:11px; border-radius:11px;
color: #fff; color: #fff;
margin-left: 5px; margin-left: 5px;
font-size: 12px;
&.running{ &.running{
background:#5091FF; background:#5091FF;
color: #F1F8FF; color: #F1F8FF;
@ -88,6 +101,10 @@ li.ant-menu-item{
background:#F73030; background:#F73030;
color:#FCEEEE ; color:#FCEEEE ;
} }
&.killed{
background:#eee;
color:#999 ;
}
} }
.handleBox{ .handleBox{
position: fixed; position: fixed;
@ -95,6 +112,10 @@ li.ant-menu-item{
right:240px; right:240px;
z-index: 10000; z-index: 10000;
} }
.laterest{
color: #05690d;
}
@media screen and (max-width: 1800px){ @media screen and (max-width: 1800px){
.handleBox{ .handleBox{
right:190px; right:190px;
@ -119,4 +140,56 @@ li.ant-menu-item{
.handleBox{ .handleBox{
right:0px; right:0px;
} }
}
.ant-drawer{
z-index: 10000!important;
}
.ant-drawer-body{
padding:0px!important;
.drawerHead{
background-color: #333;
color: #fff;
padding:15px 20px;
}
.ant-tree{
margin:0px 20px!important;
}
}
.menuPanels{
width: 240px;
height: 180px;
.ant-popover-content,.ant-popover-inner{
height: 100%;
width: 100%;
}
}
.halfs{
margin-top: 24px;
padding:24px 0px 0px 0px;
border-top: 1px solid #e8e8e8;
.attrPerson{
padding-bottom: 24px;
}
}
.menuinfos{
padding:15px 0px;
&>a{
display: flex;
flex-direction: column;
align-items: center;
border-right: 1px solid #eee;
flex: 1;
& >span:first-child{
font-size: 18px;
font-weight: 400;
color: #333;
}
& >span:last-child{
color: #666;
}
&:last-child{
border-right: none;
}
}
} }

View File

@ -0,0 +1,160 @@
import React, { useEffect, useState } from 'react';
import { AlignCenter , FlexAJ } from '../Component/layout';
import { Link } from 'react-router-dom';
import { Popover , Spin } from 'antd';
import { getImageUrl } from 'educoder';
import './Component.scss';
import { getUser } from '../GetData/getData';
import axios from 'axios';
function Contributors({contributors,owner,projectsId}){
const [ menuList ,setMenuList ]= useState([]);
const [ list , setList ]= useState(undefined);
const [ total , setTotal ]= useState(0);
const [ menu , setMenu ] = useState("");
const [ login , setLogin ] = useState(undefined);
const [ isSpin , setIsSpin ] = useState(false);
useEffect(()=>{
if(contributors && contributors.total_count>0){
setTotal(contributors.total_count);
setList(contributors.list);
}
},[contributors])
useEffect(()=>{
if(login){
getUsers(login);
}else{
setMenu(undefined);
}
},[login])
async function getUsers(login){
setIsSpin(true);
let a = menuList && menuList.filter(i=>i.login === login);
if(a.length === 0){
let result = await getUser(login);
let arr = menuList;
arr.push({...result});
setMenuList(arr);
setMenusFunc(result);
setIsSpin(false);
}else{
setMenusFunc(a[0]);
setIsSpin(false);
}
}
function setMenusFunc(data){
if(data){
let ele = (
<Spin spinning={isSpin}>
<FlexAJ>
<AlignCenter>
<Link to={`/users/${data.login}`}><img src={getImageUrl(`/${data.image_url}`)} alt="" className="radius" width="38px" height="38px"/></Link>
<Link to={`/users/${data.login}`} className="ml10">{data.name}</Link>
</AlignCenter>
{
data.is_watch ? <a className="color-grey-9" onClick={()=>FocusFunc(false,data.login)}>取消关注</a>:<a className="color-blue" onClick={()=>FocusFunc(true,data.login)}>关注</a>
}
</FlexAJ>
<AlignCenter className="menuinfos">
<a href={data.projects_url}>
<span>{data.projects_count}</span>
<span>项目数</span>
</a>
<a href={data.followers_url}>
<span>{data.followers_count}</span>
<span>粉丝数</span>
</a>
<a href={data.following_url}>
<span>{data.following_count}</span>
<span>关注数</span>
</a>
</AlignCenter>
{
data.organizations && data.organizations.length > 0 ?
<AlignCenter className="font-12 pt4 pb4">
<span>所属组织</span>
<div className="task-hide flex1">
{renderArray(data.organizations)}
</div>
</AlignCenter>
:""
}
{
data.location && <AlignCenter className="font-12 pt4 pb4"><span>所在地址:</span><span className="ml5">{data.location}</span></AlignCenter>
}
</Spin>
)
setMenu(ele);
}
}
function FocusFunc(flag,login){
axios({
method: flag ? 'post' : 'delete',
url: `/watchers/${flag ? 'follow' : 'unfollow'}.json`,
params: {target_type: "user",id:login}
}).then(result => {
if (result && (result.data.status === 0 || result.data.status === 2)) {
let a = menuList && menuList.filter(i=>i.login === login);
if(a){
a[0].is_watch = flag;
}
setMenusFunc(a[0]);
}
})
.catch(error => {
console.log(error);
});
}
function renderArray(array){
let str = "";
for(var i = 0;i<array.length;i++){
str += array[i].name +"、";
}
let substr = str.substr(0,str.length-1);
return (<span title={substr}>{substr}</span>)
}
function setVisibleFunc(flag,l,index){
if(l !== login){
setLogin(l);
}
var lx = list.concat();
lx.map(i=>i.visible =false);
if(flag){
lx[index].visible = flag;
}
lx.splice();
setList(lx);
}
return(
<div className="halfs">
<FlexAJ>
<AlignCenter><span className="font-16 color-grey-6">贡献者</span>{ contributors && contributors.total_count > 0 && <span className="infoCount">{contributors.total_count}</span>}</AlignCenter>
<Link className="font-12 color-grey-9" to={`/projects/${owner}/${projectsId}/contribute`}>全部</Link>
</FlexAJ>
<div className="attrPerson" onMouseLeave={()=>setVisibleFunc(false)}>
{
total > 0 ?
list.map((item,key)=>{
return(
<Popover content={menu} visible={item.visible} overlayClassName="menuPanels" placement="top">
<Link key={key} to={`/users/${item.login}`}>
<img src={getImageUrl(`/${item.image_url}`)} alt="" onMouseOver={()=>setVisibleFunc(true,item.login,key)}/>
</Link>
</Popover>
)
})
:""
}
</div>
</div>
)
}
export default Contributors;

View File

@ -0,0 +1,99 @@
import React, { useEffect, useState } from 'react';
import { Drawer , Tree , Spin } from 'antd';
import './Component.scss';
import axios from 'axios';
const { TreeNode , DirectoryTree } = Tree;
function DrawerPanel({visible,onClose,branch,owner,projectsId,history, name , list}){
const [ treeData , setTreeData ] = useState(undefined);
const [ isSpin , setIsSpin ] = useState(true);
const [first , setFirst ] = useState(true);
useEffect(()=>{
if(visible && first){
if(list){
setTreeData(list);
setIsSpin(false);
}else{
getMenulist();
}
setFirst(false);
}
},[visible])
function getMenulist(){
const url = `/${owner}/${projectsId}/entries.json`;
axios.get(url,{ params: { ref: branch } }).then(result=>{
if(result){
setTreeData(result.data.entries);
}
setIsSpin(false);
}).catch(error=>{})
}
function renderTreeNodes(data) {
return data && data.length > 0 && data.map((item) => {
return (
<TreeNode title={item.name} key={item.key} dataRef={item} isLeaf={item.type === "file"}>
{renderTreeNodes(item.children)}
</TreeNode>
);
});
}
function onLoadData(tr){
return new Promise((resolve) => {
if (tr.props.children) {
resolve();
return;
}
let en = [];
const url = `/${owner}/${projectsId}/sub_entries.json`;
axios.get(url, {
params:{
filepath:tr.props.dataRef.path,
ref:branch,
type:"dir"
}
}).then((result) => {
if(result){
en = result.data.entries;
}
}).catch(error=>{})
setTimeout(() => {
tr.props.dataRef.children = en;
setTreeData([...treeData]);
resolve();
}, 2000);
});
}
function selectTree(keys,event){
let dataref = event.node.props.dataRef;
if(dataref.type==="file"){
onClose();
history.push(`/projects/${owner}/${projectsId}/tree/${branch}/${dataref.path}`);
}
}
return(
<Drawer
placement="left"
visible={visible}
closable={false}
onClose={onClose}
width={"320px"}
maskStyle={{backgroundColor:'rgba(0,0,0,0.09)'}}
>
<Spin spinning={isSpin}>
<div className="drawerHead">
<p className="font-20">{name}</p>
<p><i class="iconfont icon-fenzhi2 font-18 color-grey-9 mr3"></i>{branch}</p>
</div>
<DirectoryTree loadData={onLoadData} onSelect={selectTree}>
{treeData && renderTreeNodes(treeData)}
</DirectoryTree>
</Spin>
</Drawer>
)
}
export default DrawerPanel;

View File

@ -0,0 +1,9 @@
.ant-modal-mask{
z-index: 1001;
}
.ant-modal-wrap{
z-index: 1002;
.ant-form-explain{
position: absolute;
}
}

View File

@ -0,0 +1,60 @@
import React , {forwardRef, useEffect} from 'react';
import { Modal , Form , Input , Button } from 'antd';
import './EAccount.scss';
function EducoderAccount({form , visible , onOk , email}){
const { getFieldDecorator, validateFields , setFieldsValue } = form;
useEffect(()=>{
if(email){
setFieldsValue({email})
}
},[email])
function onSure(){
validateFields((error,values)=>{
if(!error){
onOk(values);
}
})
}
const layout = {
labelCol: { span: 5 },
wrapperCol: { span: 18 },
};
return(
<Modal
visible={visible}
title="提示"
width="500px"
closable={false}
footer={
<Button type="primary" onClick={onSure}>确定</Button>
}
centered
>
<div>
<p className="mb15 edu-txt-center" style={{maxWidth:"350px",margin:"0px auto"}}>
为确保您能正常使用平台功能请确认以下信息:
</p>
<Form {...layout}>
<Form.Item label="邮箱">
{getFieldDecorator("email",{
rules:[{required:true,message:"请输入邮箱账号"}]
})(
<Input placeholder="请输入您的邮箱账号" width="220px"/>
)}
</Form.Item>
<Form.Item label="密码">
{getFieldDecorator("password",{
rules:[{required:true,message:"请输入邮箱密码"}]
})(
<Input.Password placeholder="请输入您的邮箱密码" width="220px"/>
)}
</Form.Item>
</Form>
</div>
</Modal>
)
}
export default Form.create()(forwardRef(EducoderAccount));

View File

@ -5,7 +5,7 @@ import './Component.scss';
export default (()=>{ export default (()=>{
return( return(
<div className="handleBox"> <div className="handleBox">
<a href="https://www.trustie.net/forums/82/memos/3075" target="_blank" > <a href="https://forum.trustie.net/forums/3075/detail" target="_blank" >
<img src={Handbook} alt=""/> <img src={Handbook} alt=""/>
</a> </a>
</div> </div>

View File

@ -1,12 +1,10 @@
import React from 'react'; import React from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
export default ({title , value , className})=>{ export default ({title , value , className})=>{
const Keys = styled.span` const Keys = styled.span`
display:flex; display:flex;
align-item:center; align-items:center;
& span{ & span{
display:block; display:block;
height:20px; height:20px;

View File

@ -0,0 +1,54 @@
import React, { useEffect, useState } from 'react';
import { FlexAJ } from '../Component/layout';
function LanguagePower({languages}){
const [ array , setArray ] = useState(undefined);
useEffect(()=>{
if(languages){
let arr = [];
Object.keys(languages).map((item,key)=>{
arr.push({name:item,percent:languages[item],color:getColor()});
})
setArray(arr);
}
},[languages])
 function getColor(){
let str = "#";
let arr = ["1","2","3","4","4","5","6","7","8","9","a","b","c","d","e","f"];
for(var i=0;i<6;i++){
let num = parseInt(Math.random() * 16);
str+=arr[num];
}
return str;
}
return(
<div>
<p className="font-16 color-grey-6">开发语言</p>
<div className="progress">
{
array && array.map((item,key)=>{
return(
<span style={{width:item.percent,backgroundColor:item.color}}></span>
)
})
}
</div>
{
array && array.length > 0 &&
<FlexAJ className="progresstip">
{
array.map((item,key)=>{
return(
<span><i className="zero" style={{backgroundColor:`${item.color}`}}></i><span>{item.name}</span><span>{item.percent}</span></span>
)
})
}
</FlexAJ>
}
</div>
)
}
export default LanguagePower;

View File

@ -19,7 +19,7 @@ export default (({fork,parise})=>{
}`; }`;
const SpanStyleparise = styled.span`{ const SpanStyleparise = styled.span`{
display:flex; display:flex;
align-item:center; align-items:center;
margin-left:30px; margin-left:30px;
padding:0px 12px; padding:0px 12px;
border-radius:13px; border-radius:13px;

View File

@ -1,6 +1,10 @@
import React from 'react'; import React from 'react';
import './Component.scss'; import './Component.scss';
import { Button } from 'antd';
import styled from 'styled-components'; import styled from 'styled-components';
import FocusButton from "../UsersList/focus_button";
import { getImageUrl } from 'educoder';
import { Link } from 'react-router-dom';
const Img = styled.img`{ const Img = styled.img`{
border-radius:50%; border-radius:50%;
@ -28,26 +32,8 @@ const I = styled.i`{
font-size:13px!important; font-size:13px!important;
color:#60B25E; color:#60B25E;
margin-right:2px; margin-right:2px;
}` height:17px;
const FocusBtn = styled.a`{ line-height:17px;
display:inline-block;
height:30px;
line-height:26px;
padding:0px 12px;
background-color:#fafafa;
border:1px solid #eee;
border-radius:2px;
color:#888!important;
}`
const Ifocused = styled.i`{
font-size:16px!important;
color:#FFA802;
margin-right:4px;
}`
const Ifocus = styled.i`{
font-size:16px!important;
color:#BBBBBB;
margin-right:4px;
}` }`
const Div = styled.div`{ const Div = styled.div`{
margin-bottom: 18px; margin-bottom: 18px;
@ -56,17 +42,18 @@ const Div = styled.div`{
align-items: center; align-items: center;
border:1px solid #eee; border:1px solid #eee;
}` }`
export default (({img,name,time, focusStatus})=>{ export default (({ user , img, name, time, focusStatus, is_current_user, login , successFunc }) => {
return( return (
<Div> <Div>
<Img src={img}/> <Link to={`/users/${user && user.login}`}><Img src={getImageUrl(`/${img}`)} /></Link>
<div className="m-infos"> <div className="m-infos">
<Name>{name}</Name> <Link to={`/users/${user && user.login}`}><Name>{name}</Name></Link>
<Time><I className="iconfont icon-shijian"></I>加入时间:{time}</Time> <Time><I className="iconfont icon-shijian"></I>加入时间:{time}</Time>
{ {
focusStatus ? is_current_user ?
<FocusBtn><Ifocused className="iconfont icon-shixing"></Ifocused>已关注</FocusBtn> : <Button type="default">当前用户</Button>
<FocusBtn><Ifocus className="iconfont icon-kongxing"></Ifocus>关注</FocusBtn> :
<FocusButton is_watch={focusStatus} id={login} successFunc={successFunc}/>
} }
</div> </div>
</Div> </Div>

View File

@ -0,0 +1,24 @@
import React from 'react';
import { Modal , Button } from 'antd';
import './Component.scss';
function Modals({visible,title,content,onOk,onCancel}){
return(
<Modal
className="modalsStyle"
visible={visible}
title={title}
onCancel={onCancel}
closable={true}
footer={
<div>
<Button onClick={onCancel}>取消</Button>
<Button type={"primary"} style={{marginLeft:"20px"}} onClick={onOk}>确定</Button>
</div>
}
>
<div style={{fontSize:"16px"}}>{content}</div>
</Modal>
)
}
export default Modals;

View File

@ -0,0 +1,61 @@
import React , { useState , useEffect } from 'react';
import { Select } from 'antd';
import { getUrl } from 'educoder';
import axios from 'axios';
const Option = Select.Option;
export default (({ language , select_language })=>{
const [ six , setSix ] = useState(undefined);
const [ languages , setLanguage ] = useState(undefined);
useEffect(()=>{
const url = '/ci/languages.json';
axios.get(url).then(result=>{
if(result){
setLanguage(result.data);
}
}).catch(error=>{
console.log(error);
})
},[])
function changelanguage(value){
let array = value ? languages.filter(item=>item.name === value) :undefined;
select_language(value,array && array[0]);
}
useEffect(()=>{
const url = '/ci/languages/common.json';
axios.get(url).then(result=>{
if(result){
setSix(result.data);
}
}).catch(error=>{
console.log(error);
})
},[])
return(
<React.Fragment>
{
six &&
<ul className="language">
{
six.map((item,key)=>{
return(
key < 6 ? <li className={language ===item.name ? "active":""} onClick={()=>changelanguage(item.name)}><img alt="" src={item.cover_url && getUrl(item.cover_url)} /></li> : ""
)
})
}
</ul>
}
<Select showSearch={true} placeholder={"请选择文本语言"} style={{ width: 200 }} value={language} onChange={changelanguage}>
<Option value={undefined}>请选择文本语言</Option>
{languages && languages.map((item, key) => {
return <Option value={item.name}>{item.name}</Option>;
})}
</Select>
</React.Fragment>
)
})

View File

@ -3,42 +3,54 @@ import './Component.scss';
export const Tags = (status)=>{ export const Tags = (status)=>{
switch(status){ switch(status){
case 1: case "running":
return( return(
<span className="statusColor running">运行中</span> <span className="statusColor running">运行中</span>
); );
case 2: case "failure":case"error":
return ( return (
<span className="statusColor failed">未通过</span> <span className="statusColor failed">未通过</span>
); );
case 3: case "success":
return ( return (
<span className="statusColor pass">已通过</span> <span className="statusColor pass">已通过</span>
); );
default: case "pending":
return ( return (
<span className="statusColor Preparing">准备中</span> <span className="statusColor Preparing">准备中</span>
); );
case 'killed':
return (
<span className="statusColor killed">已撤销</span>
);
} }
} }
export const TagsLine = (status)=>{ export const TagsLine = (status)=>{
switch(status){ switch(status){
case 1: case "running":
return( return(
<span className="statuslineColor running">运行中</span> <span className="statuslineColor running">运行中</span>
); );
case 2: case "failure":case "error":
return ( return (
<span className="statuslineColor failed">未通过</span> <span className="statuslineColor failed">未通过</span>
); );
case 3: case "success":
return ( return (
<span className="statuslineColor pass">已通过</span> <span className="statuslineColor pass">已通过</span>
); );
default: case "pending":
return ( return (
<span className="statuslineColor Preparing">准备中</span> <span className="statuslineColor Preparing">准备中</span>
); );
case 'killed':
return (
<span className="statuslineColor killed">已撤销</span>
);
case 'skipped':
return (
<span className="statuslineColor skipped">已跳过</span>
);
} }
} }

View File

@ -0,0 +1,46 @@
import React ,{ useState } from 'react';
import { Modal , Input , Spin } from 'antd';
import { AlignCenter } from "./layout";
import axios from 'axios';
import './Component.scss';
function PasswordAuthority({ authorityValBox , successFunc , cancelFunc }){
const [ authorityVal , setAuthorityVal ] = useState(undefined);
const [ authorityValFlag , setAuthorityValFlag ] = useState(false);
const [ isSpin , setIsSpin ] = useState(false);
// -
function cancelAuthority(){
setAuthorityVal(undefined);
cancelFunc();
}
//
function okAuthority(){
if(!authorityVal){
setAuthorityValFlag(true);
return;
}
setIsSpin(true);
const url = `/users/ci/oauth_grant.json`;
axios.get(url,{
params:{password:authorityVal}
}).then(result=>{
setIsSpin(false);
if(result){
successFunc(result.data.step);
}
}).catch(error=>{setIsSpin(false);});
}
return(
<Modal visible={authorityValBox} centered={true} title="授权" onCancel={cancelAuthority} onOk={okAuthority}>
<Spin spinning={isSpin}>
<p style={{textAlign:"center"}}>请输入您的登录密码确认授权DevOps应用</p>
<AlignCenter style={{justifyContent:"center",marginTop:"20px"}}>
<span>密码</span>
<Input.Password value={authorityVal} className={authorityValFlag===true && "flags"} onChange={(e)=>setAuthorityVal(e.target.value)} style={{width:"220px"}}></Input.Password>
</AlignCenter>
</Spin>
</Modal>
)
}
export default PasswordAuthority;

View File

@ -0,0 +1,41 @@
import React from 'react';
import { AlignCenter , AlignTop , FlexAJ } from '../Component/layout';
import { Link } from 'react-router-dom';
function Releases({owner,projectsId,releaseVersions}){
return(
<div>
<FlexAJ>
<AlignCenter><span className="font-16 color-grey-6">发行版</span>
{ releaseVersions && releaseVersions.total_count > 0 && <span className="infoCount">{releaseVersions.total_count}</span>}
</AlignCenter>
{ releaseVersions && releaseVersions.total_count > 0 ?
<Link className="font-12 color-grey-9" to={`/projects/${owner}/${projectsId}/releases`}>全部</Link>
:
<Link className="font-12 color-blue" to={`/projects/${owner}/${projectsId}/releases/new`}>新建</Link>
}
</FlexAJ>
{
releaseVersions && releaseVersions.total_count>0 ?
releaseVersions.list.map((item,key)=>{
return(
key === 0 &&<AlignTop className="mt10">
<i className="iconfont icon-biaoqian3 color-grey-6 font-18 mr10"></i>
<div>
<p className="font-16 color-grey-6">
<Link to={`/projects/${owner}/${projectsId}/releases`}>{item.name}</Link>
<span className="font-12 laterest ml5">最新</span>
</p>
<p className="color-grey-9 font-13">{item.created_at}</p>
</div>
</AlignTop>
)
})
:""
}
</div>
)
}
export default Releases;

View File

@ -2,13 +2,15 @@ import React from "react";
import { Input } from "antd"; import { Input } from "antd";
const { Search } = Input; const { Search } = Input;
export default ({ placeholder , onSearch }) => { export default ({ placeholder , onSearch , onChange }) => {
return ( return (
<Search <Search
allowClear
placeholder={placeholder} placeholder={placeholder}
enterButton={'搜索'} enterButton={'搜索'}
onSearch={onSearch} onSearch={onSearch}
width="300px" width="300px"
onChange={onChange}
></Search> ></Search>
) )
}; };

View File

@ -2,52 +2,53 @@ import React , { useState , useEffect } from 'react';
import { AutoComplete } from 'antd'; import { AutoComplete } from 'antd';
import { getImageUrl } from "educoder"; import { getImageUrl } from "educoder";
import axios from 'axios'; import axios from 'axios';
const Option = AutoComplete.Option; const Option = AutoComplete.Option;
export default ({ getUser })=>{ export default ({ getUser , placeholder, width ,value })=>{
const [ source , setSource ] = useState(undefined);
const [ searchKey , setSearchKey ] = useState(undefined); const [ searchKey , setSearchKey ] = useState(undefined);
const [ userDataSource , setUserDataSource ] = useState(undefined);
useEffect(()=>{
if(!value){
setSearchKey(undefined);
}
},[value])
useEffect(()=>{
getUserList();
},[searchKey])
function getUserList(e){ function getUserList(e){
const url = `/users/list.json`; const url = `/users/list.json`;
axios.get(url, { axios.get(url, {
params: { params: {
search: e, search: searchKey,
}, },
}) }).then((result) => {
.then((result) => {
if (result) { if (result) {
setUserDataSource(result.data.users); sourceOptions(result.data.users);
} }
}) })
.catch((error) => { .catch((error) => {
console.log(error); console.log(error);
}); });
}; };
function changeInputUser(value){
setSearchKey(value);
getUserList(value);
}
function selectInputUser(id, option){ function sourceOptions(userDataSource){
setSearchKey(option.props.searchValue); const s = userDataSource && userDataSource.map((item, key) => {
getUserList(option.props.searchValue);
getUser && getUser(id);
}
const source =
userDataSource && userDataSource.map((item, key) => {
return ( return (
<Option <Option
key={key} key={key}
value={`${item.user_id}`} value={`${item.user_id}`}
searchValue={`${item.username}`} login={`${item.login}`}
name={item.username}
> >
<img <img
className="user_img radius" className="user_img radius"
width="28" width="28"
height="28" height="28"
src={getImageUrl(`images/${item && item.image_url}`)} src={getImageUrl(`/${item && item.image_url}`)}
alt="" alt=""
/> />
<span className="ml10" style={{ "vertical-align": "middle" }}> <span className="ml10" style={{ "vertical-align": "middle" }}>
@ -57,14 +58,31 @@ export default ({ getUser })=>{
</Option> </Option>
); );
}); });
setSource(s);
}
function changeInputUser(e){
setSearchKey(e);
};
//
function selectInputUser(e, option){
setSearchKey(option.props.name);
getUser(option.props.login);
};
return( return(
<AutoComplete <div className="addPanel">
dataSource={source} <AutoComplete
value={searchKey} getPopupContainer={trigger => trigger.parentNode}
style={{ width: 300 }} dataSource={source}
onChange={changeInputUser} value={searchKey}
onSelect={selectInputUser} style={{ width: width || 300 }}
placeholder="搜索需要添加的用户..." onChange={changeInputUser}
/> onSelect={selectInputUser}
placeholder={placeholder || "搜索需要添加的用户..."}
allowClear
/>
</div>
) )
} }

View File

@ -1,8 +1,8 @@
import React from 'react'; import React from 'react';
import styled from 'styled-components'; import styled from 'styled-components';
import { Link } from 'react-router-dom';
export default ({ url , name , column , id , login })=>{
export default ({ url , name , column })=>{
const Img = styled.span` const Img = styled.span`
display:flex; display:flex;
${column && "flex-direction: column;text-align:center;"} ${column && "flex-direction: column;text-align:center;"}
@ -19,8 +19,16 @@ export default ({ url , name , column })=>{
} }
`; `;
return( return(
id?
<Link to={`/users/${login}`}>
<Img>
{ url && <img src={url} alt=""/> }
<span>{name}</span>
</Img>
</Link>
:
<Img> <Img>
<img src={url} alt=""/> { url && <img src={url} alt=""/> }
<span>{name}</span> <span>{name}</span>
</Img> </Img>
) )

View File

@ -24,18 +24,33 @@ export const AlignCenter = styled.div`{
display:flex; display:flex;
align-items: center; align-items: center;
}` }`
export const AlignTop = styled.div`{
display:flex;
align-items: flex-start;
}`
// //
export const Box = styled.div`{ export const Box = styled.div`{
display:flex; display:flex;
align-item:flex-start; align-items:flex-start;
}`
export const LongWidth = styled.div`{
flex:1;
width:0;
border-radius:5px;
margin-bottom:30px;
}` }`
export const Long = styled.div`{ export const Long = styled.div`{
width:72%; width:78%;
border-radius:5px;
margin-bottom:30px;
}`
export const ShortWidth = styled.div`{
width:300px;
border-radius:5px; border-radius:5px;
margin-bottom:30px; margin-bottom:30px;
}` }`
export const Short = styled.div`{ export const Short = styled.div`{
width:28%; flex:1;
border-radius:5px; border-radius:5px;
margin-bottom:30px; margin-bottom:30px;
}` }`
@ -61,22 +76,24 @@ export const Redline = styled.a`{
line-height:28px; line-height:28px;
border-radius:2px; border-radius:2px;
border:1px solid #F73030; border:1px solid #F73030;
color:#F73030; color:${props => (props.bold ? "#fff" : "#F73030")} !important;
padding:0px 12px; padding:0px 12px;
display:inline-block; display:inline-block;
min-width:80px; min-width:80px;
text-align:center; text-align:center;
background:${props => (props.bold ? "#F73030" : "#fff")};
}` }`
export const Greenline = styled.a`{ export const Greenline = styled.a`{
height:30px; height:30px;
line-height:28px; line-height:28px;
border-radius:2px; border-radius:2px;
border:1px solid #28BD6C; border:1px solid #28BD6C;
color:#28BD6C; color:${props => (props.bold ? "#fff" : "#28BD6C")} !important;
padding:0px 12px; padding:0px 12px;
display:inline-block; display:inline-block;
min-width:80px; min-width:80px;
text-align:center; text-align:center;
background:${props => (props.bold ? "#28BD6C" : "#fff")};
}` }`
export const Greenback = styled.a`{ export const Greenback = styled.a`{
height:30px; height:30px;
@ -94,7 +111,7 @@ export const Blueback = styled.a`{
line-height:30px; line-height:30px;
border-radius:2px; border-radius:2px;
background-color:rgba(80,145,255,1); background-color:rgba(80,145,255,1);
color:#fff; color:#fff!important;
padding:0px 12px; padding:0px 12px;
display:inline-block; display:inline-block;
min-width:80px; min-width:80px;
@ -154,3 +171,9 @@ export const Content = styled.div`{
background-color:#fff; background-color:#fff;
justify-content: center; justify-content: center;
}` }`
export const GroupProjectBackgroup = styled.div`{
background:#fafafa;
padding:20px 30px;
width:100%;
}`

View File

@ -1,27 +1,71 @@
import React , { forwardRef , useCallback } from 'react'; import React, { forwardRef, useCallback, useState , useEffect } from "react";
import activate from '../Images/activate.png'; import activate from "../Images/activate.png";
import { Blueback } from '../Component/layout'; import { AlignCenter, Blueback } from "../Component/layout";
import styled from 'styled-components'; import PasswordAuthority from "../Component/PasswordAuthority";
import { Link } from 'react-router-dom'; import styled from "styled-components";
import { Form , Input } from 'antd'; import { Form, Input , Spin , Button } from "antd";
import axios from 'axios'; import ServiceModal from './ServiceModal';
import axios from "axios";
const P = styled.p`{ const P = styled.p`
width:200px; {
line-height:30px; width: 230px;
font-size:16px; line-height: 30px;
color:#333; font-size: 16px;
text-align:center; color: #333;
margin-top:30px; text-align: center;
margin-bottom:30px!important; margin-top: 30px;
}`; margin-bottom: 30px !important;
function About( props , ref){ }
const { form: { getFieldDecorator , validateFields } } = props; `;
function About(props, ref) {
const { form: { getFieldDecorator, validateFields , setFieldsValue } } = props;
const [isSpining, setIsSpining] = useState(true);
//
const [ authorityVal , setAuthorityVal ] = useState(undefined);
const [ authorityValFlag , setAuthorityValFlag ] = useState(false);
//0: devops
//1:
const [step, setStep] = useState(0);
const owner = props.match.params.owner;
const { user } = props;
const projectsId = props.match.params.projectsId;
const [ disabled, setDisabled ] = useState(false);
const [ typeFlag, setTypeFlag] = useState(false);
const AuthorLogin = props.projectDetail && props.projectDetail.author && props.projectDetail.author.login;
const CurrentLogin = props.current_user && props.current_user.login;
useEffect(()=>{
if(CurrentLogin === AuthorLogin){
auth('get');
}else{
setIsSpining(false);
}
},[AuthorLogin,CurrentLogin])
function auth(type){
const url = `/${owner}/${projectsId}/ci_authorize.json`;
axios({
method:`${type}`,
url
}).then(result=>{
setIsSpining(false);
if(result && result.data ){
setStep(result.data.step);
}
}).catch(error=>{
setIsSpining(false);
console.log(error);
})
}
const helper = useCallback( const helper = useCallback(
(label, name, rules, widget, isRequired) => ( (label, name, rules, widget, isRequired) => (
<React.Fragment> <React.Fragment>
<span className={isRequired?"required":""}>{label}</span> <span className={isRequired ? "required" : ""}>{label}</span>
<Form.Item> <Form.Item>
{getFieldDecorator(name, { rules, validateFirst: true })(widget)} {getFieldDecorator(name, { rules, validateFirst: true })(widget)}
</Form.Item> </Form.Item>
@ -29,52 +73,181 @@ function About( props , ref){
), ),
[] []
); );
//
function startActive(){ function goStep() {
let projectsId = props.match.params.projectsId; validateFields((error, values) => {
validateFields((error,values)=>{ if (!error) {
if(!error){ if(disabled){
const url = `/dev_ops/cloud_accounts.json`; setStep(1);
axios.post(url,{ }else{
...values, setIsSpining(true);
project_id:projectsId const url = `/${owner}/${projectsId}/cloud_accounts.json`;
}).then(result=>{ axios.post(url, {...values,ip_num:values.ip}).then((result) => {
if(result && result.data.redirect_url){ setIsSpining(false);
window.location.href = result.data.redirect_url; if (result && result.data.redirect_url) {
} props.showNotification("服务器信息配置完成!");
}).catch(error=>{ setStep(1);
console.log(error); }
}) })
.catch((error) => {
console.log(error);
setIsSpining(false);
});
}
} }
});
}
// 12trustie
function sureModal(type){
if(type === 2){
setTypeFlag(false);
setIsSpining(true);
const url = `/users/ci/cloud_account/trustie_bind.json`;
axios.post(url,{
account:user && user.login
}).then(result=>{
setIsSpining(false);
if(result && result.data){
setStep(result.data.step);
}
}).catch(error=>{setIsSpining(false)})
}else{
setTypeFlag(true);
}
}
//
function goUpStep(step){
setTypeFlag(false);
setStep(step);
}
//
function authStep(){
if(!authorityVal){
setAuthorityValFlag(true);
return;
}
setAuthorityValFlag(false);
setIsSpining(true);
const url = `/users/ci/oauth_grant.json`;
axios.get(url,{
params:{password:authorityVal}
}).then(result=>{
setIsSpining(false);
if(result){
setStep(result.data.step);
}
}).catch(error=>{setIsSpining(false)});
}
//
function startActive(){
setIsSpining(true);
const url = `/${owner}/${projectsId}/activate.json`;
axios.post(url).then(result=>{
setIsSpining(false);
if(result && result.data.status === 0){
props.history.push(`/projects/${owner}/${projectsId}/devops/dispose`);
// open_devops
let { changeOpenDevops } = props;
changeOpenDevops && changeOpenDevops(true);
}
}).catch(error=>{
console.log(error);
setIsSpining(false);
}) })
} }
return(
<div className="activatePanel"> return (
<img src={activate} alt="" width="250px"/> <Spin spinning={isSpining}>
<P>定义DevOps工作流帮助您检测bug发布代码</P> {/* <PasswordAuthority authorityValBox={authorityValBox} successFunc={okAuthority} cancelFunc={cancelAuthority}></PasswordAuthority> */}
<Link to={""} style={{color:"#5091FF",marginBottom:"20px"}}>了解什么是DevOps</Link> <div className="activatePanel">
<Form> <img src={activate} alt="" width="250px" />
{helper( <P>定义DevOps工作流帮助您检测bug发布代码</P>
"服务器IP地址", {
"ip_num", CurrentLogin !== AuthorLogin ?
[{ required: true, message: "请输入服务器IP地址" }], <div className="noOperation">DevOps开启功能暂未对项目创建者以外的角色开放可以联系项目创建者进行开启开启后便可查看构建信息</div>:""
<Input placeholder="请输入服务器IP地址" style={{width:"368px"}} size="large" />,true }
)} <a href={"https://forum.trustie.net/forums/3110/detail"} target="_blank" style={{ color: "#5091FF"}}>
{helper( 了解什么是DevOps
"服务器用户名:", </a>
"account", <a href={"https://forum.trustie.net/forums/3080/detail"} target="_blank" style={{ color: "#5091FF"}}>
[{ required: true, message: "请输入服务器用户名" }], 如何使用DevOps
<Input placeholder="请输入服务器用户名" size="large" />,true </a>
)} {
{helper( AuthorLogin === CurrentLogin ?
"服务器密码:", <React.Fragment>
"secret", {
[{ required: true, message: "请输入服务器密码" }], step === 0 && !typeFlag ?
<Input.Password placeholder="请输入服务器密码" size="large" />,true <ServiceModal sureModal={sureModal}></ServiceModal>
)} :""
</Form> }
<Blueback onClick={startActive}>开始激活</Blueback> { step === 0 && typeFlag ?
</div> <React.Fragment>
) <Input.Password style={{display:'none'}} size="large" />
<Form style={{marginTop:"20px"}}>
<p className="mb20" style={{width:"370px"}}>请仔细核对您的服务器信息一旦确认提交将无法修改</p>
{helper(
"服务器IP地址",
"ip",
[{ required: true, message: "请输入服务器IP地址" }],
<Input
placeholder="请输入服务器IP地址"
style={{ width: "368px" }}
size="large"
disabled={disabled}
/>,
true
)}
{helper(
"服务器用户名:",
"account",
[{ required: true, message: "请输入服务器用户名" }],
<Input placeholder="请输入服务器用户名" size="large" disabled={disabled}/>,
true
)}
{helper(
"服务器密码:",
"secret",
[{ required: true, message: "请输入服务器密码" }],
<Input.Password placeholder="请输入服务器密码" size="large" disabled={disabled}/>,
true
)}
</Form>
<AlignCenter>
{ !disabled && <Button className="mr20" onClick={()=>goUpStep(0)}>上一步</Button>}
<Blueback onClick={goStep}>下一步</Blueback>
</AlignCenter>
</React.Fragment>
:""
}
{
step === 1 ?
<div>
<AlignCenter style={{justifyContent:"center",marginTop:"20px"}}>
<span style={{marginBottom:"42px"}}>密码</span>
<div>
<Input.Password value={authorityVal} className={authorityValFlag===true && "flags"} onChange={(e)=>setAuthorityVal(e.target.value)} style={{width:"220px"}}></Input.Password>
<p className="color-grey-9" style={{textAlign:"left",lineHeight:'21px'}}>您已保存相关服务器信息请输入密码<br/>确认授权DevOps应用</p>
</div>
</AlignCenter>
<AlignCenter style={{justifyContent:'center'}}>
<Blueback onClick={authStep} className="mt20">下一步</Blueback>
</AlignCenter>
</div>:""
}
{ step === 2 ?
<div style={{textAlign:'center',marginTop:"20px"}}>
<Blueback onClick={startActive} className="mt20">开始激活</Blueback>
</div>:""
}
</React.Fragment>
:""
}
</div>
</Spin>
);
} }
export default Form.create()(forwardRef(About)); export default Form.create()(forwardRef(About));

View File

@ -1,140 +1,167 @@
import React , { useState , useEffect } from 'react'; import React , { useState , useEffect } from 'react';
import { Spin , Pagination } from 'antd';
import { Blueback } from '../Component/layout'; import { Blueback } from '../Component/layout';
import Editor from "react-monaco-editor"; import List from './Dispose/List';
import Modals from './DisposeModal'; import Head from './Dispose/head';
import FileLanguage from '../Component/FileLanguage';
import axios from 'axios'; import axios from 'axios';
import PipelineName from './Dispose/PipelineName';
import styled from 'styled-components';
const Div = styled.div`{
padding:24px 30px;
}`;
const limit = 15;
function Dispose(props){ function Dispose(props){
const [ info , setInfo ] = useState(undefined); const [ spining , setSpining ] = useState(true);
const [ updateInfo , setUpdateInfo ] = useState(undefined);
const [ list , setList ] = useState(undefined);
const [ permission , setPermission ] = useState(undefined);
const [ visible , setVisible ] = useState(false); const [ visible , setVisible ] = useState(false);
const [ ymlValue , setYmlValue ] = useState(""); const [ page , setPage ] = useState(1);
const [ six , setSix ] = useState(undefined); const [ totalCount , setTotalCount ] = useState(0);
const [ fileLanguage , setFileLanguage ] = useState(undefined); const [ branchList , setBranchList ] =useState(undefined);
const [ first , setFirst ] = useState(false);
const projectDetail = props.projectDetail;
const current_user = props.current_user;
let projectsId = props.match.params.projectsId; let projectsId = props.match.params.projectsId;
let owner = props.match.params.owner; let owner = props.match.params.owner;
//
useEffect(()=>{ useEffect(()=>{
if(projectsId){ if(projectDetail){
const url = '/dev_ops/builds/get_trustie_pipeline.json'; setPermission(props.projectDetail.permission);
axios.get(url,{
params:{
project_id:projectsId
}
}).then(result=>{
if(result && result.data.content){
setInfo(result.data);
setYmlValue(result.data.content);
setFirst(true);
}else{
setFirst(false);
}
}).catch(error=>{
console.log(error);
})
} }
},[]) },[projectDetail])
useEffect(()=>{ function Init(){
const url = '/dev_ops/languages/common.json'; const url = `/ci/pipelines/list.json`;
axios.get(url).then(result=>{ axios.get(url,{
if(result){ params:{
setSix(result.data); identifier:projectsId,owner,
page,limit
} }
}).catch(error=>{ }).then(result=>{
console.log(error); if(result && result.data){
}) setList(result.data.pipelines);
},[]) }
setSpining(false);
// }).catch(error=>{setSpining(false);})
function changeEditor(value){
setYmlValue(value);
} }
// useEffect(()=>{
function select_language(value,array){ Init();
setFileLanguage(value); },[page])
// console.log(array);
setYmlValue( array && array.content);
}
// useEffect(()=>{
function submit(){ if(owner && projectsId){
let url = ''; const url = `/${owner}/${projectsId}/branches.json`;
let params = { axios.get(url).then(result=>{
branch: "master", if(result && result.data){
content:ymlValue, setBranchList(result.data);
filepath:info && info.name,
message:''
}
if(first){
// true
url = `/${owner}/${projectsId}/update_file.json`;
axios.put(url,{
...params,
sha:info && info.sha
}).then(result=>{
if(result){
setVisible(true);
} }
}).catch(error=>{ }).catch(error=>{})
console.log(error); }
}) },[owner,projectsId])
// /线
function addNew(pipeline_name,id,branch,event){
setVisible(true);
setUpdateInfo(undefined);
if(pipeline_name){
let eventA = event.split(",");
let l = {pipeline_name,id,branch,event:eventA}
setUpdateInfo(l);
}else{ }else{
url = `/${owner}/${projectsId}/create_file.json`; setUpdateInfo(undefined);
axios.post(url,params).then(result=>{
if(result){
setVisible(true);
}
}).catch(error=>{
console.log(error);
})
} }
} }
function suresubmit(){
props.history.push(`/projects/${owner}/${projectsId}/ops/list`); function onOk(pipeline_name,updateId,branch,event){
} if(pipeline_name){
let eventStr = "";
return( for(var i = 0;i<event.length;i++){
<React.Fragment> eventStr +=event[i]+",";
<Modals visible={visible} closeFunc={(flag)=>setVisible(flag)} sureFunc={suresubmit}></Modals>
<p>编程语言</p>
{
six &&
<ul className="language">
{
six && six.map((item,key)=>{
return(
key < 6 ? <li><img alt="" src={item.cover_url} /></li> : ""
)
})
}
</ul>
} }
<div className="mt20 mb20"> eventStr = eventStr.substring(0,eventStr.length-1);
<FileLanguage language={fileLanguage} select_language={select_language}/> if(!updateId){
//
const url = `/ci/pipelines.json`;
axios.post(url,{
pipeline_name,
file_name:".trustie-pipeline.yml",
repo:projectsId,branch,event:eventStr,owner
}).then(result=>{
setVisible(false);
if(result && result.data){
props.showNotification("流水线新增成功,请进行工作流配置!");
props.history.push(`/projects/${owner}/${projectsId}/devops/dispose/${result.data.id}`);
}else{
props.showNotification("流水线新增失败,请稍后再试!");
}
}).catch(error=>{})
}else{
//
const url = `/ci/pipelines/${updateId}.json`;
axios.put(url,{
pipeline_name,repo:projectsId,branch,event:eventStr,owner
}).then(result=>{
if(result && result.data){
setVisible(false);
Init();
props.showNotification("流水线名称更新成功!");
}else{
props.showNotification("流水线名称更新失败,请稍后再试!");
}
}).catch(error=>{})
}
}else{
props.showNotification("请输入流水线名称!");
}
}
//
function deleteFunc(id){
const url = `/ci/pipelines/${id}.json`;
axios.delete(url).then(result=>{
if(result && result.data){
props.showNotification("流水线删除成功!");
Init();
}
}).catch(error=>{})
}
//
function toModalManage(){
props.history.push(`/projects/${owner}/${projectsId}/devops/mould`);
}
//
function toparameter(){
props.history.push(`/projects/${owner}/${projectsId}/devops/params`);
}
const operate = current_user && (permission && permission !== "Reporter");
return(
<Spin spinning={spining}>
<PipelineName branchList={branchList} visible={visible} value={updateInfo} onCancel={()=>setVisible(false)} onOk={onOk}/>
<div className="disposePanel">
<Head manager={ operate ? toModalManage : undefined} parameter={operate ? toparameter :undefined}/>
<Div>
{ operate && <Blueback onClick={()=>addNew(undefined,undefined)}>新增流水线</Blueback> }
<div className="mt20 disposeList">
<List list={list} operate={operate} projectsId={projectsId} owner={owner} showModal={addNew} deleteFunc={deleteFunc}/>
{
totalCount > limit &&
<div className="mt20 pb20" style={{textAlign:'center'}}>
<Pagination simple current={page} pageSize={limit} total={totalCount} onChange={(page)=>setPage(page)}/>
</div>
}
</div>
</Div>
</div> </div>
<p>配置脚本</p> </Spin>
<div className="editorBody">
<p className="editorHead">
<span>{info && info.name}</span>
<a><i className="iconfont icon-bianji6 font-14"></i></a>
</p>
<Editor
height="300px"
language={"java"}
theme={"vs-grey"}
defaultValue="请输入内容"
value={ymlValue}
options={"editor_options"}
onChange={changeEditor}
></Editor>
</div>
<Blueback onClick={submit}>确定提交</Blueback>
</React.Fragment>
) )
} }
export default Dispose; export default Dispose;

View File

@ -0,0 +1,100 @@
import React , { useEffect , useState } from 'react';
function Choosen({ chooseFunc, temp , templateId , category }){
const [ tempId, setTemId ] = useState(undefined);
const [ cate , setCate ]= useState(undefined);
const [ templates , setTemplates ] = useState(undefined);
const [ categories , setCategories ] = useState(undefined);
useEffect(()=>{
if(templateId){
setTemId(templateId);
}
},[templateId])
useEffect(()=>{
if(category){
setCate(category);
}
},[category])
useEffect(()=>{
if(temp && temp.length > 0){
if(temp[0].category !== "初始化"){
setCategories(temp);
}else{
setCategories(undefined);
}
if(category && temp[0].category !== "初始化" && category !== "初始化"){
let c = temp.filter(item=>item.category === category);
let t = c && c.length > 0 && c[0].templates;
setTemplates(t);
setCate(category);
}else{
setTemplates(temp[0].templates);
setCate(temp[0].category);
}
}else{
setTemplates(undefined);
setCate(undefined);
setCategories(undefined);
}
},[temp,category])
//
function changeCate(cate){
setCate(cate);
let c = categories && categories.filter(item=>item.category === cate);
let t = c && c[0].templates;
setTemplates(t);
let m_t_id = t && t.length>0 && t[0].id;
let m_t_content = t && t.length>0 && t[0].content;
setTemId(m_t_id);
chooseFunc && chooseFunc(m_t_content,m_t_id,cate);
}
//
function chooseOption(id){
let item = templates.filter(item=>item.id === id);
let content = item && item.length >0 && item[0].content;
chooseFunc && chooseFunc(content,id,cate);
setTemId(id);
}
return(
<React.Fragment>
{
categories && categories.length > 0 &&
<div className="choosenList">
<span>模板类别</span>
<ul>
{
categories.map((item,key)=>{
return(
<li className={cate === item.category ?"active":""} onClick={()=>changeCate(item.category)}>{item.category}</li>)
})
}
</ul>
</div>
}
{
templates && templates.length> 0 &&
<div className="choosenList">
<span>模板选择</span>
<ul>
{
templates.map((item,key)=>{
return(
<li className={tempId === item.id ? "active":""} onClick={()=>chooseOption(item.id)}>{item.template_name}</li>
)
})
}
</ul>
</div>
}
</React.Fragment>
)
}
export default Choosen;

View File

@ -0,0 +1,37 @@
import React from 'react';
import Editor from 'react-monaco-editor';
function Editors({value,onChange,theme,height,visible,width="100%",Numbers="on"}){
const editor_options = {
lineNumbers: Numbers,
wordWrap: true, //
selectOnLineNumbers: true,
lineHeight: 24,
renderLineHighlight: "line",
revealHorizontalRightPadding: 5,
placeholder:"请输入内容",
readOnly: visible,
cursorStyle: visible ? "underline-thin" : "line",
folding: true,
foldingStrategy: "indentation", //
automaticLayout: true, //
minimap: {
//
enabled: false,
},
}
return(
<Editor
height={height}
width={width}
language={"yaml"}
theme={theme}
placeholder="请输入内容"
value={value}
options={editor_options}
onChange={(value)=>onChange(value)}
disabled={true}
></Editor>
)
}
export default Editors;

View File

@ -0,0 +1,66 @@
import React , { useEffect , useState } from 'react';
import { Button } from 'antd';
import Choosen from './Choosen';
import Editors from './Editors';
function Init({ datas , templates , saveFunc , saveDatas}){
const [ templateId , setTemplateId ] = useState(undefined);
const [ ymlValue , setYmlValue ] = useState(undefined);
const [ temp , setTemp ] = useState(undefined);
useEffect(()=>{
if(templates && templates.length > 0){
setTemp(templates)
}
},[templates])
useEffect(()=>{
if(datas && datas.length > 0){
setTemplateId(datas[0].template_id);
setYmlValue(datas[0].content);
}
},[datas])
//
function chooseFunc(content,id,cate){
setTemplateId(id);
setYmlValue(content);
recieveData(id,content);
}
function recieveData(id,content){
let steps = datas;
if(datas && datas.length>0){
steps[0].content = content || ymlValue;
steps[0].template_id = id || templateId ;
}else{
steps =
[{
step_name:"初始化",
show_index:1,
content:content || ymlValue,
template_id:id || templateId
}]
}
saveDatas(steps);
}
//
function nextStep(){
recieveData();
saveFunc(undefined,undefined,undefined,undefined,"next");
}
return(
<div>
<Choosen chooseFunc={chooseFunc} templateId={templateId} temp={temp}/>
<div className="mt15">
<Editors value={ymlValue} onChange={setYmlValue} theme={"vs-dark"} height={"400px"}/>
</div>
<div className="mt20">
<Button type={"primary"} onClick={nextStep}>下一步</Button>
</div>
</div>
)
}
export default Init;

View File

@ -0,0 +1,131 @@
import React from 'react';
import { Table , Popconfirm } from 'antd';
import { Link } from 'react-router-dom';
// const STATUS = {
// running:"",
// failure:"",
// error:"",
// success:"",
// killed:"",
// pending:""
// }
function renderTableStatus(status) {
switch (status) {
case "running":
return (
<span className="statusTag running">
<i className="iconfont icon-yunhangzhong"></i>运行中
</span>
);
case "failure": case 'error':
return (
<span className="statusTag failed">
<i className="iconfont icon-weitongguo"></i>未通过
</span>
);
case "success":
return (
<span className="statusTag pass">
<i className="iconfont icon-yitongguo"></i>已通过
</span>
);
case 'killed':
return (
<span className="statusTag killed">
<i className="iconfont icon-weitongguo"></i>已撤销
</span>
);
default :
return (
<span className="statusTag Preparing">
<i className="iconfont icon-zhunbeizhong"></i>准备中
</span>
);
}
}
function List({ list, operate , projectsId , owner , showModal , deleteFunc }){
const columns = [
{
title:"流水线名称",
dataIndex:"pipeline_name",
key:1,
ellipsis:true,
render:(txt,item)=>{
return(
<span onDoubleClick={()=>showModal(txt,item.id,item.branch,item.event)} style={{display:"block",cursor:"pointer"}}>{txt}</span>
)
}
},
{
title:"文件名称",
dataIndex:"file_name",
key:1,
width:"15%",
ellipsis:true,
render:(value,item)=>{
return(
<Link to={`/projects/${owner}/${projectsId}/tree/${item.branch}/${value}`} className="color-blue">{value}</Link>
)
}
},
{
title:"触发分支",
dataIndex:"branch",
key:1,
width:"10%",
ellipsis:true
},
{
title:"触发事件",
dataIndex:"event",
key:1,
width:"10%",
ellipsis:true
},
{
title:"最近构建时间",
dataIndex:"last_build_time",
key:1,
width:"15%",
ellipsis:true
},
{
title:"最近构建状态",
dataIndex:"pipeline_status",
key:1,
width:"12%",
ellipsis:true,
render:(txt)=>{
return renderTableStatus(txt)
}
},
{
title:"操作",
dataIndex:"operation",
key:1,
width:"21%",
render:(txt,item)=>{
return(
<span>
{ operate ?
<Link to={`/projects/${owner}/${projectsId}/devops/dispose/${item.id}`} className="mr10 color-grey-6">
<i className="iconfont icon-zaibianji font-13 mr3"></i>编辑</Link> :""
}
{ operate ?
<Popconfirm title={"确定要删除此流水线?"} onConfirm={()=>deleteFunc(item.id)} okText="确定" cancelText={"取消"}>
<a className="mr10 color-grey-6"><i className="iconfont icon-lajitong font-13 mr3"></i>删除</a>
</Popconfirm>:""
}
<Link to={`/projects/${owner}/${projectsId}/devops/list/${item.branch}`} className="color-grey-6"><i className="iconfont icon-yunhang font-13 mr3"></i>查看运行记录</Link>
</span>
)
}
}
]
return(
<Table size="small" columns={columns} dataSource={list} rowKey={(row)=>row.id} pagination={false}></Table>
)
}
export default List;

View File

@ -0,0 +1,67 @@
import React , { useEffect , useState } from 'react';
import { Modal , Input , Select } from 'antd';
const { Option }= Select;
const EVENT = ["push","pull_request","tag","cron","custom","promote","rollback"]
function PipelineName({visible,onCancel,onOk,value ,branchList}){
const [ name , setName ] = useState(undefined);
const [ branchValue , setBranchValue ] = useState(undefined);
const [ eventValue , setEventValue ] = useState([EVENT[0]]);
useEffect(()=>{
if(branchList && branchList.length>0){
setBranchValue(branchList[0].name);
}
},[branchList])
useEffect(()=>{
if(value){
setName(value.pipeline_name);
setBranchValue(value.branch);
setEventValue(value.event);
}else{
setName(undefined);
}
},[value])
function onSure(){
onOk(name,value && value.id,branchValue,eventValue);
}
return(
<Modal
visible={visible}
title="流水线名称"
width={"500px"}
onCancel={onCancel}
onOk={onSure}
centered={true}
>
<div className="choosenList">
<span>流水线名称:</span>
<Input value={name} onChange={(e)=>setName(e.target.value)} placeholder="请输入名称" style={{width:"340px",margin:"6px 0px"}}/>
</div>
<div className="choosenList mt20">
<span>触发条件:</span>
<Select value={branchValue} style={{width:"150px"}} onChange={(e)=>setBranchValue(e)}>
{
branchList && branchList.length>0 && branchList.map((item,key)=>{
return(
<Option value={item.name} key={key}>{item.name}</Option>
)
})
}
</Select>
<Select mode="multiple" allowClear value={eventValue} style={{width:"180px",marginLeft:"10px"}} onChange={(e)=>{console.log(e);setEventValue(e)}}>
{
EVENT.map((item,key)=>{
return(
<Option value={item} key={key}>{item}</Option>
)
})
}
</Select>
</div>
</Modal>
)
}
export default PipelineName;

View File

@ -0,0 +1,102 @@
import React , { useEffect , useState } from 'react';
import { Button , Popconfirm } from 'antd';
import { Cancel } from '../../Component/layout';
import Item from './StageItem';
function Stage({
templates ,
datas ,
saveDatas ,
saveFunc ,
stepName ,
deleteStep ,
deleteFunc ,
deleteFlag
}){
const [ stepList , setStepList ] = useState(undefined);
const [ temp , setTemp ] = useState(undefined);
useEffect(()=>{
if(templates && templates.length > 0){
setTemp(templates);
}
},[templates])
useEffect(()=>{
if(datas){
if(datas.length > 0 && stepList !== datas){
setStepList(datas);
}else if(datas.length === 0){
let list = [];
setStepList(list);
}
}
},[datas])
//
function addFunc(){
let list = stepList;
let length = list ? list.length : 0;
let pre = temp && temp.length > 0 && temp[0];
let c = pre && pre.category;
let child = pre && pre.templates && pre.templates.length > 0 && pre.templates[0];
let step =
{
"category":c,
"step_name": stepName+`${length + 1}`,
"show_index": length + 1,
"content":child.content,
"template_id":child.id,
"hide":false
}
list.push(step);
saveDatas(list);
}
//
function saveItems(content,id,cate,key){
let item = stepList;
item[key].content = content;
item[key].template_id = id;
item[key].category = cate;
saveDatas([...item]);
}
function slideItems(key,hide){
let item = stepList;
item[key].hide = !hide;
setStepList([...item]);
saveDatas(item);
}
function deleteItem(id,key){
deleteStep(id,key);
}
//
function nextStep(btn){
saveFunc(undefined,undefined,undefined,undefined,btn);
}
return(
<div>
{
stepList && stepList.length > 0 && stepList.map((item,key)=>{
return(
<Item item={item} templates={temp} k={key} saveItems={saveItems} slideItems={slideItems} deleteStep={deleteItem}/>
)
})
}
<a className="addStageBtn" onClick={addFunc}>+ 添加步骤</a>
<div className="mt20">
<Button type="primary" onClick={()=>nextStep("last")}>上一步</Button>
<Button className="ml20" type="primary" onClick={()=>nextStep("next")}>下一步</Button>
{!deleteFlag &&
<Popconfirm title={'确定要删除当前阶段吗'} okText="是" cancelText="否" onConfirm={deleteFunc}>
<Cancel className="ml20">删除</Cancel>
</Popconfirm>
}
</div>
</div>
)
}
export default Stage;

View File

@ -0,0 +1,41 @@
import React from 'react';
import { FlexAJ } from '../../Component/layout';
import Editors from './Editors';
import Choosen from './Choosen';
import { Popconfirm } from 'antd';
function StageItem({item, templates,saveItems,k, slideItems , deleteStep}){
function onChangevalue(value){
saveItems(value,item.template_id,item.category,k);
}
//
function chooseFunc(content,id,cate){
saveItems(content,id,cate,k);
}
return(
<div className="stepsItem">
<FlexAJ className="stepsHead">
<span>{item.step_name}</span>
<span className="color-grey-9">
<Popconfirm
title={"确定要删除这个步骤吗?"}
okText="是"
cancelText="否"
onConfirm={() => deleteStep(item.id,k)}
><a>
<i className="iconfont icon-lajitong1 font-14"></i></a>
</Popconfirm>
<a onClick={()=>slideItems(k,item.hide)}><i className={ (!item.hide || item.hide === false) ? "iconfont icon-sanjiaoxing-down font-14" :"iconfont icon-triangle font-14"}></i></a>
</span>
</FlexAJ>
<div className={(!item.hide || item.hide === false) ? "stepsBody active" : "stepsBody"}>
<Choosen chooseFunc={chooseFunc} category={item.category} templateId={item.template_id} temp={templates}/>
<Editors value={item.content} onChange={onChangevalue} theme="vs-dark" height="270px" />
</div>
</div>
)
}
export default StageItem;

View File

@ -0,0 +1,32 @@
import React ,{useEffect , useState} from 'react';
import { Button } from 'antd';
import Editors from './Editors';
function Sure({datas , name , saveFunc , sureSubmit , loading}){
const [ value , setValue ] = useState(undefined);
useEffect(()=>{
if(datas && datas.content){
setValue(datas.content)
}
},[datas]);
function sure(){
sureSubmit();
}
return(
<div>
<div style={{padding:"0px 15px 15px 15px"}}>
工作流名称{name}
</div>
<div className="editorBody" style={{marginTop:"0px"}}>
<Editors value={value} theme={"vs-grey"} height={"600px"} visible/>
</div>
<div className="mt20">
<Button type={"primary"} onClick={()=>saveFunc(undefined,undefined,undefined,undefined,"last")}>上一步</Button>
{ value && <Button type={"primary"} loading={loading} className="ml20" onClick={sure}>确定提交</Button> }
</div>
</div>
)
}
export default Sure;

View File

@ -0,0 +1,21 @@
import React from 'react';
import { AlignCenterBetween , Blueline , FlexAJ } from '../../Component/layout';
function head({manager , parameter}){
return(
<AlignCenterBetween>
<span className="font-20">工作流配置</span>
<FlexAJ>
{
parameter && <Blueline onClick={parameter}>参数管理</Blueline>
}
{
manager && <Blueline style={{marginLeft:"20px"}} onClick={manager}>模板管理</Blueline>
}
<a href={`https://forum.trustie.net/forums/3111/detail`} target="_blank" className="color-grey-6 ml20"><i className="iconfont icon-tishi1 font-14 mr3"></i>模板使用说明</a>
</FlexAJ>
</AlignCenterBetween>
)
}
export default head;

View File

@ -0,0 +1,40 @@
import React from 'react';
import MenusRename from './menusRename';
import MenusAdd from './menusAdd';
const typeIcon = {
init:"icon-initialize",build:"icon-structure",deploy:"icon-arrange",customize:"icon-newStage",confirm:'icon-sure'
}
function Menus({step,changeStep, menuList , renameFunc , checkDatas , addFunc }){
function InitActive(key,stage_type,stage_id,stage_name){
changeStep(key,stage_type,stage_id,stage_name);
}
//
function getName(name,index){
addFunc && addFunc(name,index);
}
return(
<ul className="menus">
{
menuList && menuList.length > 0 && menuList.map((item,key)=>{
return(
<React.Fragment key={item.id} >
<li onClick={()=>InitActive(item.show_index,item.stage_type,item.id,item.stage_name)} className={item.show_index === step ?"active":""}>
<i className={`iconfont ${typeIcon[`${item.stage_type}`]}`}></i>
<MenusRename renameFunc={renameFunc} id={item.id} name={item.stage_name} edit={item.stage_type !== "init" && item.stage_type !== "confirm"}/>
</li>
{ key !== (menuList.length-1) && menuList.length < 7 ?
<MenusAdd checkDatas={checkDatas} k={key+2} getName={getName}/>:""
}
</React.Fragment>
)
})
}
</ul>
)
}
export default Menus;

View File

@ -0,0 +1,55 @@
import React , { useState , useEffect } from 'react';
import { Input } from 'antd';
function menusAdd ({ getName , checkDatas , k }){
const [ show, setShow ] = useState(false);
const [ value , setValue ] = useState(undefined);
const [ index , setIndex ] = useState(undefined);
const [ref, setRef ] = useState(undefined);
const [put, setPut ] = useState(false);
useEffect(() => {
if (put && ref) {
ref.focus();
}
})
useEffect(() => {
if (k) {
setIndex(k);
}
},[k])
function blurInput(){
if(value){
getName(value , index);
}
setValue(undefined);
setShow(false);
setPut(false);
}
function showInput(){
let c = checkDatas();
if(c || c === "" ){
setShow(true);
setPut(true);
}
}
return(
<li className="menuAdd">
{ !show && <i className="iconfont icon-tianjia" onClick={showInput}></i> }
<Input
ref={(el) => setRef(el)}
size={"small"}
maxLength={8}
style={{width:"75px",display : `${show?"block":'none'}`}}
placeholder="新阶段名称"
value={value}
onChange={(e)=>setValue(e.target.value)} onBlur={blurInput}
/>
</li>
)
}
export default menusAdd;

View File

@ -0,0 +1,53 @@
import React , { useEffect , useState } from 'react';
import { Input } from 'antd';
function menusRename({ name , edit , id , renameFunc }){
const [ n , setN ] = useState(undefined);
const [ show , setShow ] = useState(false);
const [ref, setRef ] = useState(undefined);
const [put, setPut ] = useState(false);
useEffect(() => {
if (edit && ref) {
ref.focus();
}
})
useEffect(()=>{
if(name){
setN(name)
}
},[name])
// input
function changeShow(e){
e.stopPropagation();
setShow(true);
setPut(true);
}
function blurInput(e){
renameFunc(e.target.value,id);
setPut(false);
setShow(false);
}
return(
<div className="aboutEdit">
<span className="operateName">
{ !show && n }
<Input
ref={(el) => setRef(el)}
value={n}
size="small"
maxLength={8}
onClick={(e)=>e.stopPropagation()}
onBlur={blurInput}
style={{width:"75px",display : `${show?"block":'none'}`}}
onChange={(e)=>setN(e.target.value)}
/>
{ !show && edit && <i className="iconfont icon-editUnder font-16 color-grey-9" onClick={changeShow}></i> }
</span>
</div>
)
}
export default menusRename

View File

@ -8,7 +8,7 @@ const Div = styled.div`{
text-align:center; text-align:center;
color:#333; color:#333;
}` }`
export default (({visible , closeFunc , suresubmit})=>{ export default (({visible , closeFunc , sureFunc})=>{
return( return(
<Modal <Modal
title="提示" title="提示"
@ -17,7 +17,7 @@ export default (({visible , closeFunc , suresubmit})=>{
footer={ footer={
<div> <div>
<Button onClick={()=>closeFunc(false)}>取消</Button> <Button onClick={()=>closeFunc(false)}>取消</Button>
<Button type={"primary"} onClick={suresubmit} style={{marginLeft:"20px"}}>确定</Button> <Button type={"primary"} onClick={()=>sureFunc()} style={{marginLeft:"20px"}}>确定</Button>
</div> </div>
} }
onCancel={()=>closeFunc(false)} onCancel={()=>closeFunc(false)}

View File

@ -1,4 +1,4 @@
import React from 'react'; import React , { useEffect } from 'react';
import { WhiteBack } from '../Component/layout'; import { WhiteBack } from '../Component/layout';
import './ops.scss'; import './ops.scss';
@ -10,27 +10,65 @@ const About = Loadable({
loader: () => import('./About'), loader: () => import('./About'),
loading: Loading, loading: Loading,
}) })
const Infos = Loadable({ const New = Loadable({
loader: () => import('./Infos'), loader: () => import('./disposePipeline'),
loading: Loading, loading: Loading,
}) })
const Dispose = Loadable({
loader: () => import('./Dispose'),
loading: Loading,
})
const Stucture = Loadable({
loader: () => import('./Structure'),
loading: Loading,
})
const Mould = Loadable({
loader: () => import('./Mould'),
loading: Loading,
})
const Params = Loadable({
loader: () => import('./Manage/Params'),
loading: Loading,
})
export default ((props)=>{ export default ((props)=>{
return( return(
<WhiteBack className="opsPanel"> <WhiteBack className="opsPanel">
<Switch {...props}> <Switch {...props}>
<Route path="/projects/:projectsId/ops/dispose" <Route path="/projects/:owner/:projectsId/devops/dispose/:disposeId"
render={ render={
() => (<Infos {...props} />) (p) => (<New {...props} {...p}/>)
} }
></Route> ></Route>
<Route path="/projects/:projectsId/ops/list" <Route path="/projects/:owner/:projectsId/devops/params"
render={ render={
() => (<Infos {...props} />) (p) => (<Params {...props} {...p}/>)
} }
></Route> ></Route>
<Route path="/projects/:projectsId/ops" <Route path="/projects/:owner/:projectsId/devops/mould"
render={ render={
() => (<About {...props} />) (p) => (<Mould {...props} {...p}/>)
}
></Route>
<Route path="/projects/:owner/:projectsId/devops/dispose/new"
render={
(p) => (<New {...props} {...p}/>)
}
></Route>
<Route path="/projects/:owner/:projectsId/devops/dispose"
render={
(p) => (<Dispose {...props} {...p}/>)
}
></Route>
<Route path="/projects/:owner/:projectsId/devops/list/:branch"
render={
(p) => (<Stucture {...props} {...p}/>)
}
></Route>
<Route path="/projects/:owner/:projectsId/devops"
render={
(p) => (<About {...props} {...p}/>)
} }
></Route> ></Route>
</Switch> </Switch>

View File

@ -3,7 +3,6 @@ import { Banner } from '../Component/layout';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import Dispost from './Dispose'; import Dispost from './Dispose';
import Structure from './Structure';
import styled from 'styled-components'; import styled from 'styled-components';
@ -11,27 +10,26 @@ const Div = styled.div`{
padding:24px 30px; padding:24px 30px;
}`; }`;
export default ((props)=>{ export default ((props)=>{
const [ menu , setMenu ] = useState(undefined); const [ permission , setPermission ] = useState("");
const owner = props.match.params.owner;
const projectDetail = props.projectDetail;
const path = props.location.pathname;
useEffect(()=>{ useEffect(()=>{
// console.log(props.match.params.projectsId) if(projectDetail){
if(path === `/projects/${props.match.params.projectsId}/ops/list`){ setPermission(props.projectDetail.permission);
setMenu(true);
}else{
setMenu(false);
} }
},[path]) },[projectDetail])
return( return(
<div className="disposePanel"> <div className="disposePanel">
<Banner> <Banner>
<Link to={`/projects/${props.match.params.projectsId}/ops/dispose`}>工作流配置</Link> { permission !=="Reporter" && <Link to={`/projects/${owner}/${props.match.params.projectsId}/devops/dispose`}>工作流配置</Link>}
{ menu ? <Link to={`/projects/${props.match.params.projectsId}/ops/list`} style={{ marginLeft:"66px",color:"#5091FF" }}>构建列表</Link>:""}
</Banner> </Banner>
<Div> <Div>
{ menu && menu === true && <Structure {...props}/> } <Dispost {...props}/>
{ menu && menu === false && <Dispost {...props}/> }
</Div> </Div>
</div> </div>
) )

View File

@ -0,0 +1,119 @@
import React , { useEffect , useState , useRef } from 'react';
import { Banner , Blueback , FlexAJ , AlignCenter } from '../../Component/layout';
import { Input , Table , Popconfirm , Pagination } from 'antd';
import { Link } from 'react-router-dom';
import styled from 'styled-components';
import New from './ParamsNew';
import "./manage.scss";
import axios from 'axios';
import { result } from 'lodash';
const Div = styled.div`{
padding:24px 30px;
min-height:420px;
}`;
function Params(props){
const [ list ,setList ] = useState(undefined);
const [ editList ,setEditList ] = useState(undefined);
const [ visible ,setVisible ] = useState(false);
let projectsId = props.match.params.projectsId;
let owner = props.match.params.owner;
useEffect(()=>{
Init()
},[])
function Init(){
const url = `/ci/secrets.json`;
axios.get(url,{
params:{
owner,repo:projectsId
}
}).then(result=>{
if(result){
setList(result.data);
}
}).catch(error=>{})
}
const columns=[
{
title:"参数名",
dataIndex:"name",
key:1,
ellipsis:true
},
{
title:"操作",
dataIndex:"operation",
key:4,
render:(txt,item)=>{
return(
<React.Fragment>
<a className="mr10 color-grey-6" onClick={()=>editMouldFunc(item)}><i className="iconfont icon-zaibianji font-13 mr3"></i>编辑</a>
<Popconfirm title={"确定要删除此模板?"} onConfirm={()=>deleteMouldFunc(item.id,item.name)} okText="确定" cancelText={"取消"}>
<a className="mr10 color-grey-6"><i className="iconfont icon-lajitong font-13 mr3"></i>删除</a>
</Popconfirm>
</React.Fragment>
)
}
}
]
//
function editMouldFunc(item){
setEditList(item);
setVisible(true);
}
//
function deleteMouldFunc(id,name){
if(id && name){
const url = `/ci/secrets/${id}.json`;
axios.delete(url,{
params:{owner,repo:projectsId,name}
}).then(result=>{
if(result){
Init();
props.showNotification(`参数删除成功!`);
}
}).catch(error=>{})
}
}
function successFunc(values,id){
const url = `/ci/secrets.json?owner=${owner}&repo=${projectsId}`;
axios.post(url,{
...values,id
}).then(result=>{
if(result){
props.showNotification(`${id ? '参数编辑':"新增参数"}成功!`);
Init();
}
}).catch(error=>{})
}
function CancelFunc(){
setVisible(false)
}
return(
<div>
<New visble={visible} successFunc={successFunc} CancelFunc={CancelFunc} editList={editList}/>
<Banner>
<FlexAJ>
<span className="font-18">工作流 - 参数管理</span>
<Link to={`/projects/${owner}/${projectsId}/devops/dispose`} className="font-14 color-grey-9 ml20">返回</Link>
</FlexAJ>
</Banner>
<Div className="disposeList">
<div style={{textAlign:"right"}}>
<Blueback onClick={()=>setVisible(true)}>新建</Blueback>
</div>
<Table className="mt20" size="small" columns={columns} dataSource={list} rowKey={(row)=>row.id} pagination={false}></Table>
</Div>
</div>
)
}
export default Params;

View File

@ -0,0 +1,73 @@
import React , { useEffect , useState , useRef , forwardRef } from 'react';
import { Modal , Input , Form } from 'antd';
const { TextArea } = Input;
function ParamsNew({ form , visble,successFunc,CancelFunc ,editList }){
const { getFieldDecorator, validateFields , setFieldsValue } = form;
const layout = {
labelCol: { span: 5 },
wrapperCol: { span: 18 },
};
useEffect(()=>{
if(editList && editList.id){
setFieldsValue({
name:editList.name,
data:editList.data
})
}else{
setFieldsValue({
name:undefined,
data:undefined
})
}
},[editList])
//
function onConfirmFunc(){
validateFields((error,values)=>{
if(!error){
successFunc(values,editList && editList.id);
onCancelFunc();
}
})
}
function onCancelFunc(){
setFieldsValue({
name:undefined,
data:undefined
})
CancelFunc();
}
return(
<Modal
visible={visble}
okText={"确定"}
cancelText={"取消"}
onCancel={onCancelFunc}
onOk={onConfirmFunc}
title={"新建"}
closable={false}
width="500px"
>
<Form {...layout}>
<Form.Item label="参数名称">
{getFieldDecorator("name",{
rules:[{required:true,message:"请输入参数名称"}]
})(
<Input placeholder="请输入参数名称" width="220px"/>
)}
</Form.Item>
<Form.Item label="参数值">
{getFieldDecorator("data",{
rules:[{required:true,message:"请输入参数值"}]
})(
<TextArea placeholder="请输入参数值" width="220px" autoSize={{ minRows: 4, maxRows: 4 }}/>
)}
</Form.Item>
</Form>
</Modal>
)
}
export default Form.create()(forwardRef(ParamsNew));

View File

@ -0,0 +1,4 @@
.ant-form-explain{
position: absolute;
bottom: -15px;
}

160
src/forge/DevOps/Mould.jsx Normal file
View File

@ -0,0 +1,160 @@
import React , { useEffect , useState , useRef } from 'react';
import { Banner , Blueback , FlexAJ } from '../Component/layout';
import { Input , Table ,Pagination , Select , Popconfirm } from 'antd';
import { Link } from 'react-router-dom'
import styled from 'styled-components';
import axios from 'axios';
import New from './MouldNew';
const { Option } = Select;
const Div = styled.div`{
padding:24px 30px;
min-height:420px;
}`;
const STAGE = [
{stage_name:"所有",stage_type:"all"},
  {stage_name:"初始化",stage_type:"init"},
  {stage_name:"编译构建",stage_type:"build"},
  {stage_name:"部署",stage_type:"deploy"},
  {stage_name:"其他",stage_type:"customize"}
]
const limit = 15;
function Mould(props){
const [ visible ,setVisible ] = useState(false);
const [ list ,setList ] = useState(undefined);
const [ page ,setPage ] = useState(1);
const [ totalCount ,setTotalCount ] = useState(0);
const [ stageType ,setStageType ] = useState("all");
const [ search ,setSearch ] = useState(undefined);
const childRef = useRef();
let projectsId = props.match.params.projectsId;
let owner = props.match.params.owner;
useEffect(()=>{
Init(page,stageType);
},[page,stageType])
function Init(page,stageType,searchvalue){
const url = `/ci/templates/list.json`;
axios.get(url,{
params:{
page,limit,stage_type:stageType,name:searchvalue
}
}).then(result=>{
if(result && result.data){
setList(result.data.templates);
setTotalCount(result.data.total_count);
}
}).catch(error=>{})
}
const columns=[
{
title:"名称",
dataIndex:"template_name",
key:1,
ellipsis:true
},
{
title:"所属阶段",
dataIndex:"stage_type",
key:2,
ellipsis:true,
render:(txt,item)=>{
let i = STAGE.filter(item=>item.stage_type === txt);
return i && i.length>0 && i[0].stage_name
}
},
{
title:"模板类型",
dataIndex:"category",
key:3,
ellipsis:true
},
{
title:"操作",
dataIndex:"operation",
key:4,
ellipsis:true,
render:(txt,item)=>{
return(
<span>
<a className="mr10 color-grey-6" onClick={()=>editMouldFunc(item)}><i className="iconfont icon-zaibianji font-13 mr3"></i>编辑</a>
<Popconfirm title={"确定要删除此模板?"} onConfirm={()=>deleteMouldFunc(item.id)} okText="确定" cancelText={"取消"}>
<a className="mr10 color-grey-6"><i className="iconfont icon-lajitong font-13 mr3"></i>删除</a>
</Popconfirm>
</span>
)
}
}
]
//
function editMouldFunc(item){
if (childRef.current) {
childRef.current.setEditInfo(item);
}
setVisible(true);
}
//
function deleteMouldFunc(id){
const url = `/ci/templates/${id}.json`;
axios.delete(url).then(result=>{
if(result && result.data){
props.showNotification("模板删除成功!");
Init(page,stageType,search);
}
})
}
function searchValue(){
Init(page,stageType,search);
}
function newMouldFunc(){
if (childRef.current) {
childRef.current.setEditInfo(undefined);
}
setVisible(true);
}
function onOk(){
Init(page,stageType);
}
return(
<div>
<New wrappedComponentRef={(f) => childRef.current = f} ref={childRef} visible={visible} onCancel={()=>setVisible(false)} onOk={onOk}></New>
<Banner>
<FlexAJ><span>工作流 - 模板管理</span><Link to={`/projects/${owner}/${projectsId}/devops/dispose`} className="font-14 color-grey-9">返回</Link></FlexAJ>
</Banner>
<Div className="disposeList">
<FlexAJ>
<Blueback onClick={newMouldFunc}>新建模板</Blueback>
<FlexAJ>
<span className="mr10">阶段</span>
<Select onChange={e=>setStageType(e)} value={stageType} style={{width:"180px"}}>
{
STAGE.map((item,key)=>{
return(
<Option value={item.stage_type}>{item.stage_name}</Option>
)
})
}
</Select>
<Input placeholder="请输入模板名称" value={search} onChange={(e)=>setSearch(e.target.value)} allowClear style={{width:"160px",marginLeft:"15px"}}/>
<Blueback className="ml15" onClick={searchValue}>搜索</Blueback>
</FlexAJ>
</FlexAJ>
<Table className="mt20" size="small" columns={columns} dataSource={list} rowKey={(row)=>row.id} pagination={false}></Table>
{
totalCount > limit &&
<div className="mt20 pb20" style={{textAlign:'center'}}>
<Pagination simple current={page} pageSize={limit} total={totalCount} onChange={(page)=>setPage(page)}/>
</div>
}
</Div>
</div>
)
}
export default Mould;

View File

@ -0,0 +1,166 @@
import React , { useImperativeHandle , useState , forwardRef , useCallback } from 'react';
import { Form , Modal , Input , Select , Spin } from 'antd';
import Editor from './Dispose/Editors';
import axios from 'axios';
const { Option } = Select;
const TYPE = ["Java","C","C++","Python","Go","Ruby","R","PHP",
    "Perl","Node","Docker","Rust","Swift","Erlang","Other"]
function MouldNew({ form , visible , onCancel , onOk }, ref){
const [value , setValue ] = useState(undefined);
const [isSpin , setIsSpin ] = useState(false);
const [valueFlag , setValueFlag ] = useState(false);
const [ id , setId ] = useState(false);
const [ buildFlag , setBuildFlag ] = useState(false);
const { getFieldDecorator, validateFields , setFieldsValue } = form;
useImperativeHandle(ref, () => ({
setEditInfo: (info) => {
if(info){
setFieldsValue({
...info
})
if(info.stage_type === "build"){
setBuildFlag(true);
setFieldsValue({
category:TYPE[0]
})
}else{
removeCate();
}
setValue(info.content);
setId(info.id);
}else{
removeCate();
clear();
setId(undefined);
}
}
}))
const helper = useCallback(
(label, name, rules, widget, className, isRequired,flag) => (
<Form.Item label={label} className={className}>
{getFieldDecorator(name, { rules, validateFirst: true , valuePropName:flag ? "checked":"value" })(widget)}
</Form.Item>
),
[]
);
function changeContent(v){
if(v){
setValue(v);
setValueFlag(false);
}
}
function cancel(){
clear();
onCancel();
}
function sure(){
if(!value){
setValueFlag(true);
return;
}
validateFields((error,values)=>{
if(!error){
setIsSpin(true);
const url = `/ci/templates.json`;
axios.post(url,{
...values,id,content:value,category:buildFlag ? values.category:""
}).then(result=>{
if(result && result.data){
setIsSpin(false);
cancel();
onOk();
}
}).catch(error=>{})
}
})
}
function clear(){
setFieldsValue({
stage_type:"init",
template_name:undefined,
category:"Java",
})
setValue("");
setValueFlag(false);
}
function changeStage(e){
if(e === "build"){
setBuildFlag(true);
setFieldsValue({
category:TYPE[0]
})
}else{
removeCate();
}
}
function removeCate(){
setBuildFlag(false);
setFieldsValue({
category:""
})
}
return(
<Modal
visible={visible}
width="500px"
title={"新建/编辑模板"}
onCancel={cancel}
onOk={sure}
centered={true}
>
<Spin spinning={isSpin}>
<Form layout={"inline"}>
{helper(
"所属阶段",
"stage_type",
[{required:true,message:"请选择所属阶段"}],
<Select placeholder="请选择所属阶段" style={{width:"350px"}} onChange={(e)=>{changeStage(e)}}>
<Option value="init">初始化</Option>
<Option value="build">编译构建</Option>
<Option value="deploy">部署</Option>
<Option value="customize">其他</Option>
</Select>
)}
{helper(
"模板名称",
"template_name",
[{required:true,message:"请输入模板名称"}],
<Input placeholder="请输入模板名称" style={{width:"350px"}}/>
)}
{helper(
"模板分类",
"category",
[{required:buildFlag,message:"请选择模板分类"}],
<Select placeholder="请选择模板分类" style={{width:"350px"}}>
{
TYPE.map((item,key)=>{
return(
<Option value={item}>{item}</Option>
)
})
}
</Select>,buildFlag===true ? "" :"hide"
)}
<div style={{display:'flex',justifyContent:"flex-start"}}>
<span><span className="color-red">* </span>模板内容</span>
<div>
<div className="editorPanel">
<Editor Numbers={"off"} width={"350px"} value={value} height="200px" theme="vs-grey" onChange={changeContent}/>
</div>
{ valueFlag && <span className="color-red">请输入模板内容</span>}
</div>
</div>
</Form>
</Spin>
</Modal>
)
}
export default Form.create()(forwardRef(MouldNew));

View File

@ -1,42 +1,127 @@
import React from 'react'; import React, { useEffect, useState } from "react";
import { FlexAJ , Blueline , AlignCenter } from '../Component/layout'; import { FlexAJ, Blueline, AlignCenter } from "../Component/layout";
import styled from 'styled-components'; import styled from "styled-components";
import { Menu } from 'antd'; import { Menu, Popconfirm } from "antd";
import { TagsLine } from '../Component/OpsStatus'; import { TagsLine } from "../Component/OpsStatus";
import { Time } from "../Utils/Time";
import { truncateCommitId } from "../common/util";
import { getUrl } from 'educoder';
const SubMenu = Menu.SubMenu; const SubMenu = Menu.SubMenu;
const Img = styled.img`{ const Img = styled.img`
width:25px; {
height:25px; width: 25px;
border-radius:50%; height: 25px;
margin-right:10px; border-radius: 50%;
}` margin-right: 10px;
export default (()=>{ }
return( `;
export default ({ data, repeatSet , chooseSteps }) => {
const [tamp, setTamp] = useState(undefined);
const [sha, setSha] = useState(undefined);
useEffect(() => {
if (data && data.started) {
let t = parseInt(data.started) * 1000;
let time = Time(t);
setTamp(time);
}
if (data && data.after) {
setSha(truncateCommitId(data.after));
}
}, [data]);
function renderStatusBtn() {
let status = data && data.status;
let number = data && data.number;
if (status === "failure" || status === "error" || status === "success") {
return "";
}else if(status === "killed"){
return(
<Popconfirm
title="确认重新构建?"
onConfirm={(e) => repeatSet(e,'repeat',number)}
onCancel={(e)=>{e.stopPropagation()}}
cancelText="取消"
okText="确定"
>
<Blueline onClick={(e)=>{e.stopPropagation()}}>重新构建</Blueline>
</Popconfirm>
);
} else {
return (
<Popconfirm
title="确认撤销构建?"
onConfirm={(e) => repeatSet(e,'cancel',number)}
onCancel={(e)=>{e.stopPropagation()}}
cancelText="取消"
okText="确定"
>
<Blueline onClick={(e)=>{e.stopPropagation()}}>撤销构建</Blueline>
</Popconfirm>
);
}
}
function clickSub(e,stageN,stepN){
chooseSteps(stageN,stepN);
}
return (
<div> <div>
<FlexAJ className="leftheader"> <FlexAJ className="leftheader">
<AlignCenter> <AlignCenter>
<Img src="https://dss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=2091711702,2468700162&fm=111&gp=0.jpg"/> <Img src={getUrl(`/images/${data && data.author && data.author.image_url}`)} />
<span className="nest">开始时间<span>2020.07.10 15:30</span></span> {data && data.started &&
<span className="nest">运行时间<span>20s</span></span> <span className="nest">
开始时间<span> {data.started}</span>
</span>
}
{
data && data.duration_time &&
<span className="nest">
运行时间<span>{data.duration_time}</span>
</span>
}
</AlignCenter> </AlignCenter>
<Blueline>重新创建</Blueline> {renderStatusBtn()}
</FlexAJ> </FlexAJ>
<div className="leftMainContent"> <div className="leftMainContent">
<AlignCenter className="contentBranch"> <AlignCenter className="contentBranch">
<i className="iconfont icon-fenzhi1"></i> <i className="iconfont icon-fenzhi1"></i>
<span>分支</span> <span>分支</span>
<span className="branchname">master</span> <span className="branchname">{data && data.branch_target}</span>
<span className="branchsha">8b3476f5</span> <span className="branchsha">{data && truncateCommitId(data.build_after_sha)}</span>
</AlignCenter> </AlignCenter>
</div> </div>
<Menu mode='inline' className="leftMenu"> <Menu mode="inline" className="leftMenu" defaultOpenKeys={[`0`]} defaultSelectedKeys={[`0`]}>
<SubMenu title={<div><i className="iconfont icon-gongzuoliu font-14 mr4"></i><span>CI</span></div>}> {data && data.stages ? data.stages.map((item, key) => {
<Menu.Item> return item.steps && item.steps.length > 0 ?
<FlexAJ><span>Build setup 01 {TagsLine(1)}</span><span>20s</span></FlexAJ> <SubMenu
</Menu.Item> title={
</SubMenu> <div>
<i className="iconfont icon-gongzuoliu font-14 mr4"></i>
<span>{item.name}</span>
</div>
}
key={`${key}`}
>
{item.steps.map((i, k) => {
return (
<Menu.Item key={`${k}`} onClick={(e)=>clickSub(e,item.number,i.id)}>
<FlexAJ>
<span>
{i.name} {i.status ? TagsLine(i.status) : ""}
</span>
<span>{i.duration_time}</span>
</FlexAJ>
</Menu.Item>
);
})}
</SubMenu>
: "";
})
: ""}
</Menu> </Menu>
</div> </div>
) );
}) };

View File

@ -1,21 +1,123 @@
import React from 'react'; import React, { useState, useEffect } from "react";
import { FlexAJ , AlignCenter } from '../Component/layout'; import { Spin , Menu } from "antd";
import { FlexAJ, AlignCenter } from "../Component/layout";
import axios from "axios";
import CodeSSH from './ssh/Index';
export default (()=>{ export default ({
return( data,
<div className="rightMainContent"> stepN,
<div> stageN,
<FlexAJ className="items"> projectId,
<span>Build setup 01</span> owner,
<AlignCenter>20<i className="iconfont icon-triangle"></i></AlignCenter> opsId,
</FlexAJ> rightSpin,
</div> }) => {
<div> const [coders, setCoders] = useState(undefined);
<FlexAJ className="items"></FlexAJ> const [empty, setEmpty] = useState(false);
</div> const [spining, setSpining] = useState(true);
<div> const [stage, setStage] = useState(undefined);
<FlexAJ className="items"></FlexAJ> const [step, setStep] = useState(undefined);
</div> const [nav, setNav] = useState("0");
</div>
) useEffect(() => {
}) setSpining(rightSpin);
}, [rightSpin]);
useEffect(() => {
if (data) {
let stages = data.stages;
if (stages && stages.length > 0) {
let pre = stageN
? stages.filter((item) => item.number === stageN)[0]
: stages[0];
setStage(pre);
let p = pre && pre.steps;
let sub = stepN
? p && p.length > 0 && p.filter((item) => item.id === stepN)[0]
: p[0];
setStep(sub);
setNav("0");
if (sub && sub.status !== "skipped") {
getStep(pre.number, sub.number);
}
// skippedout
if(sub.status === "skipped"){
setCoders(undefined);
setEmpty(true);
setSpining(false);
}
} else {
setSpining(false);
}
}
}, [data, stageN, stepN]);
function getStep(stageN, stepN) {
if (stageN && stepN) {
const url = `/${owner}/${projectId}/builds/${opsId}/logs/${stageN}/${stepN}.json`;
axios.get(url).then((result) => {
if (result) {
setCoders(result.data);
setSpining(false);
}
})
.catch((error) => {
console.log(error);
});
}
}
return (
<React.Fragment>
{/* <Menu className="devopsNav" onClick={(e)=>{setNav(e.key)}} selectedKeys={[nav]} mode="horizontal">
<Menu.Item key={'0'} value="0">开发流水线</Menu.Item>
<Menu.Item key={'1'} value="1">命令行</Menu.Item>
</Menu> */}
{
nav === "0" &&
<Spin spinning={spining}>
<div className="rightMainContent">
{data && data.status !== "error" ? (
<div>
<FlexAJ className="items">
<span>{step && step.name}</span>
<AlignCenter>
{step && step.duration_time}
<i className="iconfont icon-sanjiaoxing-down"></i>
</AlignCenter>
</FlexAJ>
<div>
{coders && coders.length > 0 ? (
coders.map((item, key) => {
return (
<div className="opsDetailOut">
<span>{key + 1}</span>
<p>{item.out}</p>
</div>
);
})
) : empty ? (
<div className="opsDetailOut">
<span>1</span>
<p>
{stage && stage.name} {step && step.name}: Skipped
</p>
</div>
) : (
""
)}
</div>
</div>
) : (
<div style={{ color: "red" }}>error:{data && data.error}</div>
)}
</div>
</Spin>
}
{
nav === "1" && <CodeSSH />
}
</React.Fragment>
);
};

View File

@ -0,0 +1,21 @@
import React, { useState } from 'react';
import { Radio , Button } from 'antd';
function ServiceModal({sureModal}){
const [ type , setType ] = useState(1);
function changeType(e){
setType(e.target.value);
}
return(
<div className="mt30" style={{textAlign:"center"}}>
<Radio.Group value={type} onChange={changeType}>
<Radio value={1}>自有服务器</Radio>
<Radio value={2}>Trustie服务器</Radio>
</Radio.Group>
<p className="mt30"><Button type="primary" onClick={()=>sureModal(type)}>下一步</Button></p>
</div>
)
}
export default ServiceModal;

View File

@ -1,240 +1,331 @@
import React , { useState , useEffect } from 'react'; import React, { useState, useEffect , useImperativeHandle ,forwardRef } from "react";
import { FlexAJ , AlignCenter , Blueback } from '../Component/layout'; import { FlexAJ, AlignCenter , Banner } from "../Component/layout";
import { Table , Pagination } from 'antd'; import { Table, Pagination, Popconfirm } from "antd";
import { truncateCommitId } from '../common/util'; import { truncateCommitId } from "../common/util";
import {getUrl} from 'educoder';
import axios from "axios";
import { Link } from 'react-router-dom';
import styled from 'styled-components'; import styled from 'styled-components';
import axios from 'axios';
const Div = styled.div`{
padding:24px 30px;
}`;
const STATUS = [ const STATUS = [
{name:"所有",value:"1"}, { name: "所有"},
{name:"准备中",value:"2"}, { name: "运行中", value: "running" },
{name:"运行中",value:"3"}, { name: "已撤销", value: "killed" },
{name:"已完成",value:"4"} { name: "构建失败", value: "failure" },
] { name: "已完成", value: "success" },
const LIMIT = 15;
const datasource = [
{
status:2,
author:"caishi",
message:{
branch:"master",
sha:"8b3476f5",
image:"https://dss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2034740944,4251903193&fm=26&gp=0.jpg",
message:"将分支“ 221063-improve-buy-ci-minutes-link”"
},
begin:"2020-07-08",
run:"20s"
},
{
status:1,
author:"caishi",
message:{
branch:"master",
sha:"8b3476f5",
image:"https://dss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2034740944,4251903193&fm=26&gp=0.jpg",
message:"将分支“ 221063-improve-buy-ci-minutes-link”"
},
begin:"2020-07-08",
run:""
}
]; ];
const LIMIT = 15;
function Structure(props,ref){
const [status, setStatus] = useState(undefined);
const [page, setPage] = useState(1);
const [total, setTotal] = useState(0);
const [data, setData] = useState(undefined);
const [tableLoading, setTableLoading] = useState(true);
const Img = styled.img`{ let projectsId = props.match.params.projectsId;
border-radius:50%; let owner = props.match.params.owner;
margin-rigth:10px; let branch = props.match.params.branch;
width:25px; const permission = props.projectDetail && props.projectDetail.permission;
height:25px;
}`
export default ((props)=>{
const [ status ,setStatus ] = useState("1");
const [ page ,setPage ] = useState(1);
const [ total ,setTotal ] = useState(10);
const [ data , setData ] = useState(undefined);
let projectsId = props.match.params.projectsId; useImperativeHandle(ref, () => ({
changeVal: () => {
useEffect(()=>{ setTableLoading(true);
if(projectsId){ Init();
const url ='/dev_ops/builds.json';
axios.get(url,{
params:{
project_id:projectsId
}
}).then(result=>{
if(result){
let list = result.data && result.data.map((item,key)=>{
return {
status:item.status,
author:item.sender,
message:{
branch:item.source,
image:item.author_avatar,
message:item.message,
sha:truncateCommitId(item.after)
},
started:item.started,
timestamp:item.timestamp
}
})
setData(list);
}
}).catch(error=>{
console.log(error);
})
} }
},[]) }))
function ChangeStatus(value){ useEffect(() => {
setStatus(value) if (projectsId) {
Init();
}
}, [page]);
let current_user = props.current_user;
function Init(status) {
const url = `/${owner}/${projectsId}/builds.json`;
axios.get(url,{
params:{
search:status,
page,limit:LIMIT,branch
}
}).then((result) => {
if (result && result.data) {
let list = result.data.builds && result.data.builds.map((item, key) => {
return {
...item,
author:item.author && item.author.name,
image_url:item.author && item.author.image_url,
message: {
branch: item.branch_target,
message: item.message,
sha: truncateCommitId(item.build_after_sha),
},
started: item.started || "--"
};
});
setTotal(result.data.total_count);
setData(list);
setTableLoading(false);
}
})
.catch((error) => {
console.log(error);
});
}
function ChangeStatus(value) {
setStatus(value);
Init(value);
} }
// //
function ChangePage(page){ function ChangePage(page) {
setPage(page) setPage(page);
} }
function renderStatus() { function renderStatus() {
return( return (
<ul className="listNav"> <ul className="listNav">
{ {STATUS.map((item, key) => {
STATUS.map((item,key)=>{ return (
return <li onClick={()=>ChangeStatus(item.value)} className={ status === item.value ? "active":""}>{item.name}</li> <li
}) onClick={() => ChangeStatus(item.value)}
} className={status === item.value ? "active" : ""}
>
{item.name}
</li>
);
})}
</ul> </ul>
) );
} }
function renderStatusBtn(status){ function renderStatusBtn(status, number) {
if(status === "failure" || status ==="success"){ if (status === "error" || status === "success") {
return "";
}else if(status === "killed" || status === "failure"){
return( return(
<a className="color-blue">重新构建</a> <Popconfirm
) title="确认重新构建?"
}else{ onConfirm={(e) => repeatSet(e,number)}
return( onCancel={(e)=>{e.stopPropagation()}}
<a className="color-red">撤销构建</a> cancelText="取消"
) okText="确定"
>
<a className="color-blue" onClick={(e)=>{e.stopPropagation()}}>重新构建</a>
</Popconfirm>
);
} else {
return (
<Popconfirm
title="确认撤销构建?"
onConfirm={(e) => cancelSet(e,number)}
onCancel={(e)=>{e.stopPropagation()}}
cancelText="取消"
okText="确定"
>
<a className="color-red" onClick={(e)=>{e.stopPropagation()}}>撤销构建</a>
</Popconfirm>
);
} }
} }
function renderTableStatus (status){ //
switch (status){ function repeatSet(e,number) {
e.stopPropagation();
setTableLoading(true);
const url = `/${owner}/${projectsId}/builds/${number}/restart.json`;
axios.post(url).then((result) => {
if (result) {
props.showNotification("工作流正在重新构建!");
Init();
}
})
.catch((error) => {
console.log(error);
});
}
//
function cancelSet(e,number) {
e.stopPropagation();
setTableLoading(true);
const url = `/${owner}/${projectsId}/builds/${number}/stop.json`;
axios.delete(url).then((result) => {
if (result) {
props.showNotification("撤销构建成功!");
Init(projectsId);
}
})
.catch((error) => {
console.log(error);
});
}
function renderTableStatus(status) {
switch (status) {
case "running": case "running":
return(
<span className="statusTag running"><i className="iconfont icon-yunhangzhong"></i>运行中</span>
);
case "failure":
return ( return (
<span className="statusTag failed"><i className="iconfont icon-weitongguo"></i>未通过</span> <span className="statusTag running">
<i className="iconfont icon-yunhangzhong"></i>运行中
</span>
);
case "failure": case 'error':
return (
<span className="statusTag failed">
<i className="iconfont icon-weitongguo"></i>未通过
</span>
); );
case "success": case "success":
return ( return (
<span className="statusTag pass"><i className="iconfont icon-yitongguo"></i>已通过</span> <span className="statusTag pass">
<i className="iconfont icon-yitongguo"></i>已通过
</span>
);
case 'killed':
return (
<span className="statusTag killed">
<i className="iconfont icon-weitongguo"></i>已撤销
</span>
); );
default: default:
return ( return (
<span className="statusTag Preparing"><i className="iconfont icon-zhunbeizhong"></i>准备中</span> <span className="statusTag Preparing">
<i className="iconfont icon-zhunbeizhong"></i>准备中
</span>
); );
} }
} }
function clickRows(event,e){
props.history.push(`/projects/${owner}/${projectsId}/devops/${e.number}/detail`);
}
const column = [ const column = [
{ {
title:'序号', title: "序号",
dataIndex:"No", dataIndex: "number",
key:"No", key: "number",
width:"8%", width: "8%",
render:(item,value,key)=>{ render: ( value, item, key) => {
return( return <span>#{value}</span>;
<span>#{key+1}</span> },
)
}
}, },
{ {
title:'状态', title: "状态",
dataIndex:"status", dataIndex: "status",
key:"status", key: "status",
width:"12%", width: "12%",
render:(value,item,key)=>{ render: (value, item, key) => {
return(renderTableStatus(value)) return renderTableStatus(value);
} },
}, },
{ {
title:'构建人', title: "构建人",
dataIndex:"author", dataIndex: "author",
key:"author", key: "author",
width:"12%", width: "12%",
align:"center" align: "center",
}, },
{ {
title:'提交信息', title: "提交信息",
dataIndex:"message", dataIndex: "message",
key:"message", key: "message",
width:"30%", width: "30%",
render:(value,item,key)=>{ render: (value, item, key) => {
let meg = item.message; let meg = item.message;
return ( return (
<React.Fragment> <React.Fragment>
<div> <div>
{ meg.branch && <span className="mr10 color-grey-8"><i className="iconfont icon-fenzhi1 font-16 mr5"></i>分支{meg.branch}</span>} {meg.branch && (
{ meg.sha && <span className="color-orange">{meg.sha}</span>} <span className="mr10 color-grey-8">
<i className="iconfont icon-fenzhi1 font-16 mr5"></i>分支
{meg.branch}
</span>
)}
{meg.sha && <span className="color-orange">{meg.sha}</span>}
</div> </div>
<AlignCenter> <AlignCenter>
<Img src={meg.image} /> <img style={{borderRadius:"50%",marginRight:"10px",width:"25px",height:"25px"}} alt="" src={`${item.image_url && getUrl(`/images/${item.image_url}`)}`} />
<div className="task-hide ml5" style={{maxWidth:"300px"}}>{meg.message}</div> <div className="task-hide ml5" style={{ maxWidth: "300px" }}>
{meg.message}
</div>
</AlignCenter> </AlignCenter>
</React.Fragment> </React.Fragment>
) );
} },
}, },
{ {
title:'开始时间', title: "开始时间",
dataIndex:"started", dataIndex: "started",
key:"started", key: "started",
width:"15%", width: "15%",
render:(value,item,key)=>{ render: (value, item, key) => {
return ( return <span>{value || "--"}</span>;
<span>{value || "--"}</span> },
)
}
}, },
{ {
title:'运行时间', title: "运行时间",
dataIndex:"timestamp", dataIndex: "duration_time",
key:"timestamp", key: "duration_time",
width:"15%", width: "15%",
render:(value,item,key)=>{ render: (value, item, key) => {
return ( return <span>{value || "--"}</span>;
<span>{value || value === 0 ? `${value}s` : "--"}</span> },
)
}
}, },
{ {
title:'操作', title: "操作",
dataIndex:"operation", dataIndex: "operation",
key:"operation", key: "operation",
render:(value,item,key)=>{ render: (value, item, key) => {
return(renderStatusBtn(item.status)); if(permission === "Admin" || permission === "Owner"){
} return renderStatusBtn(item.status, item.number);
} }else{
] return "--";
return( }
<div className="listPart"> },
<FlexAJ> },
{renderStatus()} ];
<span> return (
<Blueback className="mr30">手动创建</Blueback> <div className="disposePanel">
<span className="mr30"><i className="iconfont icon-fenzhi1 font-16 mr5 color-blue"></i>分支</span> <Banner>
<span><i className="iconfont icon-biaoqian3 font-16 mr5 color-blue"></i>标签</span> <FlexAJ>
</span> <span>构建列表</span>
</FlexAJ> <Link to={`/projects/${owner}/${projectsId}/devops/dispose`} className="font-15 color-grey-9">返回</Link>
<Table </FlexAJ>
columns={column} </Banner>
className="normalTable" <Div>
dataSource={data} <div className="listPart">
pagination={false} <FlexAJ>
></Table> {renderStatus()}
{ <a onClick={()=>Init(status)} className="color-red font-16">刷新</a>
total > LIMIT ? </FlexAJ>
<div style={{textAlign:'center',margin:"30px 50px"}}> <Table
<Pagination showQuickJumper defaultCurrent={page} total={total} pageSize={LIMIT} onChange={ChangePage}></Pagination> onRow={(record,index)=>{
</div>:"" return{
} onClick:(event)=>clickRows(event,record)
}
}}
columns={column}
className="normalTable"
dataSource={data}
pagination={false}
loading={tableLoading}
></Table>
{total > LIMIT ?
<div style={{ textAlign: "center", margin: "30px 50px" }}>
<Pagination
showQuickJumper
defaultCurrent={page}
total={total}
pageSize={LIMIT}
onChange={ChangePage}
></Pagination>
</div>
:
"" }
</div>
</Div>
</div> </div>
) );
}) };
export default forwardRef(Structure);

View File

@ -0,0 +1,317 @@
import React , { useEffect , useState } from 'react';
import { WhiteBack } from '../Component/layout';
import { Spin } from 'antd';
import Head from './Dispose/head';
import Menus from './Dispose/menus';
import Init from './Dispose/Init';
import Sure from './Dispose/Sure';
import Stage from './Dispose/Stage';
import axios from 'axios';
function disposePipeline(props){
const [ spining , setSpining ] = useState(true);
const [ stage , setStage ] = useState(1);
const [ pipeLineName , setPipeLineName ] = useState(undefined);
const [ stepName , setStepName ] = useState(undefined);
const [ stageId , setStageId ] =useState(undefined);
const [ menuList , setMenuList ] = useState(undefined);
const [ stageType , setStageType ] = useState("init");
const [ datas , setDatas ] = useState(undefined);
const [ templates , setTemplates] = useState(undefined);
const [ datasUpdataFlag , setDatasUpdataFlag ] = useState(false);
const [ loading ,setLoading ] = useState(false);
const { disposeId } = props.match.params;
let projectsId = props.match.params.projectsId;
let owner = props.match.params.owner;
useEffect(()=>{
if(stageType && stageType !=="confirm"){
InitTemplates();
}
},[stageType])
//
function InitTemplates(){
const url = `/ci/templates/templates_by_stage.json`;
axios.get(url,{
params:{ stage_type:stageType, id:disposeId }
}).then(result=>{
if(result && result.data){
setTemplates(result.data);
}
}).catch(error=>{})
}
useEffect(()=>{
if(disposeId && (stageType && stageType !=="confirm")){
getData(0);
}
},[disposeId])
//
function getData(index){
const url = `/ci/pipelines/${disposeId}/stages.json`;
axios.get(url).then(result=>{
if(result && result.data){
setMenuList(result.data.stages);
if(index || index === 0){
let first = result.data.stages[index];
setStage(first.show_index);
setStageId(first.id);
setPipeLineName(`${first.pipeline_name}`);
}
}
})
}
useEffect(()=>{
if(stageId){
getStageStep(stageId);
}
},[stageId])
//
function getStageStep(stageId){
let url = "";
if(stageType && stageType === "confirm"){
url = `/ci/pipelines/${disposeId}/content.json`;
axios.get(url,{
params:{
owner,repo:projectsId
}
}).then(result=>{
if(result && result.data){
setDatas(result.data);
}
}).catch(error=>{})
}else{
url = `/ci/pipelines/${disposeId}/${stageId}/steps.json`;
axios.get(url).then(result=>{
if(result && result.data){
let step = result.data.steps;
setDatas(step);
let flag = !step || (step && step.length === 0);
setDatasUpdataFlag(flag);
}
}).catch(error=>{})
}
setSpining(false);
}
// sshow_index,stage_type:stage_type
function changestage(show_index,stage_type,stage_id,stage_name){
if(show_index !== stage){
saveFunc(show_index,stage_type,stage_id,stage_name);
}
}
//
function saveDatas(steps){
setDatas([...steps]);
setDatasUpdataFlag(true);
}
//
function checkDatas(){
if(datas && datas.length > 0){
for(let i= 0;i< datas.length;i++){
if(datas[i] && (!datas[i].content || !datas[i].template_id)){
props.showNotification("请先选择模板!");
return false;
}
}
}else{
if(stageType === "init" ){
props.showNotification("请先选择模板!");
return false;
}else if(stageType === "confirm" ){
return true;
}else{
return "";
}
}
return true;
}
//
function saveFunc(show_index,stage_type,stage_id,stageName,btn){
setSpining(true);
//
if(datasUpdataFlag && stageType !== "confirm"){
// undefined --datas
let f = checkDatas();
if(f && (datas && datas.length !== 0)){
//
saveDataFunc(btn,show_index,stage_type,stage_id,stageName);
}
else{
setSpining(false);
f === "" && elseFunc(btn,show_index,stage_type,stage_id,stageName);
}
}else{
elseFunc(btn,show_index,stage_type,stage_id,stageName);
}
}
function saveDataFunc(btn,show_index,stage_type,stage_id,stageName){
const url = `/ci/pipelines/${disposeId}/${stageId}/stage_step.json`;
axios.post(url,{
steps:datas
}).then(result=>{
if(result && result.data){
setDatasUpdataFlag(false);
if(!btn){
setStage(show_index);
setStageType(stage_type);
setStageId(stage_id);
setStepName(pipeLineName+`-`+stageName);
}else{
enters(btn);
}
}else{
props.showNotification("阶段更新失败,请稍微重试!");
}
}).catch(error=>{})
}
function elseFunc(btn,show_index,stage_type,stage_id,stageName){
if(btn){
enters(btn);
}else{
setStage(show_index);
setStageType(stage_type);
setStageId(stage_id);
setStepName(pipeLineName+`-`+stageName);
}
}
//
function enters(btn){
let s = stage;
if(btn === "next"){
//
s = s+1;
}else{
//
s = s-1;
}
let item = menuList && menuList.filter(i=>i.show_index === (s));
setStage(s);
setStageType(item[0].stage_type);
setStageId(item[0].id);
setStepName(pipeLineName+`-`+item[0].stage_name);
}
//
function deleteStep(id,index){
if(id){
const url = `/ci/pipelines/${disposeId}/${stageId}/${id}/delete_step.json`;
axios.delete(url).then(result=>{
if(result && result.data){
getStageStep(stageId);
props.showNotification("阶段步骤删除成功!");
}
}).catch(error=>{})
}else{
let d = datas.filter(s=>s.show_index !== (index+1));
setDatas(d);
}
}
function renameFunc(value,id){
const url = `/ci/pipelines/${disposeId}/${id}/update_stage.json`;
axios.put(url,{
stage_name:value
}).then(result=>{
if(result && result.data){
getData();
}
}).catch(error=>{})
}
//
function addMenuFunc(name,index){
const url = `/ci/pipelines/${disposeId}/create_stage.json`;
axios.post(url,{
show_index:index,
stage_name:name
}).then(result=>{
if(result && result.data){
getData(index-1);
setStageType("customize");
}else{
props.showNotification("阶段新增失败!");
}
})
}
//
function deleteStageFunc(){
let next = menuList && menuList.filter(item=>item.show_index === (stage+1));
let nextStageType = next && next.length>0 && next[0].stage_type;
const url = `/ci/pipelines/${disposeId}/${stageId}/delete_stage.json`;
axios.delete(url,{
params:{show_index:stage}
}).then(result=>{
if(result && result.data){
getData(stage-1);
setStageType(nextStageType);
}else{
props.showNotification("阶段删除失败!");
}
}).catch(error=>{})
}
//
function sureSubmit(){
setLoading(true);
let params = {
branch: datas.branch,
content:datas.content,
filepath:'.trustie-pipeline.yml',
message:'',
sha:datas.sha || undefined,
owner:owner,
repo:projectsId
}
let url = `/${owner}/${projectsId}/update_trustie_pipeline.json`;
axios.put(url,{
...params
}).then(result=>{
if(result){
props.history.push(`/projects/${owner}/${projectsId}/devops/dispose`);
}
setLoading(false);
}).catch(error=>{
console.log(error);
setLoading(false);
})
}
return(
<div className="disposePanel">
<Head />
<WhiteBack style={{padding:"24px 30px"}}>
<Spin spinning={spining}>
<div style={{minHeight:"450px"}}>
<Menus step={stage} checkDatas={checkDatas} changeStep={changestage} menuList={menuList} renameFunc={renameFunc} addFunc={addMenuFunc}/>
{
stageType === "init" ? <Init stage_type={stageType} templates={templates} datas={datas} saveDatas={saveDatas} saveFunc={saveFunc}/>
:
stageType === "confirm" ? <Sure sureSubmit={sureSubmit} name={pipeLineName} datas={datas} saveFunc={saveFunc} loading={loading}/>
:
<Stage {...props}
stepName={stepName}
deleteStep={deleteStep}
stage_type={stageType}
templates={templates}
datas={datas}
deleteFunc={deleteStageFunc}
saveDatas={saveDatas}
saveFunc={saveFunc}
deleteFlag={menuList && menuList.length === 3}
/>
}
</div>
</Spin>
</WhiteBack>
</div>
)
}
export default disposePipeline;

View File

@ -10,10 +10,17 @@
padding:60px 0px; padding:60px 0px;
} }
.disposePanel{ .disposePanel{
border:1px solid #eee;
.language{ .language{
display: flex; display: flex;
margin-bottom: 20px;
li{ li{
margin-right: 20px; margin-right: 20px;
cursor: pointer;
border:1px solid #fff;
&.active{
border:1px solid #5091FF;
}
} }
} }
.editorBody{ .editorBody{
@ -36,6 +43,7 @@
top:7px; top:7px;
} }
.listPart{ .listPart{
min-height: 400px;
.listNav{ .listNav{
display: flex; display: flex;
li{ li{
@ -63,6 +71,7 @@
.ant-table-thead > tr > th, .ant-table-tbody > tr > td{ .ant-table-thead > tr > th, .ant-table-tbody > tr > td{
padding:10px 5px; padding:10px 5px;
color:#333; color:#333;
cursor: pointer;
} }
.ant-table-thead{ .ant-table-thead{
border:1px solid rgba(238,238,238,1) border:1px solid rgba(238,238,238,1)
@ -70,43 +79,10 @@
} }
} }
} }
// 列表 .ant-modal-close{
.listPart{ top:7px;
.statusTag{
display: flex;
padding:0px 16px;
height: 32px;
line-height: 32px;
border-radius:20px;
float: left;
i{
font-size: 20px!important;
margin-right: 7px;
}
&.running{
background:#F1F8FF;
border:1px solid #5091FF;
color: #5091FF;
}
&.Preparing{
background:rgba(255,248,244,1);
border:1px solid rgba(255,110,33,1);
color:rgba(255,110,33,1) ;
}
&.pass{
background:#EEFDF5;
border:1px solid #28BD6C;
color:#28BD6C ;
}
&.failed{
background:#FCEEEE;
border:1px solid #F73030;
color:#F73030 ;
}
}
} }
} }
// ops详情 // ops详情
.opsDetailPanel{ .opsDetailPanel{
@ -205,13 +181,35 @@
border:1px solid rgba(255,110,33,1); border:1px solid rgba(255,110,33,1);
color:rgba(255,110,33,1); color:rgba(255,110,33,1);
} }
&.killed{
border:1px solid #999;
color:#999;
}
&.skipped{
border:1px solid #d4d9de;
color:#798390;
}
} }
} }
&.rightSection{ &.rightSection{
width:100%; width:100%;
background-color: #081930; background-color: #081930;
.devopsNav{
background-color: #111c24;
border-bottom: none;
.ant-menu-item{
color: #ccc;
padding:0px;
margin:0px 20px!important;
}
.ant-menu-item.ant-menu-item-selected{
color: #1890ff;
}
}
.rightMainContent{ .rightMainContent{
padding:24px 30px; padding:24px 30px;
height:100vh;
overflow-y: auto;
& > div{ & > div{
margin-bottom: 12px; margin-bottom: 12px;
.items{ .items{
@ -264,4 +262,260 @@
cursor: col-resize; cursor: col-resize;
} }
} }
}
.opsDetailOut{
display: flex;
color: #fff;
line-height: 22px;
align-items: flex-start;
margin-top: 5px;
&>span{
margin-right: 10px;
min-width: 20px;
text-align: left;
padding-left: 3px;
}
&>p{
margin-bottom: 0px;
}
}
.noOperation{
margin-bottom:20px;
width:380px;
text-align:center;
line-height:22px;
color:#666;
}
.disposeList{
min-height: 450px;
.ant-table-body{
margin:0px!important;
.ant-table-thead{
background-color: #fafafa;
}
}
}
.txtright{
text-align: right;
}
.menus{
display: flex;
box-shadow: 0px 0px 6px rgba(0,3,8,0.1);
padding:20px 0px 10px 0px;
justify-content: space-between;
margin-bottom: 20px;
& > li{
display: flex;
flex-flow: column;
align-items:center;
justify-content: flex-start;
text-align: center;
color: #787878;
font-size: 16px;
position: relative;
cursor: pointer;
max-width: 122px;
flex:2;
&>i{
font-size: 30px!important;
height: 30px;
width: 30px;
line-height: 30px;
}
&:hover,&.active{
& > i{
color: #1890FF;
}
}
&.active::after{
position: absolute;
left: 50%;
margin-left: -25px;
bottom:-10px;
width: 50px;
height: 2px;
background-color: #1890FF;
content: "";
}
.aboutEdit{
width: 100%;
.operateName{
position: relative;
line-height: 22px;
display: flex;
align-items: center;
justify-content: center;
padding: 0px 15px;
min-height: 40px;
& > i{
position: absolute;
right:0px;
top:10px;
display: none;
}
}
&:hover i{
display: block;
}
}
}
& > li.menuAdd{
position: relative;
flex: 1;
&:hover{
& > i{
color: #787878;
}
}
& > i{
font-size: 18px!important;
position: absolute;
z-index: 1;
top:0px;
}
& > input{
position: absolute;
z-index: 1;
top:3px;
}
&::before{
position: absolute;
left: 0;
width: 100%;
border-bottom: 1px dashed #eee;
content: "";
top:15px;
margin-top: -1px;
z-index: 0;
}
}
}
.choosenList{
display: flex;
flex-wrap: wrap;
line-height: 35px;
align-items: center;
& > span{
display: block;
min-width: 75px;
text-align: right;
font-size: 14px;
color: #333;
height: 35px;
margin-right: 12px;
}
& > ul{
display: flex;
flex-wrap: wrap;
li{
padding:0px 12px;
height: 35px;
line-height: 35px;
border:1px solid #e1e4e8;
background-color: #fff;
margin:6px 0px;
margin-right: 12px;
border-radius: 5px;
cursor: pointer;
color: #333;
}
li.active{
color: #fff;
background-color: #1890FF;
}
}
.ant-select-selection.ant-select-selection--multiple{
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
height: 35px;
}
}
.addStageBtn{
display: block;
width: 100%;
border:1px solid #e1e4e8;
height: 48px;
line-height: 48px;
color: #1890FF;
font-size: 16px;
border-radius: 3px;
padding: 0px 20px;
}
.stepsItem{
border:1px solid #e1e4e8;
border-radius: 4px;
margin-bottom: 15px;
.stepsHead{
padding:8px 15px;
span > a > i{
margin-left: 8px;
color: #666!important;
}
}
.stepsBody{
padding:10px 15px;
border-top: 1px solid #e1e4e8;
background-color: rgb(251, 251, 251);
display: none;
transition: 0.3s;
}
.stepsBody.active{
display: block;
}
}
.editorPanel{
border:1px solid #eee;
.margin{
width: 0px;
}
.monaco-scrollable-element.editor-scrollable{
left: 0px!important;
width: 100%!important;
.view-lines{
width: 336px!important;
}
}
}
.hide{
display: none!important;
}
.statusTag{
display: flex;
padding:0px 16px;
height: 32px;
line-height: 32px;
border-radius:20px;
float: left;
i{
font-size: 20px!important;
margin-right: 7px;
}
&.running{
background:#F1F8FF;
border:1px solid #5091FF;
color: #5091FF;
}
&.Preparing{
background:rgba(255,248,244,1);
border:1px solid rgba(255,110,33,1);
color:rgba(255,110,33,1) ;
}
&.pass{
background:#EEFDF5;
border:1px solid #28BD6C;
color:#28BD6C ;
}
&.failed{
background:#FCEEEE;
border:1px solid #F73030;
color:#F73030 ;
}
&.killed{
background:#eee;
border:1px solid #999;
color:#999 ;
}
} }

View File

@ -1,33 +1,114 @@
import React from 'react'; import React, { useEffect, useState, useRef, useContext } from "react";
import './ops.scss'; import "./ops.scss";
import { FlexAJ, AlignCenter } from '../Component/layout'; import { FlexAJ, AlignCenter } from "../Component/layout";
import { Tags } from '../Component/OpsStatus'; import { Tags } from "../Component/OpsStatus";
import SplitPane from 'react-split-pane'; import SplitPane from "react-split-pane";
import LeftPanel from './OpsDetailLeftpanel'; import LeftPanel from "./OpsDetailLeftpanel";
import RightPanel from './OpsDetailRightpanel'; import RightPanel from "./OpsDetailRightpanel";
import axios from "axios";
import { Spin } from "antd";
import { Link } from "react-router-dom";
export default (props) => {
const [data, setData] = useState(undefined);
const [stageN, setStageN] = useState(undefined);
const [stepN, setStepN] = useState(undefined);
const [rightSpin, setRightSpin] = useState(false);
const [spinning, setSpinning] = useState(true);
export default (()=>{ let projectId = props.match.params.projectId;
return( let owner = props.match.params.owner;
<div className="opsDetailPanel"> let opsId = props.match.params.opsId;
<FlexAJ className="opsInfos">
<AlignCenter> useEffect(() => {
<span>#1</span> if (opsId && projectId) {
<span className="ml10">将分支221063-improve-buy-ci-minutes-link合并到221063-improve-buy-ci-minutes-link"</span> Init();
{Tags(1)} }
</AlignCenter> }, [opsId]);
<a style={{color:"#ddd"}}><i className="iconfont icon-yiguanbi font-15 mr5"></i>退出</a>
</FlexAJ> function Init() {
<div className="opsSection"> const url = `/${owner}/${projectId}/builds/${opsId}.json`;
<SplitPane className="outer-split-pane" split="vertical" minSize={468} maxSize={-350} defaultSize="40%"> axios.get(url).then((result) => {
<section className="leftSection"> if (result && result.data) {
<LeftPanel /> setSpinning(false);
</section> setData(result.data);
<section className="rightSection"> }
<RightPanel /> })
</section> .catch((error) => {
</SplitPane> console.log(error);
setSpinning(false);
});
}
//
function repeatSet(e,type,number) {
if(type==="repeat"){
//
const url = `/${owner}/${projectId}/builds/${number}/restart.json`;
axios.post(url).then((result) => {
if (result && result.data) {
props.showNotification("工作流正在重新构建!");
props.history.push(`/projects/${owner}/${projectId}/devops/${result.data.number}/detail`);
}
})
.catch((error) => {
console.log(error);
});
}else{
//
const url = `/${owner}/${projectId}/builds/${number}/stop.json`;
axios.delete(url).then((result) => {
if (result) {
props.showNotification("撤销构建成功!");
Init();
}
})
.catch((error) => {
console.log(error);
});
}
}
function chooseSteps(pre,sub){
if(pre && sub){
setStepN(sub);
setStageN(pre);
setRightSpin(true);
}
}
return (
<Spin spinning={spinning}>
<div className="opsDetailPanel">
<FlexAJ className="opsInfos">
<AlignCenter>
<span>#{data && data.number}</span>
<span className="ml10">{data && data.message}</span>
{Tags(`${data && data.status}`)}
</AlignCenter>
<Link
style={{ color: "#ddd" }}
to={`/projects/${owner}/${projectId}/devops/dispose`}
>
<i className="iconfont icon-yiguanbi font-15 mr5"></i>退出
</Link>
</FlexAJ>
<div className="opsSection">
<SplitPane
className="outer-split-pane"
split="vertical"
minSize={468}
maxSize={-350}
defaultSize="40%"
>
<section className="leftSection">
<LeftPanel data={data} repeatSet={repeatSet} chooseSteps={chooseSteps} />
</section>
<section className="rightSection">
<RightPanel data={data} rightSpin={rightSpin} stepN={stepN} stageN={stageN} owner={owner} projectId={projectId} opsId={opsId} />
</section>
</SplitPane>
</div>
</div> </div>
</div> </Spin>
) );
}); };

View File

@ -0,0 +1,42 @@
import React, { useState, useEffect } from "react";
import XmlPanel from "./XmlPanel";
import mediator from "./mediator";
import axios from "axios";
// const defaulturl = `http://47.111.130.18:48088`;
const defaultValue = {
host: "106.75.231.63",
port: "2021",
ws_url: "wss://pre-webssh.educoder.net/ws",
username: "root",
secret: "Dron_123123",
};
function Index() {
const [sshConfigData, setSshConfigData] = useState(undefined);
useEffect(() => {
if (!sshConfigData) {
init();
}
setTimeout(() => {
mediator.publish("create-socket", 1);
}, 300);
}, [sshConfigData]);
//
function init() {
const url = `/api/ci/pipelines/ssh_server.json`;
axios.get(url).then(result=>{
if(result && result.data){
setSshConfigData({...result.data})
}
}).catch(error=>{})
}
return (
<XmlPanel
sshConfigData={sshConfigData||{}}
sid={1}
/>
);
}
export default Index;

View File

@ -0,0 +1,219 @@
import React, { useRef, useEffect, useState } from 'react';
import { Base64 } from 'js-base64';
import { Terminal } from 'xterm';
import 'xterm/css/xterm.css';
import mediator from './mediator';
import ResizeObserver from 'resize-observer-polyfill';
function getColsAndRows(width, height, term) {
let w = term._core._renderService.dimensions.actualCellWidth || 9.5;
let h = term._core._renderService.dimensions.actualCellHeight || 18;
const rows = Math.floor(height / h);
const cols = Math.floor(width / w);
return [cols, rows];
}
function onLayout(term, el) {
const ro = new ResizeObserver(entries => {
console.log(entries);
for (let entry of entries) {
if (entry.target.offsetHeight > 0 || entry.target.offsetWidth > 0) {
const [cols, rows] = getColsAndRows(
entry.target.offsetWidth,
entry.target.offsetHeight,
term,
);
console.log('cols, rows', cols, rows);
term.resize(cols, rows);
mediator.publish('ssh-xterm-resize', {
columns: cols,
rows: rows,
width: entry.target.offsetWidth,
height: entry.target.offsetHeight,
});
}
}
});
ro.observe(el);
return ro;
}
const TimeTicket = 30000;
// websockt
//
//socket term socket
//mediator id
export default ({ sshConfigData, sid }) => {
const [term, setTerm] = useState(null);
const { ws_url, password, port, secret } = sshConfigData;
const el = useRef();
const socket = useRef();
const isFirstConnected = useRef(false);
//term init
useEffect(() => {
if (el.current && ws_url) {
const term = new Terminal({ fontSize: 16, rendererType: 'dom' });
term.open(el.current);
term.onData(data => {
if (socket.current) {
if (socket.current.readyState === 1) {
socket.current.send(JSON.stringify({ tp: 'client', data: data }));
mediator.publish('on-operating-ssh'); //
} else {
//
// socket.current = null
// mediator.publish('create-socket', sid)
}
}
});
term.write('Connecting...');
setTerm(term);
const ro = onLayout(term, el.current);
return () => {
term.dispose();
ro.unobserve(el.current);
};
}
}, [ws_url, el.current]);
useEffect(() => {
if (term && ws_url) {
function createSocket() {
const socketInstance = new WebSocket(ws_url);
socket.current = socketInstance;
socketInstance.onopen = () => {
let container = term.element.parentElement;
if (container) {
let width = container.offsetWidth;
let height = container.offsetHeight;
console.log('init', {
tp: 'init',
data: {
...sshConfigData,
secret: secret,
width,
height,
rows: term.rows,
columns: term.cols,
},
});
socketInstance.send(
JSON.stringify({
tp: 'init',
data: {
...sshConfigData,
secret: secret,
width,
height,
rows: term.rows,
columns: term.cols,
},
}),
);
}
term.focus();
};
socketInstance.onerror = error => {
console.log(
'------in socket error----',
error,
socketInstance,
ws_url,
);
//
// mediator.publish('on-recreate-socket')
};
socketInstance.onmessage = event => {
if (!isFirstConnected.current) {
term.write('\r');
// term.focus()
setTimeout(() => {
// term.clear();
}, 1000);
}
isFirstConnected.current = true;
console.log('event:', event);
const data = Base64.decode(event.data.toString());
let w = term._core._renderService.dimensions.actualCellWidth || 9.5;
console.log('data:', data, w, term);
term.write(data);
};
socketInstance.onclose = evt => {
if (tid) {
clearInterval(tid);
}
term.write('\r\nconnection closed');
};
}
const tid = setInterval(() => {
if (socket.current) {
socket.current.send(JSON.stringify({ tp: 'h' }));
}
}, TimeTicket);
const unSubCreate = mediator.subscribe('create-socket', id => {
if (sid === id) {
if (socket.current && socket.current.readyState === 1) {
term.focus();
} else {
createSocket();
}
term.focus();
}
});
const unSubClose = mediator.subscribe('close-socket', id => {
if (sid === id) {
if (socket.current) {
socket.current.close();
isFirstConnected.current = false;
term.clear();
}
socket.current = null;
}
});
const unSubResize = mediator.subscribe('ssh-xterm-resize', option => {
if (socket.current && socket.current.readyState === 1) {
socket.current.send(
JSON.stringify({ tp: 'resize', data: { ...option } }),
);
}
});
const unSubAddTime = mediator.subscribe('ssh-add-connect-time', () => {
if (socket.current && socket.current.readyState === 1) {
socket.current.send(JSON.stringify({ tp: 'overtime' }));
}
});
return () => {
unSubClose();
unSubCreate();
unSubResize();
unSubAddTime();
if (socket.current) {
socket.current.close();
isFirstConnected.current = false;
}
};
}
}, [term, ws_url, port]);
return (
<div ref={el} className="xterm-panel" style={{height:"100%"}}>
{!ws_url ? <p style={{ color: '#fff' }}>正在连接命令行服务...</p> : null}
</div>
);
};

View File

@ -0,0 +1,46 @@
function Mediator(obj) {
const channels = {};
const mediator = {
subscribe: function(channel, cb) {
if (!channels[channel]) {
channels[channel] = [];
}
channels[channel].push(cb);
return this.unsubscribe.bind(null, channel, cb);
},
unsubscribe: function(channel, cb) {
let rs = channels[channel];
let index = -1;
if (rs) {
for (let i = 0; i < rs.length; i++) {
if (rs[i].name === cb.name) {
index = i;
break;
}
}
if (index >= 0) {
channels[channel].splice(index, 1);
return true;
}
}
return false;
},
publish: function(channel) {
if (!channels[channel]) {
return false;
}
const args = Array.prototype.slice.call(arguments, 1);
channels[channel].forEach(subscription => {
subscription.apply(null, args);
});
return this;
},
};
return obj ? Object.assign(obj, mediator) : mediator;
}
const mediator = new Mediator();
export default mediator;

View File

@ -0,0 +1,174 @@
import React ,{ forwardRef, useEffect, useState } from 'react';
import { Modal , Form , Input , Radio , Select } from 'antd';
import SearchUser from '../Component/SearchUser';
import './Index.scss';
import Axios from 'axios';
const { Option } = Select;
function DivertModal({form , visible , onSuccess , onCancel,owner,repo}){
const { getFieldDecorator, validateFields , setFieldsValue } = form;
const [ cate , setCate ] = useState(0);
const [ value , setValue ] = useState(undefined);
const [ organizations , setOrganizations ] = useState(undefined);
useEffect(()=>{
setFieldsValue({goal:cate})
},[])
useEffect(()=>{
if(owner && repo && visible===true){
getTeam();
}
if(!visible){
setFieldsValue({
owner_name:undefined,
identifier:undefined
})
setValue(undefined)
}
},[repo,owner,visible])
function getTeam(){
const url = `/${owner}/${repo}/applied_transfer_projects/organizations.json`;
Axios.get(url).then(result=>{
if(result){
setOrganizations(result.data.organizations);
}
}).catch(error=>{})
}
//
function onOk(){
validateFields((error,values)=>{
console.log(...values);
if(!error){
const url = `/${owner}/${repo}/applied_transfer_projects.json`;
Axios.post(url,{
...values
}).then(result=>{
if(result){
onSuccess(result.data && result.data.owner);
}
}).catch(error=>{})
}
})
}
function changeType(e){
setCate(e.target.value);
setFieldsValue({
owner_name:undefined
})
}
function checkIdentifier(rule, value, callback){
if(!value){
callback();
}
if (repo && value !== repo) {
callback("请输入当前项目的标识!");
}
callback();
}
const layout = {
labelCol: { span: 5 },
wrapperCol: { span: 18 },
};
function getUser(id){
setValue(id);
setFieldsValue({
owner_name:id
})
}
return(
<Modal
width="620px"
visible={visible}
title="转移仓库"
onCancel={onCancel}
onOk={onOk}
okText="确认转移"
cancelText={"取消"}
centered
>
<div className="diverModal">
{
cate === 0 ?
<ul className="descUl">
<li>转移需对方确认接受转移成功后你将被移出仓库其他已有成员权限不变</li>
<li>转移成功后仓库的地址将变更至目标用户的命名空间下</li>
<li>已有成员如需继续操作仓库需更新本地仓库的remote使之指向新的地址</li>
</ul>
:
<ul className="descUl">
<li>仓库仅可以转移到您已经加入的组织中不可以转移到未加入的组织中</li>
<li>涉及到仓库改名操作请提前做好仓库备份并且在转移后对本地仓库的remote进行修改</li>
<li>转移仓库到组织后你和组织创建者/管理员同时拥有对该仓库的管理操作</li>
</ul>
}
<Form {...layout} colon={false} layout={"horizontal"}>
<Form.Item label="转移给:" style={{marginBottom:"0px"}}>
{getFieldDecorator("goal",{
rules:[]
})(
<Radio.Group onChange={changeType}>
<Radio value={0}>个人</Radio>
<Radio value={1}>组织</Radio>
</Radio.Group>
)}
</Form.Item>
{
cate === 0 &&
<Form.Item label=" ">
{getFieldDecorator("owner_name",{
rules:[{required:true,message:"请输入目标用户名"}]
})(
// <Input placeholder="" autoComplete={"off"}/>
<SearchUser getUser={getUser} width={"100%"} placeholder="请输入目标用户" value={value}/>
)}
</Form.Item>
}
{
cate === 1 &&
<Form.Item label=" ">
{getFieldDecorator("owner_name",
{rules:[{required:true,message:"请选择目标组织"}]}
)(
<Select placeholder="请选择目标组织" getPopupContainer={trigger => trigger.parentNode}>
{
organizations && organizations.length > 0 ?
organizations.map((i,k)=>{
return(
<Option value={i.name}>{i.nickname}</Option>
)
})
:""
}
</Select>
)}
</Form.Item>
}
<Form.Item label="仓库名称:">
{getFieldDecorator("identifier",
{
rules:[
{required:true,message:"请输入仓库名称"},
{
validator:checkIdentifier
}
]
}
)(
<Input placeholder="请输入仓库名称" autoComplete={"off"}/>
)}
</Form.Item>
</Form>
</div>
</Modal>
)
}
export default Form.create()(forwardRef(DivertModal));

View File

@ -0,0 +1,12 @@
.diverModal{
.descUl{
background-color: #fffae6;
border-radius: 4px;
padding:10px 15px;
color: #efc16b;
border:1px solid #efc16b;
}
.ant-form-item-required::before{
content: "";
}
}

View File

@ -10,4 +10,12 @@ export const getTag = async (id,owner)=>{
// hooks-web // hooks-web
export const getHooks = async (id,params)=>{ export const getHooks = async (id,params)=>{
return (await axios.get(`/projects/${id}/hooks.json`,{params})).data; return (await axios.get(`/projects/${id}/hooks.json`,{params})).data;
}
//
export const getSubEntries = async (owner,projectsId,params)=>{
return (await axios.get(`/${owner}/${projectsId}/sub_entries.json`,{params})).data;
}
//
export const getUser = async (login)=>{
return (await axios.get(`/users/${login}/hovercard.json`)).data;
} }

66
src/forge/Head/Footer.jsx Normal file
View File

@ -0,0 +1,66 @@
import React, { useEffect , useState } from 'react';
import './header.scss';
function Footer(){
const [ value , setValue ] = useState(undefined);
useEffect(()=>{
try {
var chromesettingArray = JSON.parse(localStorage.getItem('chromesetting'));
setValue(chromesettingArray.footer);
} catch (e) {
}
},[])
function showhtml(htmlString){
var html = {__html:htmlString};
return <div dangerouslySetInnerHTML={html}></div> ;
}
return(
<div>
<div style={{height:"483px"}}></div>
<div className="newFooter edu-txt-center">
{value && showhtml(value)}
{/* <div className="footerInfos">
<ul>
<li>社区</li>
<li><a href={`/`} target="_blank">网站首页</a></li>
<li><a href={`https://www.trustie.net/agreement`} target="_blank">服务协议</a></li>
<li><a href={`https://forum.trustie.net/forums/1168/detail`} target="_blank">帮助中心</a></li>
<li><a href={`https://forum.trustie.net/`} target="_blank">问吧交流</a></li>
<li><a href={`https://www.trustie.net/cooperation`} target="_blank">合作伙伴</a></li>
</ul>
<ul>
<li>支持与服务</li>
<li><a href={`https://forgeplus.trustie.net/docs/api`} target="_blank">API文档</a></li>
<li><a href={`https://forum.trustie.net/forums/1168/detail`} target="_blank">帮助中心</a></li>
<li><a href={`https://git-scm.com`} target="_blank">Git常用命令</a></li>
<li><a href={`https://forum.trustie.net/forums/3080/detail`} target="_blank">DevOps使用文档</a></li>
<li><a href={`https://forgeplus.trustie.net/projects/jasder/forgeplus/tree/master/CHANGELOG.md`} target="_blank">日志更新</a></li>
</ul>
<ul>
<li>合作伙伴</li>
<li><a href={`http://www.sei.pku.edu.cn`} target="_blank">北京大学</a></li>
<li><a href={`http://scse.buaa.edu.cn`} target="_blank">北京航空航天大学</a></li>
<li><a href={`https://www.nju.edu.cn`} target="_blank">南京大学</a></li>
<li><a href={`https://www.xtu.edu.cn`} target="_blank">湘潭大学</a></li>
<li><a href={`http://www.iscas.ac.cn`} target="_blank">ISCAS</a></li>
<li><a href={`https://www.ucloud.cn`} target="_blank">UCloud优刻得</a></li>
<li><a href={`http://www.inforbus.com`} target="_blank">中创软件</a></li>
<li><a href={`https://www.inspur.com`} target="_blank">浪潮集团</a></li>
<li><a href={`http://www.copu.org.cn`} target="_blank">中国开源软件推进联盟</a></li>
<li><a href={`https://www.sjtu.edu.cn`} target="_blank">上海交通大学</a></li>
</ul>
<ul>
<li>合作伙伴</li>
<li><span>热线</span></li>
<li><span>QQ群1071514693</span></li>
</ul>
</div>
<p className="footerCopy">© Copyright 2007~2021 国防科技大学Trustie团队 & IntelliDE <a href="https://beian.miit.gov.cn">湘ICP备 17009477</a></p> */}
</div>
</div>
)
}
export default Footer;

728
src/forge/Head/Header.js Normal file
View File

@ -0,0 +1,728 @@
import React, { Component } from 'react';
import AccountProfile from "../../modules/user/AccountProfile";
import { getImageUrl } from 'educoder'
import axios from 'axios';
import { Modal, Input, message, notification , Dropdown , Menu } from 'antd';
import LoginDialog from '../../modules/login/LoginDialog';
import GotoQQgroup from '../../modal/GotoQQgroup'
import '../../modules/tpm/TPMIndex.css';
import logo from '../../modules/tpm/images/logo.png';
import './header.scss';
const $ = window.$
// TODO 这部分脚本从公共脚本中直接调用
const { Search } = Input;
let old_url;
window._header_componentHandler = null;
// 非trustie链接则新开页跳转
const str = ['www.trustie.net','forgeplus.trustie.net','forum.trustie.net','testforgeplus.trustie.net']
class NewHeader extends Component {
constructor(props) {
super(props)
this.state = {
Addcoursestypes: false,
tojoinitemtype: false,
tojoinclasstitle: undefined,
rolearr: ["", ""],
Checkboxteacherchecked: false,
Checkboxstudentchecked: false,
Checkboxteachingchecked: false,
Checkboxteachertype: false,
Checkboxteachingtype: false,
code_notice: false,
checked_notice: false,
RadioGroupvalue: undefined,
submitapplications: false,
isRender: false,
showSearchOpentype: false,
showTrial: false,
setevaluatinghides: false,
occupation: 0,
mydisplay: false,
headtypesonClickbool: false,
headtypess: "/",
settings: null,
goshowqqgtounp: false,
visiblemyss: false,
openSearch:false,
}
}
componentDidMount() {
// this.getAppdata();
this.geturlsdata();
window._header_componentHandler = this;
//下拉框的显示隐藏
var hoverTimeout;
var hoveredPanel;
$(".edu-menu-panel").hover(function () {
if (hoverTimeout) { // 一次只显示一个panel
if (hoveredPanel && hoveredPanel !== this) {
$(hoveredPanel).find(".edu-menu-list").hide()
}
clearTimeout(hoverTimeout);
hoverTimeout = null;
}
hoveredPanel = this;
$(this).find(".edu-menu-list").show();
}, function () {
var that = this;
// 延迟hide
hoverTimeout = setTimeout(function () {
$(that).find(".edu-menu-list").hide();
}, 800)
});
//获取游览器地址
try {
window.sessionStorage.setItem("yslgeturls", JSON.stringify(window.location.href))
} catch (e) {}
}
SearchInput = (open,item)=>{
if(open){
return(
<div
onBlur={() => {
setTimeout(() => {
this.setState({
openSearch:false
})
}, 300)
}}
>
<Search placeholder="实践课程/教学课堂/实践项目/交流问答"
className={`search-input mr20`}
onSearch={(value)=>this.onGlobalSearch(value,item)}
autoFocus={true}
/>
</div>
)
}else{
return <i className="iconfont icon-sousuo font-18 color-grey-6 ml30" onClick={() => {
this.setState({openSearch:true})
}} />
}
}
onGlobalSearch=(value,item)=>{
window.location.href=`${item}?value=` + value;
}
openNotification = (messge) => {
notification.open({
message: "提示",
description:
messge,
});
};
componentWillReceiveProps(newProps, oldProps) {
this.setState({
user: newProps.user
})
if (newProps.Headertop !== undefined) {
old_url = newProps.Headertop.old_url
}
}
getCookie = (key) => {
var arr, reg = RegExp('(^| )' + key + '=([^;]+)(;|$)');
if (arr === document.cookie.match(reg))
return decodeURIComponent(arr[2]);
else
return null;
}
delCookie = (name) => {
var exp = new Date();
exp.setTime(exp.getTime() - 1);
var cval = this.getCookie(name);
if (cval != null) {
document.cookie = name + "=" + cval + ";expires=" + exp.toGMTString();
}
}
onLogout = () => {
const url = `/accounts/logout.json`
this.delCookie("autologin_trustie")
axios.get(url, {
}).then((response) => {
if (response.data.status === 1) {
this.setState({
user: undefined
})
window.location.href = "/login"
message.success('退出成功');
}
});
}
tojoinclass = () => {
let { user } = this.state;
if (user === undefined) {
this.setState({
isRender: true
})
return
}
if (user && user.login === "") {
this.setState({
isRender: true
})
return;
}
if (user && user.profile_completed === false) {
this.setState({
AccountProfiletype: true
})
return;
}
this.setState({
Addcoursestypes: true,
})
}
tojoinitem = () => {
if (this.props.user && this.props.user.email === undefined || this.props.user && this.props.user.email === null || this.props.user && this.props.user.email === "") {
this.openNotification("请先绑定邮箱,谢谢");
return
}
let { user } = this.state;
if (user === undefined) {
this.setState({
isRender: true
})
return
}
if (user && user.login === "") {
this.setState({
isRender: true
})
return;
}
if (user && user.profile_completed === false) {
this.setState({
AccountProfiletype: true
})
return;
}
this.setState({
tojoinitemtype: true
})
}
submitstatevalue = (sum, value, data) => {
this.setState({
Addcoursestypes: false,
tojoinitemtype: false,
tojoinclasstitle: undefined,
rolearr: ["", ""],
Checkboxteacherchecked: false,
Checkboxstudentchecked: false,
Checkboxteachingchecked: false,
Checkboxteachertype: false,
Checkboxteachingtype: false,
code_notice: false,
checked_notice: false,
submitapplicationssum: sum,
submitapplications: true,
submitapplicationsvalue: value,
submitapplicationsvaluedata: data,
RadioGroupvalue: undefined
})
}
onChangeRadioGroup = (e) => {
this.setState({
RadioGroupvalue: e.target.value,
});
}
submitsubmitapplications = () => {
let {
submitapplicationssum,
submitapplicationsvaluedata
} = this.state;
this.setState({
submitapplications: false,
RadioGroupvalue: undefined
})
if (submitapplicationssum === 0) {
if (submitapplicationsvaluedata !== undefined) {
window.location.href = "/courses/" + submitapplicationsvaluedata;
}
} else if (submitapplicationssum === 1) {
if (submitapplicationsvaluedata !== undefined) {
window.location.href = "/projects/" + submitapplicationsvaluedata;
}
}
}
hidesubmitapplications = () => {
this.setState({
Addcoursestypes: false,
tojoinitemtype: false,
tojoinclasstitle: undefined,
rolearr: ["", ""],
Checkboxteacherchecked: false,
Checkboxstudentchecked: false,
Checkboxteachingchecked: false,
Checkboxteachertype: false,
Checkboxteachingtype: false,
code_notice: false,
checked_notice: false,
submitapplications: false,
RadioGroupvalue: undefined
})
}
educoderlogin = () => {
//登录账号
this.setState({
isRender: true
})
}
educoderloginysl = () => {
//退出账号
var url = `/accounts/logout.json`;
axios.get((url)).then((result) => {
if (result !== undefined) {
window.location.href = "/";
}
}).catch((error) => {
console.log(error);
})
}
hideAddcoursestypes = () => {
this.setState({
Addcoursestypes: false
})
};
HideAddcoursestypess = (i) => {
console.log("调用了");
this.setState({
Addcoursestypes: false,
mydisplay: true,
occupation: i,
})
};
ModalCancelsy = () => {
this.setState({
mydisplay: false,
})
};
hidetojoinclass = () => {
this.setState({
tojoinclasstype: false,
tojoinitemtype: false,
tojoinclasstitle: undefined,
rolearr: ["", ""],
Checkboxteacherchecked: false,
Checkboxstudentchecked: false,
Checkboxteachingchecked: false,
Checkboxteachertype: false,
Checkboxteachingtype: false,
code_notice: false,
checked_notice: false,
RadioGroupvalue: undefined
})
}
// 关闭
cancelModulationModels = () => {
this.setState({ isRenders: false })
}
setevaluatinghides = () => {
this.setState({
setevaluatinghides: true
})
}
//修改登录方法
Modifyloginvalue = () => {
this.setState({
isRender: false,
})
}
hideAccountProfile = () => {
this.setState({
AccountProfiletype: false
})
};
headtypesonClick = (url, bool) => {
this.setState({
headtypess: url,
headtypesonClickbool: bool,
})
}
//获取数据为空的时候
gettablogourlnull = () => {
this.setState({
settings: undefined
});
var link = document.createElement('link'),
oldLink = document.getElementById('dynamic-favicon');
link.id = 'dynamic-favicon';
link.rel = 'shortcut icon';
link.href = "/react/build/./favicon.ico";
if (oldLink) {
document.head.removeChild(oldLink);
}
document.head.appendChild(link);
};
//获取数据的时候
gettablogourldata = (response) => {
document.title = response.data.setting.name;
var link = document.createElement('link'),
oldLink = document.getElementById('dynamic-favicon');
link.id = 'dynamic-favicon';
link.rel = 'shortcut icon';
link.href = '/' + response.data.setting.tab_logo_url;
if (oldLink) {
document.head.removeChild(oldLink);
}
document.head.appendChild(link);
}
handleVisibleChanges = (boll) => {
this.setState({
visiblemyss: boll,
})
}
getAppdata = () => {
try {
var chromesettingArray = JSON.parse(localStorage.getItem('chromesetting'));
var chromesettingresponseArray = JSON.parse(localStorage.getItem('chromesettingresponse'));
this.setState({
settings: chromesettingArray
});
if (chromesettingArray.tab_logo_url) {
this.gettablogourldata(chromesettingresponseArray);
} else {
this.gettablogourlnull();
}
} catch (e) {
this.geturlsdata();
}
};
geturlsdata = () => {
let url = "/setting.json";
axios.get(url).then((response) => {
if (response && response.data) {
this.setState({ settings: response.data.setting });
// localStorage.setItem('chromesetting', JSON.stringify(response.data.setting));
// localStorage.setItem('chromesettingresponse', JSON.stringify(response));
try {
if (response.data.setting.tab_logo_url) {
this.gettablogourldata(response);
} else {
this.gettablogourlnull();
}
} catch (e) {
this.gettablogourlnull();
}
} else {
this.gettablogourlnull();
}
}).catch((error) => {
this.gettablogourlnull();
});
}
matchpaths = (url) => {
const { match } = this.props;
if(url){
if (match.path.indexOf(url) > -1) {
return true
}else {
return false
}
}
}
// 处理弹框
setgoshowqqgtounp = (bool) => {
this.setState({
goshowqqgtounp: bool
})
}
addMenu=(list)=>{
return(
list && list.length >0 &&
<div className="dropdownFlex">
<Menu>
{
list.map((item,key)=>{
return(
(item.name !=="加入课堂" && item.name !=="加入开发项目") && <Menu.Item><a href={item.url}>{item.name}</a></Menu.Item>
)
})
}
</Menu>
</div>
)
}
render() {
const { match} = this.props;
let current_user = this.props.user;
let { Addcoursestypes,
tojoinitemtype,
tojoinclasstitle,
code_notice,
checked_notice,
AccountProfiletype,
submitapplications,
submitapplicationsvalue,
user,
isRender,
showSearchOpentype,
headtypesonClickbool,
headtypess,
settings,
goshowqqgtounp,
openSearch,
} = this.state;
/*用户名称 用户头像url*/
let activeIndex = false;
let activeForums = false;
let activeShixuns = false;
let activePaths = false;
let coursestype = false;
let activePackages = false;
let activeMoopCases = false;
let activeCompetitions = false;
if (match.path === '/forums') {
activeForums = true;
} else if (match.path.startsWith('/shixuns')) {
activeShixuns = true;
} else if (match.path.startsWith('/paths')) {
activePaths = true;
} else if (match.path.startsWith('/courses')) {
coursestype = true;
} else if (match.path.startsWith('/crowdsourcing')) {
activePackages = true;
} else if (match.path.startsWith('/moop_cases')) {
activeMoopCases = true;
} else if (match.path.startsWith('/competitions')) {
activeCompetitions = true;
} else {
activeIndex = true;
}
let headtypes = '/';
if (settings) {
if (settings.navbar) {
if (settings.navbar.length > 0) {
if (match.path === '/') {
if (headtypesonClickbool === false) {
headtypes = undefined;
} else {
headtypes = headtypess;
}
} else {
for (var i = 0; i < settings.navbar.length; i++) {
if (match.path === settings.navbar[i].link) {
headtypes = settings.navbar[i].link;
break;
}
}
}
}
}
}
let shixuntype = false;
let pathstype = false;
let coursestypes = false;
if (this.props && this.props.mygetHelmetapi != null) {
let shixun = "/shixuns";
let paths = "/paths";
let courses = "/courses";
this.props.mygetHelmetapi.navbar.map((item, key) => {
var reg = RegExp(item.link);
if (shixun.match(reg)) {
if (item.hidden === true) {
shixuntype = true
}
}
if (paths.match(reg)) {
if (item.hidden === true) {
pathstype = true
}
}
if (courses.match(reg)) {
if (item.hidden === true) {
coursestypes = true
}
}
})
}
let search_url = settings && settings.common && settings.common.search;
let notice_url = settings && settings.common && settings.common.notice;
return (
<div className="newHeaders" id="nHeader">
<div className="headerContent">
{isRender === true ?
<LoginDialog
{...this.props}
{...this.state}
Modifyloginvalue={() => this.Modifyloginvalue()}
/> : ""}
{AccountProfiletype === true ?
<AccountProfile
hideAccountProfile={() => this.hideAccountProfile()}
{...this.props}
{...this.state}
/> : ""}
{
goshowqqgtounp === true ?
<GotoQQgroup {...this.state} {...this.props} setgoshowqqgtounp={(bool) => this.setgoshowqqgtounp(bool)}></GotoQQgroup>
:""
}
<a href={settings && settings.new_course.default_url} className={"fl mr30"} style={{minWidth:"45px"}}>
{
settings && settings.nav_logo_url ?
<img alt="可控开源社区" className="logoimg" style={{ heigth: "40px" }} src={getImageUrl(`/${settings.nav_logo_url}`)}></img>
:
<img alt="可控开源社区" className="logoimg" style={{ heigth: "40px" }} src={logo}></img>
}
</a>
<div className="head-nav pr" id={"head-navpre1"}>
{
settings && settings.navbar && settings.navbar.length > 0 ?
<ul id="header-nav">
{
settings.navbar && settings.navbar.map((item, key) => {
var new_link = item.link;
var user_login = this.props.user && this.props.user.login;
var is_hidden = item.hidden
if (new_link && (new_link.indexOf("courses") > -1 || new_link.indexOf("contests") > -1)) {
if (user_login) {
if (new_link.indexOf("courses") > -1) {
new_link = new_link.replace(/courses/g, "users/" + user_login + "/courses")
} else if (new_link.indexOf("contests") > -1) {
new_link = new_link.replace(/contests/g, "users/" + user_login + "/contests")
}
} else {
is_hidden = true
}
}
if (user_login && (new_link && new_link.indexOf("homes") > -1)) {
new_link = new_link.replace(/homes/g, "users/" + user_login + "/user_activities")
}
var waiLian = (new_link && str.filter(item=>new_link.indexOf(item)>-1) );
var wl = waiLian && waiLian.length>0;
return (
<li key={key} onClick={() => this.headtypesonClick(item.link, true)} className={`${this.matchpaths(item.link) === true ? 'pr active' : 'pr'}`} style={!is_hidden ? { display: 'flex' } : { display: 'none' }}>
<a href={new_link} target={wl ? "_self":"_blank"}>{item.name}</a>
</li>
)
})
}
</ul>
: ""
}
</div>
<div className="head-right">
{search_url ? this.SearchInput(openSearch,search_url):""}
{
current_user && (current_user.main_site || current_user.login) && (settings && settings.add && settings.add.length>0)?
<Dropdown overlay={this.addMenu(settings && settings.add)} placement="bottomRight">
<i className="iconfont icon-tianjiafangda color-grey-6 ml30"></i>
</Dropdown>:""
}
{this.props.user && this.props.user.login && notice_url ?
<div className="ml30 edu-menu-panel">
{user && user.login &&
<a href={`${notice_url}`} style={{ position: 'relative' }}>
<i className="iconfont icon-xiaoxilingdang color-grey-6"></i>
<span className="newslight" style={{ display: this.props.Headertop === undefined ? "none" : this.props.Headertop.new_message === true ? "block" : "none" }}>
</span>
</a>
}
</div>:""
}
<Modal
keyboard={false}
title="提示"
visible={submitapplications}
closable={false}
footer={null}
>
<div className="task_popup_con ml30">
<div className="mr15">
<ul>
<div className="task-popup-content">
<p className="task-popup-text-center font-16">
{submitapplicationsvalue}
</p>
</div>
<li className="clearfix mt10 edu-txt-center">
<a className="task-btn mr10"
onClick={this.hidesubmitapplications}>取消</a>
<a
className="task-btn task-btn-orange ml20"
onClick={this.submitsubmitapplications}>确定</a>
</li>
</ul>
</div>
</div>
</Modal>
</div>
{!user || (user && !user.login) ?
<span className="font-15 ml30">
<a onClick={() => this.educoderlogin()} className="mr5 color-grey-6">登录</a>
{
settings && settings.common && settings.common.register &&
<span><em className="vertical-line"></em><a className="ml5 color-grey-6" href={`${settings.common.register}`} target="_blank"></a></span>
}
</span>
:
<div className="ml30 edu-menu-panel" style={{ height: "70px", lineHeight: "70px" }}>
<a href={`/users/${this.props.current_user === undefined ? "" : this.props.current_user.login}/courses`}>
<img alt="头像" className="radius" height="34" id="nh_user_logo" name="avatar_image" src={getImageUrl(`/${user.image_url}`)} width="34">
</img>
</a>
<ul className="edu-menu-list" style={{ top: '60px', textAlign: 'center' }}>
<li className="bor-bottom-greyE" style={{cursor:"default",background:"#fff"}}>{this.props.current_user.username}</li>
{
settings && settings.personal && settings.personal.length > 0 && settings.personal.map((item,key)=>{
return(
<li key={key}><a href={item.url} target="_blank">{item.name}</a></li>
)
})
}
<li className="bor-top-greyE">
<a onClick={() => this.educoderloginysl()}>退出</a>
</li>
</ul>
</div>
}
</div>
</div>
);
}
}
export default NewHeader;

View File

@ -0,0 +1,68 @@
.dropdownFlex{
display:flex;
padding:5px;
background:#fff;
border-radius: 3px;
.ant-menu-vertical > .ant-menu-item{
border:none;
height: 35px;
line-height: 35px;
margin:0px;
}
.ant-menu-vertical{
border:none;
}
}
.newFooter {
position: absolute;
bottom: 0;
width: 100%;
background: #323232;
clear: both;
min-width: 1200px;
z-index: 8;
left: 0px;
p {
margin-top: 0;
margin-bottom:0px !important;
}
.footerInfos{
display: flex;
max-width: 1200px;
margin:0px auto;
justify-content: space-around;
padding:60px 0px;
& >ul{
padding:0px 40px;
box-sizing: border-box;
max-width: 25%;
text-align: left;
li{
color: #fff;
font-weight: 300;
&:first-child{
font-size: 17px;
}
&>a,&>span{
color: #bbb;
}
&>a:hover{
color: #4cacff;
}
}
}
}
.footerCopy{
color: #bbb;
border-top: 1px solid #4e4e4e;
padding:10px 0px;
a{
color: #bbb;
&:hover{
color: #4cacff;
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 590 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

View File

@ -6,7 +6,6 @@ import { withRouter } from "react-router";
import { SnackbarHOC } from "educoder"; import { SnackbarHOC } from "educoder";
import { CNotificationHOC } from "../modules/courses/common/CNotificationHOC"; import { CNotificationHOC } from "../modules/courses/common/CNotificationHOC";
import { TPMIndexHOC } from "../modules/tpm/TPMIndexHOC"; import { TPMIndexHOC } from "../modules/tpm/TPMIndexHOC";
import Handbook from './Component/Handbook';
import "./css/index.scss"; import "./css/index.scss";
import Loadable from "react-loadable"; import Loadable from "react-loadable";
@ -31,20 +30,29 @@ const Infos = Loadable({
loader: () => import("./users/Infos"), loader: () => import("./users/Infos"),
loading: Loading, loading: Loading,
}); });
class Index extends Component { class Index extends Component {
render() { render() {
return ( return (
<div className="newMain clearfix"> <div className="newMain clearfix">
<Handbook />
<Switch {...this.props}> <Switch {...this.props}>
<Route
path="/projects/:projectsType/new/:OIdentifier"
render={(props) => (
<ProjectNew {...this.props} {...props} />
)}
></Route>
<Route <Route
path="/projects/:projectsType/new" path="/projects/:projectsType/new"
render={(props) => ( render={(props) => (
<ProjectNew {...this.props} {...props} /> <ProjectNew {...this.props} {...props} />
)} )}
></Route> ></Route>
<Route
path="/projects/new"
render={(props) => (
<ProjectNew {...this.props} {...props} />
)}
></Route>
<Route <Route
path="/projects/:owner/:projectsId" path="/projects/:owner/:projectsId"
render={(props) => ( render={(props) => (

View File

@ -0,0 +1,449 @@
import React , { useEffect , useState } from 'react';
import { WhiteBack , Box , LongWidth , ShortWidth , Gap , AlignCenter , FlexAJ } from '../Component/layout';
import { Dropdown , Menu , Divider , Spin, Button } from 'antd';
import { getImageUrl } from "educoder";
import { Link } from 'react-router-dom';
import CloneAddress from '../Branch/CloneAddress';
import SelectBranch from '../Branch/Select';
import User from '../Component/User';
import axios from 'axios';
import Path from './CoderDepotPath';
import Catalogue from './CoderDepotCatalogue';
import ReadMe from './CoderDepotReadme';
import CoderRootFileDetail from './CoderRootFileDetail';
import './Index.scss';
import Releases from '../Component/Releases';
import Contributors from '../Component/Contributors';
import LanguagePower from '../Component/LanguagePower';
import DrawerPanel from '../Component/DrawerPanel';
import UpdateDescModal from './sub/UpdateDescModal';
import Nodata from '../Nodata';
/**
* projectDetail.type:0是托管项目1是镜像项目2是同步镜像项目(为2时不支持在线创建在线上传在线修改在线删除创建合并请求等功能)
*/
function CoderDepot(props){
const [ projectDetail , setProjectDetail ]= useState(undefined);
const [ treeValue , setTreeValue ] = useState(undefined);
const [ treeValuePath , setTreeValuePath ] = useState(undefined);
const [ lastCommit,setLastCommit ] = useState(undefined);
const [ lastCommitAuthor,setLastCommitAuthor ] = useState(undefined);
const [ type ,setType ] = useState('dir');
const [ hide , setHide ] = useState(true);
const [ hideBtn , setHideBtn ] = useState(false);
const [ commitCount ,setCommitCount ] = useState(0);
const [ dirInfo ,setDirInfo ] = useState(undefined);//
const [ fileInfo ,setFileInfo ] = useState(undefined);//
const [ zip_url , setZip_url ] = useState(undefined);
const [ tar_url , setTar_url ] = useState(undefined);
const [ readOnly , setReadOnly] = useState(true);
const [ isSpin , setIsSpin] = useState(true);
const [ visible ,setVisible ] = useState(false);
const [ mainFlag ,setMainFlag ] = useState(false);
const [ openModal , setOpenModal ] = useState(false);
const [ desc , setDesc ] = useState(undefined);
const [ website , setWebsite ] = useState(undefined);
const [ lesson_url , setLessonUrl ] = useState(undefined);
const owner = props.match.params.owner;
const projectsId = props.match.params.projectsId;
const branchName = props.match.params.branchName;
let pathname = props.history.location.pathname;
useEffect(()=>{
if(props.projectDetail){
setProjectDetail(props.projectDetail);
setDesc(props.projectDetail.description);
setWebsite(props.projectDetail.website);
setLessonUrl(props.projectDetail.lesson_url);
}
},[props])
useEffect(()=>{
if(treeValue){
setTreeValuePath(treeValue.split('/'));
}else{
setTreeValuePath(undefined);
}
},[treeValue])
useEffect(()=>{
if (pathname && projectDetail){
if(pathname.indexOf(`/projects/${owner}/${projectsId}`) > -1 && pathname.indexOf(`/tree/${branchName}/`) > -1) {
let url = pathname.split(`/tree/${branchName}/`)[1];
setTreeValue(url);
getFileInfo(url,branchName);
}else{
setTreeValue(undefined);
getDirInfo(branchName ||projectDetail.default_branch);
}
}
},[pathname,projectDetail])
//
function getDirInfo(branch){
setIsSpin(true);
const url = `/${owner}/${projectsId}/entries.json`;
axios.get(url, {
params: { ref: branch }
}).then((result) => {
if (result) {
setCommitCount(result.data.commits_count);
setDirInfo(result.data.entries);
setFileInfo(undefined);
setTar_url(result.data.tar_url);
setZip_url(result.data.zip_url);
let c = result.data.last_commit
setLastCommit(c && c.commit);
setLastCommitAuthor(c && c.committer);
setMainFlag(true);
setReadOnly(true);
}
setTimeout(function(){setIsSpin(false);},500);
}).catch(error=>{setIsSpin(false);})
}
useEffect(()=>{
if(projectDetail && lastCommit)
{
let ele = document.getElementById("ptxt");
if(ele){
let h = ele.offsetHeight;
if( h > 18 ) setHideBtn(true)
}
}
},[projectDetail,lastCommit])
//
function getFileInfo(path, ref){
setIsSpin(true);
const url = `/${owner}/${projectsId}/sub_entries.json`;
axios.get(url, {
params:{
filepath:path,
ref:ref || branchName,
type
}
}).then((result) => {
if (result) {
let en = result.data.entries;
if(en.type){
setDirInfo(undefined);
setFileInfo(en);
setType(en.type);
}else{
setFileInfo(undefined);
setDirInfo(en);
setType("dir");
}
let c = result.data.last_commit
setLastCommit(c && c.commit);
setLastCommitAuthor(c && c.committer);
setMainFlag(false);
setReadOnly(true);
}
setTimeout(function(){setIsSpin(false);},500)
}).catch(error=>{setIsSpin(false);})
}
//
function changeBranch(value){
let url = `/projects/${owner}/${projectsId}${value && `/tree/${value}`}${treeValue ? `/${treeValue}`:""}`;
props.history.push(url);
}
//
const fileMenu =(
<Menu>
<Menu.Item><a onClick={()=>urlLink(`/projects/${owner}/${projectsId}/${branchName || (projectDetail && projectDetail.default_branch)}/uploadfile${treeValue === undefined ? "" : `/${treeValue}`}`)}>上传文件</a></Menu.Item>
<Menu.Item><a onClick={()=>urlLink(`/projects/${owner}/${projectsId}/${branchName || (projectDetail && projectDetail.default_branch)}/newfile${treeValue === undefined ? "" : `/${treeValue}`}`)}>新建文件</a></Menu.Item>
</Menu>
)
function getPathUrl(array,index){
if(array && array.length>0 && index){
let str = "";
for(let i=0;i<index;i++){
str += `/${array[i]}`;
}
return str.substr(1);
}
}
//
function returnMain(){
setTreeValue(undefined);
let branch = branchName || (projectDetail && projectDetail.default_branch);
props.history.push(`/projects/${owner}/${projectsId}/tree/${branch}`);
};
//
function returnUlr(url){
props.history.push(`/projects/${owner}/${projectsId}/tree${branchName?`/${branchName}`:""}/${url}`);
}
//
function goToSubRoot(path,type,filename){
setType(type);
props.history.push(`/projects/${owner}/${projectsId}${`/tree/${branchName || (projectDetail && projectDetail.default_branch)}`}${path?`/${path}`:""}`);
}
function onEdit(readOnly){
setReadOnly(readOnly);
}
function ChangeFile(path, readOnly){
//
props.history.push(`/projects/${owner}/${projectsId}/tree/${branchName || (projectDetail && projectDetail.default_branch)}/${path}`);
setType("file");
setReadOnly(readOnly);
};
function changeHide(hide){
setHide(!hide);
}
function urlLink(link){
if(props.checkIfLogin()===false){
props.showLoginDialog()
return false;
}
props.history.push(link);
}
const downloadMenu = (
<div className="downMenu">
<div style={{padding:"20px",borderBottom:"1px solid #eee"}}>
<CloneAddress
http_url={projectDetail && projectDetail.clone_url}
showNotification={props.showNotification}/>
</div>
<Menu className="edu-txt-center">
<Menu.Item><a href={zip_url}>下载 ZIP</a></Menu.Item>
<Menu.Item><a href={tar_url}>下载 TAR.GZ</a></Menu.Item>
</Menu>
</div>
)
// website
function okUpdate(d,w,l){
const url = `/${owner}/${projectsId}.json`;
axios.put(url,{
description:d,website:w,lesson_url:l
}).then(result=>{
if(result && result.data && result.data.id){
setDesc(result.data.description);
setWebsite(result.data.website);
setLessonUrl(result.data.lesson_url);
}
})
}
let n = fileInfo && fileInfo.name;
const mdFlag = n && n.substring(n.length-3,n.length) === ".md";
return(
<WhiteBack>
<UpdateDescModal desc={desc} website={website} lesson_url={lesson_url} visible={openModal} onCancel={()=>setOpenModal(false)} onOk={okUpdate}/>
<Spin spinning={isSpin}>
{
(dirInfo || fileInfo) &&
<React.Fragment>
<DrawerPanel
history={props.history}
owner={owner}
projectsId={projectsId}
name={projectDetail && projectDetail.name}
branch={branchName || (projectDetail && projectDetail.default_branch)}
visible={visible}
onClose={()=>setVisible(false)}
list = {mainFlag ? dirInfo : undefined}
/>
<div className="drawerBtn" onClick={()=>setVisible(true)}>
<i className="iconfont icon-youjiantou font-16"></i>
<span>目录</span>
</div>
</React.Fragment>
}
<div style={{minHeight:"500px"}}>
{
projectDetail &&
<Box className="Panels">
<LongWidth>
<div className="panelmenu">
<FlexAJ>
<AlignCenter>
<div className="mr20">
{
props && props.platform ?
<SelectBranch
repo_id={projectDetail && projectDetail.repo_id}
projectsId={projectsId}
branch={branchName || (projectDetail && projectDetail.default_branch)}
changeBranch={changeBranch}
owner={owner}
history={props.history}
branchList={projectDetail && projectDetail.branches && projectDetail.branches.list}
></SelectBranch>
:
<span>分支<span className="color-grey-6">{branchName || (projectDetail && projectDetail.default_branch)}</span></span>
}
</div>
<AlignCenter className="mr20">
<Link to={`/projects/${owner}/${projectsId}/branchs`} className="color-grey-9">
<i className="iconfont icon-fenzhi2 font-18 color-grey-9 mr3"></i>
<span className="color-grey-6 mr3">{projectDetail && projectDetail.branches && projectDetail.branches.total_count}</span>分支
</Link>
</AlignCenter>
<AlignCenter className="mr20">
<Link to={`/projects/${owner}/${projectsId}/tag`} className="color-grey-9">
<i className="iconfont icon-biaoqian3 font-16 color-grey-9 mr3"></i>
<span className="color-grey-6 mr3">{projectDetail && projectDetail.tags && projectDetail.tags.total_count}</span>标签
</Link>
</AlignCenter>
</AlignCenter>
<AlignCenter>
<div className="mr20 addOptionBtn">
{
projectDetail.type !== 2 &&
<a onClick={()=>urlLink(`/projects/${owner}/${projectsId}/pulls/new`)} >+ 合并请求</a>
}
<a onClick={()=>urlLink(`/projects/${owner}/${projectsId}/issues/new`)} >+ 任务</a>
</div>
{ type === "dir" && projectDetail.type !== 2 &&
<Dropdown overlay={fileMenu} className="mr20" trigger={['click']}>
<Button type="default">文件 <i className="iconfont icon-sanjiaoxing-down ml3 font-14 color-grey-9"></i></Button>
</Dropdown>
}
<Dropdown overlay={downloadMenu} placement="bottomRight" trigger={['click']}>
<Button type={'primary'}>下载 <i className="iconfont icon-sanjiaoxing-down ml3 font-14 color-white"></i></Button>
</Dropdown>
</AlignCenter>
</FlexAJ>
{
dirInfo || fileInfo ?
<div className="listtable">
{
lastCommit &&
<div className="listtablehead">
<User url={getImageUrl(`/${lastCommitAuthor && lastCommitAuthor.image_url}`)} name={lastCommitAuthor && lastCommitAuthor.name} id={lastCommitAuthor && lastCommitAuthor.id} login={lastCommitAuthor && lastCommitAuthor.login}/>
<div className={hideBtn && hide ? "ellipsistxt hide" :"ellipsistxt"}><pre id="ptxt">{lastCommit && lastCommit.message}</pre></div>
{ hideBtn && <span className="ellipsis" onClick={()=>changeHide(hide)}><i className="iconfont icon-shenglvehao"></i></span> }
<span className="ml12 color-grey-9 mt3">{lastCommit && lastCommit.time_from_now}</span>
{ commitCount ? <Link to={`/projects/${owner}/${projectsId}/commits`} className="ml12 color-grey-9"><i className="iconfont icon-tijiao mr3 font-17 color-grey-9"></i>{commitCount}次提交</Link>:"" }
</div>
}
<ul className="listtablebody">
{
treeValuePath && treeValuePath.length > 0 &&
<Path
identifier={projectDetail && projectDetail.identifier}
treeValuePath={treeValuePath}
returnUlr={returnUlr}
returnMain={returnMain}
getPathUrl={getPathUrl}
/>
}
{
dirInfo && dirInfo.length > 0 &&
dirInfo.map((item,key)=>{
return(
<Catalogue
owner={owner}
item={item}
projectsId={projectsId}
goToSubRoot={goToSubRoot}
/>
)
})
}
{
fileInfo &&
<CoderRootFileDetail
{...props}
detail={fileInfo}
readOnly={readOnly}
md={mdFlag}
onEdit={onEdit}
currentBranch={branchName || (projectDetail && projectDetail.default_branch)}
type={projectDetail.type}
></CoderRootFileDetail>
}
</ul>
</div>
: ""
}
{
(dirInfo && dirInfo.length === 0) && (fileInfo && fileInfo.length === 0) ? <Nodata _html="暂未发现文件"/> :""
}
{/* readme文件显示(显示文件详情时不显示readme文件) */}
{ dirInfo && (projectDetail && projectDetail.readme) ? <ReadMe ChangeFile={ChangeFile} readme={projectDetail && projectDetail.readme} operate={props && (props.isManager || props.isDeveloper) && projectDetail.type !==2 } history={props.history} /> :"" }
</div>
</LongWidth>
{
!fileInfo &&
<ShortWidth>
<Gap style={{paddingLeft:"30px"}}>
<div className="panelmenu">
<FlexAJ className="font-18 color-grey-6 mb20" style={{lineHeight:"28px"}}>简介
{projectDetail.permission && (projectDetail.permission==="Admin" || projectDetail.permission==="Owner") && <i onClick={()=>setOpenModal(true)} className="iconfont icon-anquanshezhi color-grey-9 font-15"></i>}
</FlexAJ>
{desc && <p className="font-14 color-grey-9 mb15 task-hide-2" style={{lineHeight:"22px",WebkitLineClamp:"4",textAlign:"justify",wordBreak:"break-all"}}>{desc}</p>}
{
website &&
<p className="color-grey-6 df">
<i className="iconfont icon-lianjie2 font-15 mr10 color-grey-9"></i>
<a href={website} target="_blank" style={{wordBreak:"break-all",lineHeight:"20px",marginTop:"5px",textDecoration:"underline"}}>{website}</a>
</p>
}
<p>
<i className="iconfont icon-wenjian4 font-15 mr10 color-grey-9"></i>
<a href="#readme" className="color-grey-6">README.md</a>
</p>
<p className="color-grey-6">
<i className="iconfont icon-dataBase font-15 mr10 color-grey-9"></i>
<span>{projectDetail && projectDetail.size}</span>
</p>
{
projectDetail && projectDetail.license_name &&
<p className="color-grey-6">
<i className="iconfont icon-tianping font-16 mr10 color-grey-9"></i>
<span>{projectDetail.license_name}</span>
</p>
}
</div>
{
lesson_url &&
<div>
<Divider />
<p className="font-16 color-grey-6">实践课程</p>
<a href={lesson_url} target="_blank" className="color-grey-6" style={{textDecoration:"underline"}}>{lesson_url}</a>
</div>
}
{/* 发布 */}
{
projectDetail && projectDetail.release_versions &&
<React.Fragment>
<Divider />
<Releases owner={owner} projectsId={projectsId} releaseVersions={projectDetail.release_versions} history={props.history}/>
</React.Fragment>
}
{/* 贡献者 */}
{
projectDetail && projectDetail.contributors &&
<Contributors contributors={projectDetail && projectDetail.contributors} owner={owner} projectsId={projectsId} />
}
{/* 语言 */}
{ projectDetail && projectDetail.languages &&
<React.Fragment>
<Divider />
<LanguagePower languages={projectDetail.languages}/>
</React.Fragment>
}
</Gap>
</ShortWidth>
}
</Box>
}
</div>
</Spin>
</WhiteBack>
)
}
export default CoderDepot;

View File

@ -0,0 +1,22 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { truncateCommitId } from '../common/util';
function CoderDepotCatalogue({item , goToSubRoot , owner , projectsId }){
return(
<li>
<span>
<a onClick={()=>goToSubRoot(item.path,item.type,item.name)}>
<i className={item.type === 'dir' ? "iconfont icon-wenjianjia1 color-green-file font-15 mr5":"iconfont icon-wenjia color-green-file font-15 mr5"}></i>{item.name}
</a>
</span>
<span title="init project">
<Link to={`/projects/${owner}/${projectsId}/commits/${truncateCommitId(`${item.commit && item.commit.sha}`)}`} title={item.commit && item.commit.message}>
{item.commit && item.commit.message}
</Link>
</span>
<span>{item.commit && item.commit.time_from_now}</span>
</li>
)
}
export default CoderDepotCatalogue;

View File

@ -0,0 +1,30 @@
import React from 'react';
function CoderDepotPath({treeValuePath , returnUlr , returnMain , getPathUrl , identifier}){
return(
<li className="listtablepath">
<p>
<a
onClick={returnMain}
className="color-blue"
>
{identifier}
</a>
{treeValuePath.map((item, key) => {
return (
<React.Fragment>
{
key === treeValuePath.length-1 ?
<span className="color-grey-6 subFileName" key={key}>{item}</span>
:
<a onClick={()=>returnUlr(`${getPathUrl(treeValuePath,key+1)}`)} className="color-blue subFileName">{item}</a>
}
</React.Fragment>
);
})}
</p>
</li>
)
}
export default CoderDepotPath;

View File

@ -0,0 +1,62 @@
import React, { useEffect, useState } from 'react';
import RenderHtml from '../../components/render-html';
import { Dropdown , Menu , Spin } from 'antd';
import { Link } from 'react-router-dom';
const $ = window.$;
function CoderDepotReadme({ operate , history , readme , ChangeFile }){
const [ menuList ,setMenuList ] = useState(undefined);
useEffect(()=>{
if(readme && readme.content){
let path = history.location.pathname;
const items = $.map($("#readme").find("h1,h2,h3,h4,h5,h6"), function (el, _) {
const anchor = el.id;
const level = el.tagName.replace("H", "");
const href = `#${anchor}`;
return { href:`${path}${href}`,text:el.textContent , level:level }
});
setMenuList(items);
}
},[readme])
function menu(){
if(menuList && menuList.length > 0){
let hash = history.location.hash;
return(
<Menu className="menuslist">
{
menuList.map((item,key)=>{
return(
<Menu.Item key={item.id} className={decodeURI(hash).indexOf(item.text)>-1 ?"active":""}><Link to={`${item.href}`} style={{paddingLeft:`${item.level *10}px`}} title={item.text}>{item.text}</Link></Menu.Item>
)
})
}
</Menu>
)
}else{
return <Spin />
}
}
return(
<div className="commonBox" id="readme">
<div className="commonBox-title">
<Dropdown overlay={menu()}>
<i className="iconfont icon-zhangjie1 font-16 color-grey-3 mr10"></i>
</Dropdown>
<span className="commonBox-title-read">README.md</span>
{
operate ?
<a className="ml20 pull-right" onClick={() =>ChangeFile(readme && readme.path, false)}>
<i className="iconfont icon-bianji6 font-16 color-blue"></i>
</a>
:""
}
</div>
<div className="commonBox-info">
<RenderHtml className="break_word_comments imageLayerParent" value={readme && readme.content} url={history.location}/>
</div>
</div>
)
}
export default CoderDepotReadme;

View File

@ -3,7 +3,7 @@ import { Link } from "react-router-dom";
import { Dropdown , Menu , Icon , Tooltip , Spin } from 'antd'; import { Dropdown , Menu , Icon , Tooltip , Spin } from 'antd';
import { truncateCommitId } from '../common/util'; import { truncateCommitId } from '../common/util';
import { getBranch } from '../GetData/getData'; import { getBranch } from '../GetData/getData';
import Nodata from '../Nodata';
import './list.css'; import './list.css';
export default ((props)=>{ export default ((props)=>{
@ -32,9 +32,9 @@ export default ((props)=>{
return( return(
<li key={key}> <li key={key}>
<div> <div>
<Link to={`/projects/${owner}/${projectsId}?branch=${item.name}`} className="color-blue font-15" style={{"maxWidth":"100px"}}>{item.name}</Link> <Link to={`/projects/${owner}/${projectsId}/tree/${item.name}`} className="color-blue font-15" style={{"maxWidth":"100px"}}>{item.name}</Link>
<p className="f-wrap-alignCenter mt15"> <p className="f-wrap-alignCenter mt15">
<span className="mr5 commitKey" style={{marginLeft:0}}>{item.last_commit && truncateCommitId(item.last_commit.sha)}</span> <Link to={`/projects/${owner}/${projectsId}/commits/${truncateCommitId(`${item.last_commit.sha}`)}`} className="mr5 commitKey" style={{marginLeft:0}}>{item.last_commit && truncateCommitId(item.last_commit.sha)}</Link>
<span className="color-grey-3 hide-1 messages leftPoint">{item.last_commit && item.last_commit.message}</span> <span className="color-grey-3 hide-1 messages leftPoint">{item.last_commit && item.last_commit.message}</span>
<span className="color-grey-8 ml30">最后更新于{item.last_commit && item.last_commit.time_from_now}</span> <span className="color-grey-8 ml30">最后更新于{item.last_commit && item.last_commit.time_from_now}</span>
</p> </p>
@ -54,6 +54,8 @@ export default ((props)=>{
</ul> </ul>
</React.Fragment> </React.Fragment>
) )
}else if(data && data.length === 0){
return ( <Nodata _html="暂无数据"/>)
} }
} }
const menu =(zip_url,tar_url)=> ( const menu =(zip_url,tar_url)=> (
@ -68,7 +70,7 @@ export default ((props)=>{
<Spin spinning={isSpin}> <Spin spinning={isSpin}>
<div className="branchTable"> <div className="branchTable">
<p className="branchTitle bor-bottom-greyE">分支列表</p> <p className="branchTitle bor-bottom-greyE">分支列表</p>
{list()} <div style={{minHeight:"400px"}}>{list()}</div>
</div> </div>
</Spin> </Spin>
</div> </div>

Some files were not shown because too many files have changed in this diff Show More