forgeplus-react/src/forge/New/Index.js

777 lines
28 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { Component } from 'react';
import { Input , Form , Select , Checkbox , Button , Spin , AutoComplete, Modal , Radio, Tooltip } from 'antd';
import { Base64 } from 'js-base64';
import { AlignCenter } from '../Component/layout';
import { withTranslation } from 'react-i18next';
import DorpChooseMenus from '../Component/licenseModal/dorpChooseMenus';
import '../css/index.scss';
import './new.scss'
import axios from 'axios';
const addr={
"gitea": "https://docs.gitea.com/development/api-usage",
"gitee": "https://forum.gitlink.org.cn/forums/10603/detail",
"github": "https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token",
"gitlab": "https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html",
"gitcode": "https://docs.gitcode.com/docs/users/pat/"
}
const plat=["gitea","gitee","github","gitlab","gitcode"];
const Option = Select.Option;
class Index extends Component {
constructor(props) {
super(props);
this.state = {
preType: "0",
languageValue: "0",
gitignoreType: "0",
LicensesType: "0",
CategoryList: undefined,
LanguageList: undefined,
GitignoreList: undefined,
LicensesList: undefined,
OwnerList: undefined,
isSpin: false,
project_language_id: undefined,
project_category_id: undefined,
license_id: undefined,
ignore_id: undefined,
owners_id:undefined,
owners_name:undefined,
project_language_list: undefined,
project_category_list: undefined,
license_list: undefined,
ignore_list: undefined,
owners_list:undefined,
project_language_name: undefined,
project_category_name: undefined,
license_name: undefined,
ignore_name: undefined,
descNum:0,
categoreFlag:false,
languageFlag:false,
ignoreFlag:false,
licenseFlag:false,
// 区块链确权
tokenConTri: false,
gitHubUrl:false,
checkToken:"",
isToken:true,
isPrivate:false,
platName:undefined
}
}
componentDidMount = () => {
this.updateDocumentTitle();
// 获取拥有者列表
this.getOwner();
//判断是否为删除新建项目失败后返回,并执行对应逻辑
this.isDeleteProjectBack();
// 获取开源许可证
this.getLicenses();
}
componentDidUpdate=(prevPros)=>{
this.updateDocumentTitle();
if(prevPros && this.props && !this.props.checkIfLogin()){
this.props.history.push("/403")
return
}
}
// 更新网页标题
updateDocumentTitle(){
const { projectsType } = this.props.match.params;
document.title = `${projectsType && projectsType === "mirror" ? "导入" : "新建"}项目`;
}
getOwner=()=>{
const { OIdentifier } = this.props.match.params;
const { user_id } = this.props && this.props.current_user;
const url = `/owners.json`;
axios.get(url).then(result=>{
if(result && result.data){
let owner = result.data.owners;
this.setState({
OwnerList: owner,
})
if(OIdentifier){
owner = owner.filter(item=>item.login === OIdentifier);
}else if(user_id){
owner = owner.filter(item=>item.id === user_id);
}
this.props.form.setFieldsValue({
user_id:owner && owner[0].id
})
owner && this.setState({
owners_id:owner[0].id,
owners_name:owner[0].name
})
this.setOptionsList(owner, 'owners');
}
}).catch(error=>{})
}
getCategory = () => {
const url = `/project_categories.json`
axios.get(url).then((result) => {
if (result) {
// this.setOptionsList(result.data.project_categories, 'project_category');
this.setState({
CategoryList: result.data.project_categories
})
}
}).catch((error) => { })
}
getLanguage = () => {
const url = `/project_languages.json`
axios.get(url).then((result) => {
if (result) {
// this.setOptionsList(result.data.project_languages, 'project_language')
this.setState({
LanguageList: result.data.project_languages
})
}
}).catch((error) => { })
}
getGitignore = () => {
const url = `/ignores.json`
axios.get(url).then((result) => {
if (result) {
// this.setOptionsList(result.data.ignores, 'ignore');
this.setState({
GitignoreList: result.data.ignores
})
}
}).catch((error) => { })
}
getLicenses = () => {
const url = `/licenses.json`
axios.get(url).then((result) => {
if (result) {
let data = result.data.licenses;
this.setState({
LicensesList: data
})
}
}).catch((error) => { })
}
isDeleteProjectBack = () => {
let mirror_status = this.props.history.location.mirror_status;
if (mirror_status === 2 && sessionStorage.newProjectValue) {
Modal.warning({
title: '警告',
content: '项目导入失败!请按操作规范重新导入项目!',
});
let newProjectValue = JSON.parse(sessionStorage.newProjectValue);
if (newProjectValue) {
this.setState({
project_language_id: newProjectValue.project_language_id,
project_category_id: newProjectValue.project_category_id,
license_id: newProjectValue.license_id,
ignore_id: newProjectValue.ignore_id
});
delete newProjectValue.project_language_id;
delete newProjectValue.project_category_id;
delete newProjectValue.license_id;
delete newProjectValue.ignore_id;
this.props.form.setFieldsValue(newProjectValue);
}
}
}
// 设置option
setOptionsList = (data, _head, name) => {
if (data && data.length > 0) {
let _data = data;
if (name) {
_data = data.filter(item => item.name.toLowerCase().indexOf(name.toLowerCase()) > -1);
}
let list = _data && _data.map((item) => (
<Option key={item.id} value={item.name}>
{item.name}
</Option>
));
this.setState({
[_head + "_list"]: list
})
}
}
subMitFrom = () => {
this.props.form.validateFieldsAndScroll((err, values) => {
if (!err) {
this.setState({
isSpin: true
})
const { projectsType } = this.props.match.params;
const { project_language_id, project_category_id, license_id, ignore_id, ignoreFlag,
licenseFlag , categoreFlag, languageFlag, tokenConTri, isPrivate,isToken} = this.state;
const decoderPass = Base64.encode(values.password);
const url = (projectsType && projectsType === "mirror") ? "/projects/migrate.json" : "/projects.json";
// 新建项目的时候,暂存数据,如果失败,返回的时候可以重新赋值
sessionStorage.newProjectValue=JSON.stringify({...values,project_language_id,project_category_id,license_id,ignore_id});
// 贡献值激励确权机制
const {blockchain_init} = values;
const { clone_addr } = values;
axios.post(url, {
...values,
clone_addr:(projectsType && projectsType === "mirror") ? clone_addr.trim() :undefined,
auth_password:decoderPass,
project_language_id:languageFlag ? project_language_id : undefined,
project_category_id:categoreFlag ? project_category_id : undefined,
license_id:licenseFlag ? license_id : undefined,
ignore_id:ignoreFlag ? ignore_id : undefined,
// user_id:owners_id,
blockchain: tokenConTri ,
blockchain_token_all:tokenConTri ? 10000 : undefined,
blockchain_init_token: tokenConTri ? parseInt(blockchain_init):undefined,
auth_token: isPrivate && isToken ? values.auth_token : undefined,
importType:undefined
}).then((result) => {
if (result && result.data.id) {
projectsType && projectsType !== "mirror" && this.props.showNotification(`项目创建成功!`);
setTimeout(() => {
this.props.history.push({pathname: `/${result.data.login}/${result.data.identifier}`, query:{showNps: true}});
}, 500);
}
this.setState({
isSpin: false
})
}).catch((error) => {
this.setState({
isSpin: false
})
})
} else {
window.scrollTo(0,0);
this.setState({
isSpin: false
})
}
})
}
checkId = (rule, value, callback, list, title) => {
let filter = list.filter(item => item.name === value);
if(!value){
callback();
}
if (filter && filter.length > 0) {
callback();
} else {
callback('请在下拉选项中选择正确的' + title + "!");
}
callback();
}
ChangeAddr=(value,unUpdateName)=>{
// 将路径最后一个/后的字符作为项目标识
if(value.indexOf("/") > -1 && !unUpdateName){
let arr = value.split("/");
let first = arr[arr.length-1];
if(first.indexOf(".") > -1){
let second = first.split('.')[0];
if(!second)return;
this.props.form.setFieldsValue({
repository_name:second,
name:second
})
}else{
this.props.form.setFieldsValue({
repository_name:first
})
}
}
// 根据htts://gitlab.com等判断是哪个平台
if(value){
let name = "";
plat.map(i=>{return value.indexOf(`://${i}`)>0 ? name = i :""});
name && this.props.form.setFieldsValue({service:name})
name && this.setState({platName:name})
}
}
changeDesc=(e)=>{
let value = e.target.value;
this.setState({
descNum:value ? value.length :0
})
}
showCateFunc =(e)=>{
const { CategoryList } = this.state;
this.setState({categoreFlag:e.target.checked});
// 获取项目类别
if(e.target.checked && (!CategoryList || (CategoryList && CategoryList.length===0))){
this.getCategory();
}
}
showLanguageFunc =(e)=>{
const { LanguageList } = this.state;
this.setState({languageFlag:e.target.checked});
// 获取项目语言
if(e.target.checked && (!LanguageList || (LanguageList && LanguageList.length===0))){
this.getLanguage();
}
}
showIgnoreFunc =(e)=>{
const { GitignoreList } = this.state;
this.setState({ignoreFlag:e.target.checked})
if(e.target.checked && (!GitignoreList || (GitignoreList && GitignoreList.length===0))){
// 获取Gitignore
this.getGitignore();
}
}
blurFunc=(rule, value, callback)=>{
if(value){
const { clone_addr } = this.props.form.getFieldsValue();
if(clone_addr){
const u = `/projects/verify_auth_token.json`;
axios.post(u,{
auth_token:value,
clone_addr
}).then(response=>{
let res = response.data;
if(res && res.data === false){
callback("请输入正确的令牌");
}else{
callback();
}
callback();
}).catch(error=>{})
}
}else{
callback();
}
}
changeName=(e)=>{
let value = e.target.value;
const { t } = this.props;
if(value){
let reg = /[a-zA-Z0-9]/g;
let strArr = value.match(reg);
if(strArr){
let str = strArr.join("");
this.props.form.setFieldsValue({
repository_name:str
})
}else{
}
}
}
changeVisibility=(e)=>{
let value = e.target.value;
let flag = value === "token";
this.setState({isToken:flag})
let { clone_addr } = this.props.form.getFieldsValue();
if(!flag && clone_addr){
setTimeout(() => {
this.ChangeAddr(clone_addr,true);
}, 500);
}
}
changeIsPrivate=(e)=>{
this.setState({
isPrivate:e.target.checked
})
if(e.target.checked){
this.props.form.setFieldsValue({
importType:"token"
})
}
}
showLicenseFunc =(e)=>{
const { LicensesList } = this.state;
this.setState({
licenseFlag:e.target.checked
})
}
getValue=(values,typeName)=>{
const {id,name} = values
if(id){
this.setState({
[typeName + "_id"]: id
})
this.props.form.setFieldsValue({
[`${typeName}`]:name
})
}
}
render() {
const { getFieldDecorator } = this.props.form;
// 项目类型deposit-托管项目mirror-镜像项目
const { projectsType } = this.props.match.params;
const {current_user:{open_blockchain}} = this.props;
const {
CategoryList,
LanguageList,
GitignoreList,
LicensesList,
isSpin,
owners_list,
OwnerList,
project_language_list,
project_category_list,
license_list,
ignore_list,
descNum,
ignoreFlag,
licenseFlag,
languageFlag,
categoreFlag,
tokenConTri,
checkToken,
isToken,
platName,
isPrivate
} = this.state;
return (
<div className="main back-white" style={{padding:"0px",border:"none"}}>
<div className="newPanel" id="newPanel">
<div className="newPanel_title">{projectsType && projectsType === "mirror" ? "导入" : "新建"}项目</div>
<Spin spinning={isSpin}>
<Form>
<div className="newPanel_content">
{
projectsType && projectsType === "mirror" &&
<React.Fragment>
<Form.Item
label="导入仓库URL"
style={{ marginBottom: "0px" }}
colon={false}
>
{getFieldDecorator('clone_addr', {
rules: [{
required: true, message: '请填写镜像版本库地址'
}],
})(
<Input placeholder="请输入需要导入到本项目的仓库地址" onBlur={(e)=>this.ChangeAddr(e.target.value)} />
)}
</Form.Item>
<p className="formTip" style={{color:"#D1d1c9"}}>示例https://github.com/Stability-AI/StableStudio.git</p>
</React.Fragment>
}
{
projectsType && projectsType === "mirror" &&
<div className="mb10">
<Form.Item
label=""
style={{marginBottom:"0px"}}
>
{getFieldDecorator('isPrivate', {
rules: [],
})(
<Checkbox value="importPrivate" onChange={this.changeIsPrivate}>导入私有项目</Checkbox>
)}
</Form.Item>
<Form.Item
label=""
style={{marginBottom:"10px",display:isPrivate?"block":"none"}}
>
{getFieldDecorator('importType', {
rules: [],
})(
<Radio.Group onChange={this.changeVisibility}>
<Radio value="token">访问令牌方式导入</Radio>
<Radio value="pwd">用户名+密码方式导入</Radio>
</Radio.Group>
)}
</Form.Item>
{/* token导入 */}
{
isToken && isPrivate &&
<Form.Item
label={<span>访问令牌Access Token{addr[`${platName && platName.toLowerCase()}`] && <a className='color-blue' href={addr[`${platName.toLowerCase()}`]} target='_blank'>如何配置</a>}</span>}
>
{getFieldDecorator('auth_token',{
rules: [
{required: true, message: '请输入需要导入仓库的访问令牌'},
{validator:(rule, value, callback)=>this.blurFunc(rule, value, callback)}
],
validateTrigger:"onBlur",
})(
<Input placeholder="请输入需要导入仓库的访问令牌"/>
)}
</Form.Item>
}
{
isPrivate && !isToken &&
<div className="df mb20" style={{alignItems:'center'}}>
{/* 用户名密码导入 */}
<span className="mr10">用户名</span>
<input type="password" style={{display:"none"}} />
<Form.Item
style={{ marginBottom: "0px"}}
label=""
>
{getFieldDecorator('auth_username', {
rules: [],
})(
<Input placeholder="请输入对应平台的登录用户名" style={{width:"240px"}} />
)}
</Form.Item>
<span className="mr10">密码</span>
<Form.Item
style={{ marginBottom: "0px" }}
>
{getFieldDecorator('password', {
rules: [],
})(
<Input.Password placeholder="请输入对应平台的登录密码" autocomplete='new-password' style={{width:"240px"}}/>
)}
</Form.Item>
</div>
}
</div>
}
<AlignCenter>
<Form.Item
label="拥有者"
style={{width:"260px"}}
colon={false}
className="explainPos"
>
{getFieldDecorator('user_id', {
rules: [{
required: true, message: '请选择拥有者'
}],
})(
<Select
showSearch
style={{width:"260px",height:"33px"}}
placeholder="请选择拥有者"
className="plateAutoComplete"
optionFilterProp="children"
filterOption={(input, option) =>
option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
>
{OwnerList && OwnerList.length > 0 &&
OwnerList.map((i,k)=>{
return(
<Option value={i.id}>{i.name}</Option>
)
})
}
</Select>
)}
</Form.Item>
<span className="ml10 mr10 mt10 font-18">/</span>
<Form.Item
label="项目名称"
className="flex1 explainPos"
colon={false}
>
{getFieldDecorator('name', {
rules: [{
required: true, message: '请填写项目名称'
}],
})(
<Input placeholder="例如:团队协作方法与研究" maxLength={50}/>// onBlur={this.changeName}
)}
</Form.Item>
</AlignCenter>
<Form.Item
label={<span>项目标识 <span className="color-grey-9">(项目url标识部分)</span></span>}
colon={false}
>
{getFieldDecorator('repository_name', {
rules: [{
required: true, message: '请填写项目标识'
},{pattern: /^(?!.*\.git$).*$/, message: `项目标识不能以.git结尾`}],
})(
<Input placeholder="项目标识请使用与项目相关的英文关键字" maxLength={100} />
)}
</Form.Item>
<div className="pr">
<span className="toprightNum">{descNum}/200</span>
<Form.Item
label="项目简介"
colon={false}
style={{marginBottom:"0px"}}
>
{getFieldDecorator('description', {
rules: [],
})(
<Input.TextArea maxLength={200} placeholder="项目的介绍" autoSize={{ minRows: 2, maxRows: 6 }} onChange={this.changeDesc}/>
)}
</Form.Item>
</div>
{
(projectsType === "deposit" || !projectsType) &&
<React.Fragment>
<Form.Item
className="privatePart"
>
{getFieldDecorator('ignoreFlag')(
<Checkbox checked={ignoreFlag} onChange={(e)=>this.showIgnoreFunc(e)}>.gitignore</Checkbox>
)}
</Form.Item>
{ ignoreFlag &&
<Form.Item>
{getFieldDecorator('ignore', {
rules: [{
required: ignoreFlag, message: '请选择gitignore'
}, {
validator: (rule, value, callback) => this.checkId(rule, value, callback, GitignoreList, 'gitignore')
}],
})(
<DorpChooseMenus idname={"newPanel"} name={"请选择gitignore用来定义哪些文件不需要添加到版本管理中"} list={GitignoreList} getValue={(value)=>this.getValue(value,"ignore")}/>
)}
</Form.Item>
}
<Form.Item
className="privatePart"
>
{getFieldDecorator('licenseFlag')(
<Checkbox checked={licenseFlag} onChange={(e)=>this.showLicenseFunc(e)}>开源许可证</Checkbox>
)}
</Form.Item>
{ licenseFlag &&
<Form.Item className="privatePart">
{getFieldDecorator('license', {
rules: [{
required: licenseFlag, message: '请选择开源许可证'
}, {
validator: (rule, value, callback) => this.checkId(rule, value, callback, LicensesList, '开源许可证')
}],
})(
<DorpChooseMenus idname={"newPanel"} name={"请选择开源许可证"} list={LicensesList} getValue={(value)=>this.getValue(value,"license")}/>
)}
</Form.Item>
}
</React.Fragment>
}
<Form.Item
className="privatePart"
>
{getFieldDecorator('private')(
<Checkbox value="limit">将项目设为私有<span className="font-13 color-grey-9">(只有项目所有人或拥有权限的项目成员才能看到)</span></Checkbox>
)}
</Form.Item >
{
projectsType && projectsType === "mirror" &&
<Form.Item
className="privatePart"
>
{getFieldDecorator('is_mirror')(
<Checkbox value="limit">该仓库将是一个<span className="color-blue">镜像</span>(8)</Checkbox>
)}
</Form.Item >
}
<Form.Item
style={{ margin: "0px" }}
className="privatePart"
>
{getFieldDecorator('categoreFlag')(
<Checkbox checked={categoreFlag} onChange={(e)=>this.showCateFunc(e)}>项目类别</Checkbox>
)}
</Form.Item>
{categoreFlag &&
<Form.Item className="privatePart">
{getFieldDecorator('project_category', {
rules: [{
required: categoreFlag, message: '请选择项目类别',
}, {
validator: (rule, value, callback) => this.checkId(rule, value, callback, CategoryList, '项目类别')
}],
})(
<DorpChooseMenus idname={"newPanel"} name={"请选择项目类别"} list={CategoryList} getValue={(value)=>this.getValue(value,"project_category")}/>
)}
</Form.Item>
}
<Form.Item className="privatePart">
{getFieldDecorator('languageFlag')(
<Checkbox checked={languageFlag} onChange={(e)=>this.showLanguageFunc(e)}>项目语言</Checkbox>
)}
</Form.Item>
{languageFlag &&
<Form.Item>
{getFieldDecorator('project_language', {
rules: [{
required: languageFlag, message: '请选择项目语言'
}, {
validator: (rule, value, callback) => this.checkId(rule, value, callback, LanguageList, '项目语言')
}],
})(
<DorpChooseMenus idname={"newPanel"} name={"请选择项目语言"} list={LanguageList} getValue={(value)=>this.getValue(value,"project_language")}/>
)}
</Form.Item>
}
{/* 确权 仅在新建项目时 */}
{open_blockchain && projectsType === "deposit" && <div className='mt10 mb10'>
<p className='font-16'>确权</p>
<div className='mt5 mb5 color-grey3'><Checkbox checked={tokenConTri} onChange={(e)=>{this.setState({tokenConTri:e.target.checked})}}>加入贡献值激励确权机制</Checkbox></div>
{tokenConTri && <Form.Item
className="flex1"
extra="Token指本项目的虚拟货币决定用户在本仓库贡献度的比例可以通过issue悬赏或在个人主页贡献确权页进行转移。创建项目时每个项目的Token总量为10000您可以分配您可获取的Token数量未分配的Token将保留至项目Token余额"
>
{getFieldDecorator('blockchain_init', {
rules: [{
required: true, message: '初始token值为一个不超过10000的正整数'
},
{ validator: (rule,val,callback) =>{
if(!/^[1-9]+[0-9]*]*$/.test(val)){
callback('初始token值为正整数');
}if(val>10000){
callback('初始token值最大值10000');
}else{
callback();
}
}}],
})(
<Input placeholder='请填写您项目创建者获取的初始Token值'/>
)}
</Form.Item>}
</div>}
<div className="mt20">
<span className="ant-form-item-required"></span>
</div>
<Form.Item className="formTip mt20">
<Button type="primary" onClick={this.subMitFrom} className="mr20">{projectsType && projectsType === "mirror" ? "导入" : "创建"}项目</Button>
<a onClick={()=>window.history.back(-1)} className="btn_32">取消</a>
</Form.Item>
</div>
</Form>
</Spin>
</div>
</div>
)
}
}
const WrappedIndexForm = Form.create({ name: 'NewWorkForm' })(Index);
export default withTranslation()(WrappedIndexForm);