mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-26 12:27:06 +00:00 
			
		
		
		
	Enable/disable owner and repo projects independently (#28805)
Part of #23318 Add menu in repo settings to allow for repo admin to decide not just if projects are enabled or disabled per repo, but also which kind of projects (repo-level/owner-level) are enabled. If repo projects disabled, don't show the projects tab.  --------- Co-authored-by: delvh <dev.lh@web.de>
This commit is contained in:
		| @@ -520,6 +520,7 @@ | ||||
|   id: 75 | ||||
|   repo_id: 1 | ||||
|   type: 8 | ||||
|   config: "{\"ProjectsMode\":\"all\"}" | ||||
|   created_unix: 946684810 | ||||
|  | ||||
| - | ||||
| @@ -650,12 +651,6 @@ | ||||
|   type: 2 | ||||
|   created_unix: 946684810 | ||||
|  | ||||
| - | ||||
|   id: 98 | ||||
|   repo_id: 1 | ||||
|   type: 8 | ||||
|   created_unix: 946684810 | ||||
|  | ||||
| - | ||||
|   id: 99 | ||||
|   repo_id: 1 | ||||
|   | ||||
| @@ -411,6 +411,11 @@ func (repo *Repository) MustGetUnit(ctx context.Context, tp unit.Type) *RepoUnit | ||||
| 			Type:   tp, | ||||
| 			Config: new(ActionsConfig), | ||||
| 		} | ||||
| 	} else if tp == unit.TypeProjects { | ||||
| 		return &RepoUnit{ | ||||
| 			Type:   tp, | ||||
| 			Config: new(ProjectsConfig), | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return &RepoUnit{ | ||||
|   | ||||
| @@ -202,6 +202,53 @@ func (cfg *ActionsConfig) ToDB() ([]byte, error) { | ||||
| 	return json.Marshal(cfg) | ||||
| } | ||||
|  | ||||
| // ProjectsMode represents the projects enabled for a repository | ||||
| type ProjectsMode string | ||||
|  | ||||
| const ( | ||||
| 	// ProjectsModeRepo allows only repo-level projects | ||||
| 	ProjectsModeRepo ProjectsMode = "repo" | ||||
| 	// ProjectsModeOwner allows only owner-level projects | ||||
| 	ProjectsModeOwner ProjectsMode = "owner" | ||||
| 	// ProjectsModeAll allows both kinds of projects | ||||
| 	ProjectsModeAll ProjectsMode = "all" | ||||
| 	// ProjectsModeNone doesn't allow projects | ||||
| 	ProjectsModeNone ProjectsMode = "none" | ||||
| ) | ||||
|  | ||||
| // ProjectsConfig describes projects config | ||||
| type ProjectsConfig struct { | ||||
| 	ProjectsMode ProjectsMode | ||||
| } | ||||
|  | ||||
| // FromDB fills up a ProjectsConfig from serialized format. | ||||
| func (cfg *ProjectsConfig) FromDB(bs []byte) error { | ||||
| 	return json.UnmarshalHandleDoubleEncode(bs, &cfg) | ||||
| } | ||||
|  | ||||
| // ToDB exports a ProjectsConfig to a serialized format. | ||||
| func (cfg *ProjectsConfig) ToDB() ([]byte, error) { | ||||
| 	return json.Marshal(cfg) | ||||
| } | ||||
|  | ||||
| func (cfg *ProjectsConfig) GetProjectsMode() ProjectsMode { | ||||
| 	if cfg.ProjectsMode != "" { | ||||
| 		return cfg.ProjectsMode | ||||
| 	} | ||||
|  | ||||
| 	return ProjectsModeNone | ||||
| } | ||||
|  | ||||
| func (cfg *ProjectsConfig) IsProjectsAllowed(m ProjectsMode) bool { | ||||
| 	projectsMode := cfg.GetProjectsMode() | ||||
|  | ||||
| 	if m == ProjectsModeNone { | ||||
| 		return true | ||||
| 	} | ||||
|  | ||||
| 	return projectsMode == m || projectsMode == ProjectsModeAll | ||||
| } | ||||
|  | ||||
| // BeforeSet is invoked from XORM before setting the value of a field of this object. | ||||
| func (r *RepoUnit) BeforeSet(colName string, val xorm.Cell) { | ||||
| 	switch colName { | ||||
| @@ -217,7 +264,9 @@ func (r *RepoUnit) BeforeSet(colName string, val xorm.Cell) { | ||||
| 			r.Config = new(IssuesConfig) | ||||
| 		case unit.TypeActions: | ||||
| 			r.Config = new(ActionsConfig) | ||||
| 		case unit.TypeCode, unit.TypeReleases, unit.TypeWiki, unit.TypeProjects, unit.TypePackages: | ||||
| 		case unit.TypeProjects: | ||||
| 			r.Config = new(ProjectsConfig) | ||||
| 		case unit.TypeCode, unit.TypeReleases, unit.TypeWiki, unit.TypePackages: | ||||
| 			fallthrough | ||||
| 		default: | ||||
| 			r.Config = new(UnitConfig) | ||||
| @@ -265,6 +314,11 @@ func (r *RepoUnit) ActionsConfig() *ActionsConfig { | ||||
| 	return r.Config.(*ActionsConfig) | ||||
| } | ||||
|  | ||||
| // ProjectsConfig returns config for unit.ProjectsConfig | ||||
| func (r *RepoUnit) ProjectsConfig() *ProjectsConfig { | ||||
| 	return r.Config.(*ProjectsConfig) | ||||
| } | ||||
|  | ||||
| func getUnitsByRepoID(ctx context.Context, repoID int64) (units []*RepoUnit, err error) { | ||||
| 	var tmpUnits []*RepoUnit | ||||
| 	if err := db.GetEngine(ctx).Where("repo_id = ?", repoID).Find(&tmpUnits); err != nil { | ||||
|   | ||||
| @@ -93,6 +93,12 @@ func CreateRepositoryByExample(ctx context.Context, doer, u *user_model.User, re | ||||
| 					AllowRebaseUpdate: true, | ||||
| 				}, | ||||
| 			}) | ||||
| 		} else if tp == unit.TypeProjects { | ||||
| 			units = append(units, repo_model.RepoUnit{ | ||||
| 				RepoID: repo.ID, | ||||
| 				Type:   tp, | ||||
| 				Config: &repo_model.ProjectsConfig{ProjectsMode: repo_model.ProjectsModeAll}, | ||||
| 			}) | ||||
| 		} else { | ||||
| 			units = append(units, repo_model.RepoUnit{ | ||||
| 				RepoID: repo.ID, | ||||
|   | ||||
| @@ -90,6 +90,7 @@ type Repository struct { | ||||
| 	ExternalWiki                  *ExternalWiki    `json:"external_wiki,omitempty"` | ||||
| 	HasPullRequests               bool             `json:"has_pull_requests"` | ||||
| 	HasProjects                   bool             `json:"has_projects"` | ||||
| 	ProjectsMode                  string           `json:"projects_mode"` | ||||
| 	HasReleases                   bool             `json:"has_releases"` | ||||
| 	HasPackages                   bool             `json:"has_packages"` | ||||
| 	HasActions                    bool             `json:"has_actions"` | ||||
| @@ -180,6 +181,8 @@ type EditRepoOption struct { | ||||
| 	HasPullRequests *bool `json:"has_pull_requests,omitempty"` | ||||
| 	// either `true` to enable project unit, or `false` to disable them. | ||||
| 	HasProjects *bool `json:"has_projects,omitempty"` | ||||
| 	// `repo` to only allow repo-level projects, `owner` to only allow owner projects, `all` to allow both. | ||||
| 	ProjectsMode *string `json:"projects_mode,omitempty" binding:"In(repo,owner,all)"` | ||||
| 	// either `true` to enable releases unit, or `false` to disable them. | ||||
| 	HasReleases *bool `json:"has_releases,omitempty"` | ||||
| 	// either `true` to enable packages unit, or `false` to disable them. | ||||
|   | ||||
| @@ -2090,7 +2090,11 @@ settings.pulls.default_delete_branch_after_merge = Delete pull request branch af | ||||
| settings.pulls.default_allow_edits_from_maintainers = Allow edits from maintainers by default | ||||
| settings.releases_desc = Enable Repository Releases | ||||
| settings.packages_desc = Enable Repository Packages Registry | ||||
| settings.projects_desc = Enable Repository Projects | ||||
| settings.projects_desc = Enable Projects | ||||
| settings.projects_mode_desc = Projects Mode (which kinds of projects to show) | ||||
| settings.projects_mode_repo = Repo projects only | ||||
| settings.projects_mode_owner = Only user or org projects | ||||
| settings.projects_mode_all = All projects | ||||
| settings.actions_desc = Enable Repository Actions | ||||
| settings.admin_settings = Administrator Settings | ||||
| settings.admin_enable_health_check = Enable Repository Health Checks (git fsck) | ||||
|   | ||||
| @@ -944,13 +944,33 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error { | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if opts.HasProjects != nil && !unit_model.TypeProjects.UnitGlobalDisabled() { | ||||
| 		if *opts.HasProjects { | ||||
| 	currHasProjects := repo.UnitEnabled(ctx, unit_model.TypeProjects) | ||||
| 	newHasProjects := currHasProjects | ||||
| 	if opts.HasProjects != nil { | ||||
| 		newHasProjects = *opts.HasProjects | ||||
| 	} | ||||
| 	if currHasProjects || newHasProjects { | ||||
| 		if newHasProjects && !unit_model.TypeProjects.UnitGlobalDisabled() { | ||||
| 			unit, err := repo.GetUnit(ctx, unit_model.TypeProjects) | ||||
| 			var config *repo_model.ProjectsConfig | ||||
| 			if err != nil { | ||||
| 				config = &repo_model.ProjectsConfig{ | ||||
| 					ProjectsMode: repo_model.ProjectsModeAll, | ||||
| 				} | ||||
| 			} else { | ||||
| 				config = unit.ProjectsConfig() | ||||
| 			} | ||||
|  | ||||
| 			if opts.ProjectsMode != nil { | ||||
| 				config.ProjectsMode = repo_model.ProjectsMode(*opts.ProjectsMode) | ||||
| 			} | ||||
|  | ||||
| 			units = append(units, repo_model.RepoUnit{ | ||||
| 				RepoID: repo.ID, | ||||
| 				Type:   unit_model.TypeProjects, | ||||
| 				Config: config, | ||||
| 			}) | ||||
| 		} else { | ||||
| 		} else if !newHasProjects && !unit_model.TypeProjects.UnitGlobalDisabled() { | ||||
| 			deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeProjects) | ||||
| 		} | ||||
| 	} | ||||
|   | ||||
| @@ -587,8 +587,15 @@ func retrieveProjects(ctx *context.Context, repo *repo_model.Repository) { | ||||
| 	if repo.Owner.IsOrganization() { | ||||
| 		repoOwnerType = project_model.TypeOrganization | ||||
| 	} | ||||
|  | ||||
| 	projectsUnit := repo.MustGetUnit(ctx, unit.TypeProjects) | ||||
|  | ||||
| 	var openProjects []*project_model.Project | ||||
| 	var closedProjects []*project_model.Project | ||||
| 	var err error | ||||
| 	projects, err := db.Find[project_model.Project](ctx, project_model.SearchOptions{ | ||||
|  | ||||
| 	if projectsUnit.ProjectsConfig().IsProjectsAllowed(repo_model.ProjectsModeRepo) { | ||||
| 		openProjects, err = db.Find[project_model.Project](ctx, project_model.SearchOptions{ | ||||
| 			ListOptions: db.ListOptionsAll, | ||||
| 			RepoID:      repo.ID, | ||||
| 			IsClosed:    optional.Some(false), | ||||
| @@ -598,20 +605,7 @@ func retrieveProjects(ctx *context.Context, repo *repo_model.Repository) { | ||||
| 			ctx.ServerError("GetProjects", err) | ||||
| 			return | ||||
| 		} | ||||
| 	projects2, err := db.Find[project_model.Project](ctx, project_model.SearchOptions{ | ||||
| 		ListOptions: db.ListOptionsAll, | ||||
| 		OwnerID:     repo.OwnerID, | ||||
| 		IsClosed:    optional.Some(false), | ||||
| 		Type:        repoOwnerType, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		ctx.ServerError("GetProjects", err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ctx.Data["OpenProjects"] = append(projects, projects2...) | ||||
|  | ||||
| 	projects, err = db.Find[project_model.Project](ctx, project_model.SearchOptions{ | ||||
| 		closedProjects, err = db.Find[project_model.Project](ctx, project_model.SearchOptions{ | ||||
| 			ListOptions: db.ListOptionsAll, | ||||
| 			RepoID:      repo.ID, | ||||
| 			IsClosed:    optional.Some(true), | ||||
| @@ -621,7 +615,21 @@ func retrieveProjects(ctx *context.Context, repo *repo_model.Repository) { | ||||
| 			ctx.ServerError("GetProjects", err) | ||||
| 			return | ||||
| 		} | ||||
| 	projects2, err = db.Find[project_model.Project](ctx, project_model.SearchOptions{ | ||||
| 	} | ||||
|  | ||||
| 	if projectsUnit.ProjectsConfig().IsProjectsAllowed(repo_model.ProjectsModeOwner) { | ||||
| 		openProjects2, err := db.Find[project_model.Project](ctx, project_model.SearchOptions{ | ||||
| 			ListOptions: db.ListOptionsAll, | ||||
| 			OwnerID:     repo.OwnerID, | ||||
| 			IsClosed:    optional.Some(false), | ||||
| 			Type:        repoOwnerType, | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| 			ctx.ServerError("GetProjects", err) | ||||
| 			return | ||||
| 		} | ||||
| 		openProjects = append(openProjects, openProjects2...) | ||||
| 		closedProjects2, err := db.Find[project_model.Project](ctx, project_model.SearchOptions{ | ||||
| 			ListOptions: db.ListOptionsAll, | ||||
| 			OwnerID:     repo.OwnerID, | ||||
| 			IsClosed:    optional.Some(true), | ||||
| @@ -631,8 +639,11 @@ func retrieveProjects(ctx *context.Context, repo *repo_model.Repository) { | ||||
| 			ctx.ServerError("GetProjects", err) | ||||
| 			return | ||||
| 		} | ||||
| 		closedProjects = append(closedProjects, closedProjects2...) | ||||
| 	} | ||||
|  | ||||
| 	ctx.Data["ClosedProjects"] = append(projects, projects2...) | ||||
| 	ctx.Data["OpenProjects"] = openProjects | ||||
| 	ctx.Data["ClosedProjects"] = closedProjects | ||||
| } | ||||
|  | ||||
| // repoReviewerSelection items to bee shown | ||||
|   | ||||
| @@ -14,7 +14,7 @@ import ( | ||||
| 	issues_model "code.gitea.io/gitea/models/issues" | ||||
| 	"code.gitea.io/gitea/models/perm" | ||||
| 	project_model "code.gitea.io/gitea/models/project" | ||||
| 	attachment_model "code.gitea.io/gitea/models/repo" | ||||
| 	repo_model "code.gitea.io/gitea/models/repo" | ||||
| 	"code.gitea.io/gitea/models/unit" | ||||
| 	"code.gitea.io/gitea/modules/base" | ||||
| 	"code.gitea.io/gitea/modules/json" | ||||
| @@ -33,16 +33,17 @@ const ( | ||||
| 	tplProjectsView base.TplName = "repo/projects/view" | ||||
| ) | ||||
|  | ||||
| // MustEnableProjects check if projects are enabled in settings | ||||
| func MustEnableProjects(ctx *context.Context) { | ||||
| // MustEnableRepoProjects check if repo projects are enabled in settings | ||||
| func MustEnableRepoProjects(ctx *context.Context) { | ||||
| 	if unit.TypeProjects.UnitGlobalDisabled() { | ||||
| 		ctx.NotFound("EnableKanbanBoard", nil) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if ctx.Repo.Repository != nil { | ||||
| 		if !ctx.Repo.CanRead(unit.TypeProjects) { | ||||
| 			ctx.NotFound("MustEnableProjects", nil) | ||||
| 		projectsUnit := ctx.Repo.Repository.MustGetUnit(ctx, unit.TypeProjects) | ||||
| 		if !ctx.Repo.CanRead(unit.TypeProjects) || !projectsUnit.ProjectsConfig().IsProjectsAllowed(repo_model.ProjectsModeRepo) { | ||||
| 			ctx.NotFound("MustEnableRepoProjects", nil) | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| @@ -325,10 +326,10 @@ func ViewProject(ctx *context.Context) { | ||||
| 	} | ||||
|  | ||||
| 	if project.CardType != project_model.CardTypeTextOnly { | ||||
| 		issuesAttachmentMap := make(map[int64][]*attachment_model.Attachment) | ||||
| 		issuesAttachmentMap := make(map[int64][]*repo_model.Attachment) | ||||
| 		for _, issuesList := range issuesMap { | ||||
| 			for _, issue := range issuesList { | ||||
| 				if issueAttachment, err := attachment_model.GetAttachmentsByIssueIDImagesLatest(ctx, issue.ID); err == nil { | ||||
| 				if issueAttachment, err := repo_model.GetAttachmentsByIssueIDImagesLatest(ctx, issue.ID); err == nil { | ||||
| 					issuesAttachmentMap[issue.ID] = issueAttachment | ||||
| 				} | ||||
| 			} | ||||
|   | ||||
| @@ -533,6 +533,9 @@ func SettingsPost(ctx *context.Context) { | ||||
| 			units = append(units, repo_model.RepoUnit{ | ||||
| 				RepoID: repo.ID, | ||||
| 				Type:   unit_model.TypeProjects, | ||||
| 				Config: &repo_model.ProjectsConfig{ | ||||
| 					ProjectsMode: repo_model.ProjectsMode(form.ProjectsMode), | ||||
| 				}, | ||||
| 			}) | ||||
| 		} else if !unit_model.TypeProjects.UnitGlobalDisabled() { | ||||
| 			deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeProjects) | ||||
|   | ||||
| @@ -1344,7 +1344,7 @@ func registerRoutes(m *web.Route) { | ||||
| 					}) | ||||
| 				}) | ||||
| 			}, reqRepoProjectsWriter, context.RepoMustNotBeArchived()) | ||||
| 		}, reqRepoProjectsReader, repo.MustEnableProjects) | ||||
| 		}, reqRepoProjectsReader, repo.MustEnableRepoProjects) | ||||
|  | ||||
| 		m.Group("/actions", func() { | ||||
| 			m.Get("", actions.List) | ||||
|   | ||||
| @@ -113,8 +113,11 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInR | ||||
| 		defaultAllowMaintainerEdit = config.DefaultAllowMaintainerEdit | ||||
| 	} | ||||
| 	hasProjects := false | ||||
| 	if _, err := repo.GetUnit(ctx, unit_model.TypeProjects); err == nil { | ||||
| 	projectsMode := repo_model.ProjectsModeAll | ||||
| 	if unit, err := repo.GetUnit(ctx, unit_model.TypeProjects); err == nil { | ||||
| 		hasProjects = true | ||||
| 		config := unit.ProjectsConfig() | ||||
| 		projectsMode = config.ProjectsMode | ||||
| 	} | ||||
|  | ||||
| 	hasReleases := false | ||||
| @@ -211,6 +214,7 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInR | ||||
| 		InternalTracker:               internalTracker, | ||||
| 		HasWiki:                       hasWiki, | ||||
| 		HasProjects:                   hasProjects, | ||||
| 		ProjectsMode:                  string(projectsMode), | ||||
| 		HasReleases:                   hasReleases, | ||||
| 		HasPackages:                   hasPackages, | ||||
| 		HasActions:                    hasActions, | ||||
|   | ||||
| @@ -142,6 +142,7 @@ type RepoSettingForm struct { | ||||
| 	ExternalTrackerRegexpPattern          string | ||||
| 	EnableCloseIssuesViaCommitInAnyBranch bool | ||||
| 	EnableProjects                        bool | ||||
| 	ProjectsMode                          string | ||||
| 	EnableReleases                        bool | ||||
| 	EnablePackages                        bool | ||||
| 	EnablePulls                           bool | ||||
|   | ||||
| @@ -174,7 +174,8 @@ | ||||
| 					</a> | ||||
| 				{{end}} | ||||
|  | ||||
| 				{{if and (not .UnitProjectsGlobalDisabled) (.Permission.CanRead $.UnitTypeProjects)}} | ||||
| 				{{$projectsUnit := .Repository.MustGetUnit $.Context $.UnitTypeProjects}} | ||||
| 				{{if and (not .UnitProjectsGlobalDisabled) (.Permission.CanRead $.UnitTypeProjects) ($projectsUnit.ProjectsConfig.IsProjectsAllowed "repo")}} | ||||
| 					<a href="{{.RepoLink}}/projects" class="{{if .IsProjectsPage}}active {{end}}item"> | ||||
| 						{{svg "octicon-project"}} {{ctx.Locale.Tr "repo.project_board"}} | ||||
| 						{{if .Repository.NumOpenProjects}} | ||||
|   | ||||
| @@ -446,13 +446,45 @@ | ||||
|  | ||||
| 				{{$isProjectsEnabled := .Repository.UnitEnabled $.Context $.UnitTypeProjects}} | ||||
| 				{{$isProjectsGlobalDisabled := .UnitTypeProjects.UnitGlobalDisabled}} | ||||
| 				{{$projectsUnit := .Repository.MustGetUnit $.Context $.UnitTypeProjects}} | ||||
| 				<div class="inline field"> | ||||
| 					<label>{{ctx.Locale.Tr "repo.project_board"}}</label> | ||||
| 					<div class="ui checkbox{{if $isProjectsGlobalDisabled}} disabled{{end}}"{{if $isProjectsGlobalDisabled}} data-tooltip-content="{{ctx.Locale.Tr "repo.unit_disabled"}}"{{end}}> | ||||
| 						<input class="enable-system" name="enable_projects" type="checkbox" {{if $isProjectsEnabled}}checked{{end}}> | ||||
| 						<input class="enable-system" name="enable_projects" type="checkbox" data-target="#projects_box" {{if $isProjectsEnabled}}checked{{end}}> | ||||
| 						<label>{{ctx.Locale.Tr "repo.settings.projects_desc"}}</label> | ||||
| 					</div> | ||||
| 				</div> | ||||
| 				<div class="field {{if not $isProjectsEnabled}} disabled{{end}} gt-pl-4" id="projects_box"> | ||||
| 					<p> | ||||
| 						{{ctx.Locale.Tr "repo.settings.projects_mode_desc"}} | ||||
| 					</p> | ||||
| 					<div class="ui dropdown selection"> | ||||
| 						<select name="projects_mode"> | ||||
| 							<option value="repo" {{if or (not $isProjectsEnabled) (eq $projectsUnit.ProjectsConfig.ProjectsMode "repo")}}selected{{end}}>{{ctx.Locale.Tr "repo.settings.projects_mode_repo"}}</option> | ||||
| 							<option value="owner" {{if or (not $isProjectsEnabled) (eq $projectsUnit.ProjectsConfig.ProjectsMode "owner")}}selected{{end}}>{{ctx.Locale.Tr "repo.settings.projects_mode_owner"}}</option> | ||||
| 							<option value="all" {{if or (not $isProjectsEnabled) (eq $projectsUnit.ProjectsConfig.ProjectsMode "all")}}selected{{end}}>{{ctx.Locale.Tr "repo.settings.projects_mode_all"}}</option> | ||||
| 						</select> | ||||
| 						{{svg "octicon-triangle-down" 14 "dropdown icon"}} | ||||
| 						<div class="default text"> | ||||
| 							{{if (eq $projectsUnit.ProjectsConfig.ProjectsMode "repo")}} | ||||
| 								{{ctx.Locale.Tr "repo.settings.projects_mode_repo"}} | ||||
| 							{{end}} | ||||
| 							{{if (eq $projectsUnit.ProjectsConfig.ProjectsMode "owner")}} | ||||
| 								{{ctx.Locale.Tr "repo.settings.projects_mode_owner"}} | ||||
| 							{{end}} | ||||
| 							{{if (eq $projectsUnit.ProjectsConfig.ProjectsMode "all")}} | ||||
| 								{{ctx.Locale.Tr "repo.settings.projects_mode_all"}} | ||||
| 							{{end}} | ||||
| 						</div> | ||||
| 						<div class="menu"> | ||||
| 							<div class="item" data-value="repo">{{ctx.Locale.Tr "repo.settings.projects_mode_repo"}}</div> | ||||
| 							<div class="item" data-value="owner">{{ctx.Locale.Tr "repo.settings.projects_mode_owner"}}</div> | ||||
| 							<div class="item" data-value="all">{{ctx.Locale.Tr "repo.settings.projects_mode_all"}}</div> | ||||
| 						</div> | ||||
| 					</div> | ||||
| 				</div> | ||||
|  | ||||
| 				<div class="divider"></div> | ||||
|  | ||||
| 				{{$isReleasesEnabled := .Repository.UnitEnabled $.Context $.UnitTypeReleases}} | ||||
| 				{{$isReleasesGlobalDisabled := .UnitTypeReleases.UnitGlobalDisabled}} | ||||
|   | ||||
							
								
								
									
										9
									
								
								templates/swagger/v1_json.tmpl
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										9
									
								
								templates/swagger/v1_json.tmpl
									
									
									
										generated
									
									
									
								
							| @@ -19570,6 +19570,11 @@ | ||||
|           "type": "boolean", | ||||
|           "x-go-name": "Private" | ||||
|         }, | ||||
|         "projects_mode": { | ||||
|           "description": "`repo` to only allow repo-level projects, `owner` to only allow owner projects, `all` to allow both.", | ||||
|           "type": "string", | ||||
|           "x-go-name": "ProjectsMode" | ||||
|         }, | ||||
|         "template": { | ||||
|           "description": "either `true` to make this repository a template or `false` to make it a normal repository", | ||||
|           "type": "boolean", | ||||
| @@ -22491,6 +22496,10 @@ | ||||
|           "type": "boolean", | ||||
|           "x-go-name": "Private" | ||||
|         }, | ||||
|         "projects_mode": { | ||||
|           "type": "string", | ||||
|           "x-go-name": "ProjectsMode" | ||||
|         }, | ||||
|         "release_counter": { | ||||
|           "type": "integer", | ||||
|           "format": "int64", | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Denys Konovalov
					Denys Konovalov