mirror of https://github.com/go-gitea/gitea
Add a migrate service type switch page (#12697)
* Add a migrat service type switch page * Improve translations * remove images * Fix images * remove extra create repo button on dashboard * Follow reviewers' opinions * Fix frontend lint * Remove wrong submit file * Fix tests * Adjust the size of image * Apply suggestions from code review Co-authored-by: 赵智超 <1012112796@qq.com> * Remove username and password from migration of github/gitlab * Improve docs * Improve interface docs Co-authored-by: 赵智超 <1012112796@qq.com> Co-authored-by: techknowlogick <techknowlogick@gitea.io>pull/12775/head^2
parent
6483dbc8ec
commit
e153cf07c3
After Width: | Height: | Size: 584 B |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 396 B |
@ -0,0 +1,173 @@ |
|||||||
|
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||||
|
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package repo |
||||||
|
|
||||||
|
import ( |
||||||
|
"strings" |
||||||
|
|
||||||
|
"code.gitea.io/gitea/models" |
||||||
|
"code.gitea.io/gitea/modules/auth" |
||||||
|
"code.gitea.io/gitea/modules/base" |
||||||
|
"code.gitea.io/gitea/modules/context" |
||||||
|
"code.gitea.io/gitea/modules/migrations" |
||||||
|
"code.gitea.io/gitea/modules/setting" |
||||||
|
"code.gitea.io/gitea/modules/structs" |
||||||
|
"code.gitea.io/gitea/modules/task" |
||||||
|
"code.gitea.io/gitea/modules/util" |
||||||
|
) |
||||||
|
|
||||||
|
const ( |
||||||
|
tplMigrate base.TplName = "repo/migrate/migrate" |
||||||
|
) |
||||||
|
|
||||||
|
// Migrate render migration of repository page
|
||||||
|
func Migrate(ctx *context.Context) { |
||||||
|
ctx.Data["Services"] = append([]structs.GitServiceType{structs.PlainGitService}, structs.SupportedFullGitService...) |
||||||
|
serviceType := ctx.QueryInt("service_type") |
||||||
|
if serviceType == 0 { |
||||||
|
ctx.HTML(200, tplMigrate) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
ctx.Data["Title"] = ctx.Tr("new_migrate") |
||||||
|
ctx.Data["private"] = getRepoPrivate(ctx) |
||||||
|
ctx.Data["IsForcedPrivate"] = setting.Repository.ForcePrivate |
||||||
|
ctx.Data["DisableMirrors"] = setting.Repository.DisableMirrors |
||||||
|
ctx.Data["mirror"] = ctx.Query("mirror") == "1" |
||||||
|
ctx.Data["wiki"] = ctx.Query("wiki") == "1" |
||||||
|
ctx.Data["milestones"] = ctx.Query("milestones") == "1" |
||||||
|
ctx.Data["labels"] = ctx.Query("labels") == "1" |
||||||
|
ctx.Data["issues"] = ctx.Query("issues") == "1" |
||||||
|
ctx.Data["pull_requests"] = ctx.Query("pull_requests") == "1" |
||||||
|
ctx.Data["releases"] = ctx.Query("releases") == "1" |
||||||
|
ctx.Data["LFSActive"] = setting.LFS.StartServer |
||||||
|
// Plain git should be first
|
||||||
|
ctx.Data["service"] = structs.GitServiceType(serviceType) |
||||||
|
|
||||||
|
ctxUser := checkContextUser(ctx, ctx.QueryInt64("org")) |
||||||
|
if ctx.Written() { |
||||||
|
return |
||||||
|
} |
||||||
|
ctx.Data["ContextUser"] = ctxUser |
||||||
|
|
||||||
|
ctx.HTML(200, base.TplName("repo/migrate/"+structs.GitServiceType(serviceType).Name())) |
||||||
|
} |
||||||
|
|
||||||
|
func handleMigrateError(ctx *context.Context, owner *models.User, err error, name string, tpl base.TplName, form *auth.MigrateRepoForm) { |
||||||
|
switch { |
||||||
|
case migrations.IsRateLimitError(err): |
||||||
|
ctx.RenderWithErr(ctx.Tr("form.visit_rate_limit"), tpl, form) |
||||||
|
case migrations.IsTwoFactorAuthError(err): |
||||||
|
ctx.RenderWithErr(ctx.Tr("form.2fa_auth_required"), tpl, form) |
||||||
|
case models.IsErrReachLimitOfRepo(err): |
||||||
|
ctx.RenderWithErr(ctx.Tr("repo.form.reach_limit_of_creation", owner.MaxCreationLimit()), tpl, form) |
||||||
|
case models.IsErrRepoAlreadyExist(err): |
||||||
|
ctx.Data["Err_RepoName"] = true |
||||||
|
ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), tpl, form) |
||||||
|
case models.IsErrNameReserved(err): |
||||||
|
ctx.Data["Err_RepoName"] = true |
||||||
|
ctx.RenderWithErr(ctx.Tr("repo.form.name_reserved", err.(models.ErrNameReserved).Name), tpl, form) |
||||||
|
case models.IsErrNamePatternNotAllowed(err): |
||||||
|
ctx.Data["Err_RepoName"] = true |
||||||
|
ctx.RenderWithErr(ctx.Tr("repo.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), tpl, form) |
||||||
|
default: |
||||||
|
remoteAddr, _ := form.ParseRemoteAddr(owner) |
||||||
|
err = util.URLSanitizedError(err, remoteAddr) |
||||||
|
if strings.Contains(err.Error(), "Authentication failed") || |
||||||
|
strings.Contains(err.Error(), "Bad credentials") || |
||||||
|
strings.Contains(err.Error(), "could not read Username") { |
||||||
|
ctx.Data["Err_Auth"] = true |
||||||
|
ctx.RenderWithErr(ctx.Tr("form.auth_failed", err.Error()), tpl, form) |
||||||
|
} else if strings.Contains(err.Error(), "fatal:") { |
||||||
|
ctx.Data["Err_CloneAddr"] = true |
||||||
|
ctx.RenderWithErr(ctx.Tr("repo.migrate.failed", err.Error()), tpl, form) |
||||||
|
} else { |
||||||
|
ctx.ServerError(name, err) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// MigratePost response for migrating from external git repository
|
||||||
|
func MigratePost(ctx *context.Context, form auth.MigrateRepoForm) { |
||||||
|
ctx.Data["Title"] = ctx.Tr("new_migrate") |
||||||
|
// Plain git should be first
|
||||||
|
ctx.Data["service"] = form.Service |
||||||
|
ctx.Data["Services"] = append([]structs.GitServiceType{structs.PlainGitService}, structs.SupportedFullGitService...) |
||||||
|
|
||||||
|
ctxUser := checkContextUser(ctx, form.UID) |
||||||
|
if ctx.Written() { |
||||||
|
return |
||||||
|
} |
||||||
|
ctx.Data["ContextUser"] = ctxUser |
||||||
|
|
||||||
|
if ctx.HasError() { |
||||||
|
ctx.HTML(200, tplMigrate) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
remoteAddr, err := form.ParseRemoteAddr(ctx.User) |
||||||
|
if err != nil { |
||||||
|
if models.IsErrInvalidCloneAddr(err) { |
||||||
|
ctx.Data["Err_CloneAddr"] = true |
||||||
|
addrErr := err.(models.ErrInvalidCloneAddr) |
||||||
|
switch { |
||||||
|
case addrErr.IsURLError: |
||||||
|
ctx.RenderWithErr(ctx.Tr("form.url_error"), tplMigrate, &form) |
||||||
|
case addrErr.IsPermissionDenied: |
||||||
|
ctx.RenderWithErr(ctx.Tr("repo.migrate.permission_denied"), tplMigrate, &form) |
||||||
|
case addrErr.IsInvalidPath: |
||||||
|
ctx.RenderWithErr(ctx.Tr("repo.migrate.invalid_local_path"), tplMigrate, &form) |
||||||
|
default: |
||||||
|
ctx.ServerError("Unknown error", err) |
||||||
|
} |
||||||
|
} else { |
||||||
|
ctx.ServerError("ParseRemoteAddr", err) |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
var opts = migrations.MigrateOptions{ |
||||||
|
OriginalURL: form.CloneAddr, |
||||||
|
GitServiceType: structs.GitServiceType(form.Service), |
||||||
|
CloneAddr: remoteAddr, |
||||||
|
RepoName: form.RepoName, |
||||||
|
Description: form.Description, |
||||||
|
Private: form.Private || setting.Repository.ForcePrivate, |
||||||
|
Mirror: form.Mirror && !setting.Repository.DisableMirrors, |
||||||
|
AuthUsername: form.AuthUsername, |
||||||
|
AuthPassword: form.AuthPassword, |
||||||
|
AuthToken: form.AuthToken, |
||||||
|
Wiki: form.Wiki, |
||||||
|
Issues: form.Issues, |
||||||
|
Milestones: form.Milestones, |
||||||
|
Labels: form.Labels, |
||||||
|
Comments: form.Issues || form.PullRequests, |
||||||
|
PullRequests: form.PullRequests, |
||||||
|
Releases: form.Releases, |
||||||
|
} |
||||||
|
if opts.Mirror { |
||||||
|
opts.Issues = false |
||||||
|
opts.Milestones = false |
||||||
|
opts.Labels = false |
||||||
|
opts.Comments = false |
||||||
|
opts.PullRequests = false |
||||||
|
opts.Releases = false |
||||||
|
} |
||||||
|
|
||||||
|
err = models.CheckCreateRepository(ctx.User, ctxUser, opts.RepoName) |
||||||
|
if err != nil { |
||||||
|
handleMigrateError(ctx, ctxUser, err, "MigratePost", tplMigrate, &form) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
err = task.MigrateRepository(ctx.User, ctxUser, opts) |
||||||
|
if err == nil { |
||||||
|
ctx.Redirect(setting.AppSubURL + "/" + ctxUser.Name + "/" + opts.RepoName) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
handleMigrateError(ctx, ctxUser, err, "MigratePost", tplMigrate, &form) |
||||||
|
} |
@ -0,0 +1,103 @@ |
|||||||
|
{{template "base/head" .}} |
||||||
|
<div class="repository new migrate"> |
||||||
|
<div class="ui middle very relaxed page grid"> |
||||||
|
<div class="column"> |
||||||
|
<form class="ui form" action="{{.Link}}" method="post"> |
||||||
|
{{.CsrfTokenHtml}} |
||||||
|
<h3 class="ui top attached header"> |
||||||
|
{{.i18n.Tr "repo.migrate.migrate" .service.Title}} |
||||||
|
<input id="service_type" type="hidden" name="service" value="{{.service}}"> |
||||||
|
</h3> |
||||||
|
<div class="ui attached segment"> |
||||||
|
{{template "base/alert" .}} |
||||||
|
<div class="inline required field {{if .Err_CloneAddr}}error{{end}}"> |
||||||
|
<label for="clone_addr">{{.i18n.Tr "repo.migrate.clone_address"}}</label> |
||||||
|
<input id="clone_addr" name="clone_addr" value="{{.clone_addr}}" autofocus required> |
||||||
|
<span class="help"> |
||||||
|
{{.i18n.Tr "repo.migrate.clone_address_desc"}}{{if .ContextUser.CanImportLocal}} {{.i18n.Tr "repo.migrate.clone_local_path"}}{{end}} |
||||||
|
{{if .LFSActive}}<br/>{{.i18n.Tr "repo.migrate.lfs_mirror_unsupported"}}{{end}} |
||||||
|
</span> |
||||||
|
</div> |
||||||
|
<div class="inline field {{if .Err_Auth}}error{{end}}"> |
||||||
|
<label for="auth_username">{{.i18n.Tr "username"}}</label> |
||||||
|
<input id="auth_username" name="auth_username" value="{{.auth_username}}" {{if not .auth_username}}data-need-clear="true"{{end}}> |
||||||
|
</div> |
||||||
|
<input class="fake" type="password"> |
||||||
|
<div class="inline field {{if .Err_Auth}}error{{end}}"> |
||||||
|
<label for="auth_password">{{.i18n.Tr "password"}}</label> |
||||||
|
<input id="auth_password" name="auth_password" type="password" value="{{.auth_password}}"> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="inline field"> |
||||||
|
<label>{{.i18n.Tr "repo.migrate_options"}}</label> |
||||||
|
<div class="ui checkbox"> |
||||||
|
{{if .DisableMirrors}} |
||||||
|
<input id="mirror" name="mirror" type="checkbox" readonly> |
||||||
|
<label>{{.i18n.Tr "repo.migrate_options_mirror_disabled"}}</label> |
||||||
|
{{else}} |
||||||
|
<input id="mirror" name="mirror" type="checkbox" {{if .mirror}}checked{{end}}> |
||||||
|
<label>{{.i18n.Tr "repo.migrate_options_mirror_helper" | Safe}}</label> |
||||||
|
{{end}} |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="ui divider"></div> |
||||||
|
|
||||||
|
<div class="inline required field {{if .Err_Owner}}error{{end}}"> |
||||||
|
<label>{{.i18n.Tr "repo.owner"}}</label> |
||||||
|
<div class="ui selection owner dropdown"> |
||||||
|
<input type="hidden" id="uid" name="uid" value="{{.ContextUser.ID}}" required> |
||||||
|
<span class="text" title="{{.ContextUser.Name}}"> |
||||||
|
<img class="ui mini image" src="{{.ContextUser.RelAvatarLink}}"> |
||||||
|
{{.ContextUser.ShortName 20}} |
||||||
|
</span> |
||||||
|
<i class="dropdown icon"></i> |
||||||
|
<div class="menu" title="{{.SignedUser.Name}}"> |
||||||
|
<div class="item" data-value="{{.SignedUser.ID}}"> |
||||||
|
<img class="ui mini image" src="{{.SignedUser.RelAvatarLink}}"> |
||||||
|
{{.SignedUser.ShortName 20}} |
||||||
|
</div> |
||||||
|
{{range .Orgs}} |
||||||
|
<div class="item" data-value="{{.ID}}" title="{{.Name}}"> |
||||||
|
<img class="ui mini image" src="{{.RelAvatarLink}}"> |
||||||
|
{{.ShortName 20}} |
||||||
|
</div> |
||||||
|
{{end}} |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="inline required field {{if .Err_RepoName}}error{{end}}"> |
||||||
|
<label for="repo_name">{{.i18n.Tr "repo.repo_name"}}</label> |
||||||
|
<input id="repo_name" name="repo_name" value="{{.repo_name}}" required> |
||||||
|
</div> |
||||||
|
<div class="inline field"> |
||||||
|
<label>{{.i18n.Tr "repo.visibility"}}</label> |
||||||
|
<div class="ui checkbox"> |
||||||
|
{{if .IsForcedPrivate}} |
||||||
|
<input name="private" type="checkbox" checked readonly> |
||||||
|
<label>{{.i18n.Tr "repo.visibility_helper_forced" | Safe}}</label> |
||||||
|
{{else}} |
||||||
|
<input name="private" type="checkbox" {{if .private}}checked{{end}}> |
||||||
|
<label>{{.i18n.Tr "repo.visibility_helper" | Safe}}</label> |
||||||
|
{{end}} |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="inline field {{if .Err_Description}}error{{end}}"> |
||||||
|
<label for="description">{{.i18n.Tr "repo.repo_desc"}}</label> |
||||||
|
<textarea id="description" name="description">{{.description}}</textarea> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="inline field"> |
||||||
|
<label></label> |
||||||
|
<button class="ui green button"> |
||||||
|
{{.i18n.Tr "repo.migrate_repo"}} |
||||||
|
</button> |
||||||
|
<a class="ui button" href="{{AppSubUrl}}/">{{.i18n.Tr "cancel"}}</a> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</form> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
{{template "base/footer" .}} |
@ -0,0 +1,137 @@ |
|||||||
|
{{template "base/head" .}} |
||||||
|
<div class="repository new migrate"> |
||||||
|
<div class="ui middle very relaxed page grid"> |
||||||
|
<div class="column"> |
||||||
|
<form class="ui form" action="{{.Link}}" method="post"> |
||||||
|
{{.CsrfTokenHtml}} |
||||||
|
<h3 class="ui top attached header"> |
||||||
|
{{.i18n.Tr "repo.migrate.migrate" .service.Title}} |
||||||
|
<input id="service_type" type="hidden" name="service" value="{{.service}}"> |
||||||
|
</h3> |
||||||
|
<div class="ui attached segment"> |
||||||
|
{{template "base/alert" .}} |
||||||
|
<div class="inline required field {{if .Err_CloneAddr}}error{{end}}"> |
||||||
|
<label for="clone_addr">{{.i18n.Tr "repo.migrate.clone_address"}}</label> |
||||||
|
<input id="clone_addr" name="clone_addr" value="{{.clone_addr}}" autofocus required> |
||||||
|
<span class="help"> |
||||||
|
{{.i18n.Tr "repo.migrate.clone_address_desc"}}{{if .ContextUser.CanImportLocal}} {{.i18n.Tr "repo.migrate.clone_local_path"}}{{end}} |
||||||
|
{{if .LFSActive}}<br/>{{.i18n.Tr "repo.migrate.lfs_mirror_unsupported"}}{{end}} |
||||||
|
</span> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="inline field {{if .Err_Auth}}error{{end}}"> |
||||||
|
<label for="auth_token">{{.i18n.Tr "access_token"}}</label> |
||||||
|
<input id="auth_token" name="auth_token" value="{{.auth_token}}" {{if not .auth_token}}data-need-clear="true"{{end}}> |
||||||
|
<a target=”_blank” href="https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html">{{svg "octicon-question" 16}}</a> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="inline field"> |
||||||
|
<label>{{.i18n.Tr "repo.migrate_options"}}</label> |
||||||
|
<div class="ui checkbox"> |
||||||
|
{{if .DisableMirrors}} |
||||||
|
<input id="mirror" name="mirror" type="checkbox" readonly> |
||||||
|
<label>{{.i18n.Tr "repo.migrate_options_mirror_disabled"}}</label> |
||||||
|
{{else}} |
||||||
|
<input id="mirror" name="mirror" type="checkbox" {{if .mirror}}checked{{end}}> |
||||||
|
<label>{{.i18n.Tr "repo.migrate_options_mirror_helper" | Safe}}</label> |
||||||
|
{{end}} |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<span class="help">{{.i18n.Tr "repo.migrate.migrate_items_options"}}</span> |
||||||
|
<div id="migrate_items"> |
||||||
|
<div class="inline field"> |
||||||
|
<label>{{.i18n.Tr "repo.migrate_items"}}</label> |
||||||
|
<div class="ui checkbox"> |
||||||
|
<input name="wiki" type="checkbox" {{if .wiki}}checked{{end}}> |
||||||
|
<label>{{.i18n.Tr "repo.migrate_items_wiki" | Safe}}</label> |
||||||
|
</div> |
||||||
|
<div class="ui checkbox"> |
||||||
|
<input name="milestones" type="checkbox" {{if .milestones}}checked{{end}}> |
||||||
|
<label>{{.i18n.Tr "repo.migrate_items_milestones" | Safe}}</label> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="inline field"> |
||||||
|
<label></label> |
||||||
|
<div class="ui checkbox"> |
||||||
|
<input name="labels" type="checkbox" {{if .labels}}checked{{end}}> |
||||||
|
<label>{{.i18n.Tr "repo.migrate_items_labels" | Safe}}</label> |
||||||
|
</div> |
||||||
|
<div class="ui checkbox"> |
||||||
|
<input name="issues" type="checkbox" {{if .issues}}checked{{end}}> |
||||||
|
<label>{{.i18n.Tr "repo.migrate_items_issues" | Safe}}</label> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="inline field"> |
||||||
|
<label></label> |
||||||
|
<div class="ui checkbox"> |
||||||
|
<input name="pull_requests" type="checkbox" {{if .pull_requests}}checked{{end}}> |
||||||
|
<label>{{.i18n.Tr "repo.migrate_items_merge_requests" | Safe}}</label> |
||||||
|
</div> |
||||||
|
<div class="ui checkbox"> |
||||||
|
<input name="releases" type="checkbox" {{if .releases}}checked{{end}}> |
||||||
|
<label>{{.i18n.Tr "repo.migrate_items_releases" | Safe}}</label> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="ui divider"></div> |
||||||
|
|
||||||
|
<div class="inline required field {{if .Err_Owner}}error{{end}}"> |
||||||
|
<label>{{.i18n.Tr "repo.owner"}}</label> |
||||||
|
<div class="ui selection owner dropdown"> |
||||||
|
<input type="hidden" id="uid" name="uid" value="{{.ContextUser.ID}}" required> |
||||||
|
<span class="text" title="{{.ContextUser.Name}}"> |
||||||
|
<img class="ui mini image" src="{{.ContextUser.RelAvatarLink}}"> |
||||||
|
{{.ContextUser.ShortName 20}} |
||||||
|
</span> |
||||||
|
<i class="dropdown icon"></i> |
||||||
|
<div class="menu" title="{{.SignedUser.Name}}"> |
||||||
|
<div class="item" data-value="{{.SignedUser.ID}}"> |
||||||
|
<img class="ui mini image" src="{{.SignedUser.RelAvatarLink}}"> |
||||||
|
{{.SignedUser.ShortName 20}} |
||||||
|
</div> |
||||||
|
{{range .Orgs}} |
||||||
|
<div class="item" data-value="{{.ID}}" title="{{.Name}}"> |
||||||
|
<img class="ui mini image" src="{{.RelAvatarLink}}"> |
||||||
|
{{.ShortName 20}} |
||||||
|
</div> |
||||||
|
{{end}} |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="inline required field {{if .Err_RepoName}}error{{end}}"> |
||||||
|
<label for="repo_name">{{.i18n.Tr "repo.repo_name"}}</label> |
||||||
|
<input id="repo_name" name="repo_name" value="{{.repo_name}}" required> |
||||||
|
</div> |
||||||
|
<div class="inline field"> |
||||||
|
<label>{{.i18n.Tr "repo.visibility"}}</label> |
||||||
|
<div class="ui checkbox"> |
||||||
|
{{if .IsForcedPrivate}} |
||||||
|
<input name="private" type="checkbox" checked readonly> |
||||||
|
<label>{{.i18n.Tr "repo.visibility_helper_forced" | Safe}}</label> |
||||||
|
{{else}} |
||||||
|
<input name="private" type="checkbox" {{if .private}}checked{{end}}> |
||||||
|
<label>{{.i18n.Tr "repo.visibility_helper" | Safe}}</label> |
||||||
|
{{end}} |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="inline field {{if .Err_Description}}error{{end}}"> |
||||||
|
<label for="description">{{.i18n.Tr "repo.repo_desc"}}</label> |
||||||
|
<textarea id="description" name="description">{{.description}}</textarea> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="inline field"> |
||||||
|
<label></label> |
||||||
|
<button class="ui green button"> |
||||||
|
{{.i18n.Tr "repo.migrate_repo"}} |
||||||
|
</button> |
||||||
|
<a class="ui button" href="{{AppSubUrl}}/">{{.i18n.Tr "cancel"}}</a> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</form> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
{{template "base/footer" .}} |
@ -0,0 +1,23 @@ |
|||||||
|
{{template "base/head" .}} |
||||||
|
<div class="repository new migrate"> |
||||||
|
<div class="ui middle very relaxed page grid"> |
||||||
|
<div class="column"> |
||||||
|
<div class="ui three stackable cards"> |
||||||
|
{{range .Services}} |
||||||
|
<div class="ui card"> |
||||||
|
<a class="image" href="{{AppSubUrl}}/repo/migrate?service_type={{.}}"> |
||||||
|
{{svg (Printf "gitea-%s" .Name) 184}} |
||||||
|
</a> |
||||||
|
<div class="content"> |
||||||
|
<a class="header" href="{{AppSubUrl}}/repo/migrate?service_type={{.}}">{{.Title}}</a> |
||||||
|
<div class="description"> |
||||||
|
{{(Printf "repo.migrate.%s.description" .Name) | $.i18n.Tr }} |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
{{end}} |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
{{template "base/footer" .}} |
After Width: | Height: | Size: 702 B |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 409 B |
Loading…
Reference in new issue