Add status indicator on main home screen for each repo (#24638)
It will show the calculated commit status state of the latest commit on the default branch for each repository in the dashboard repo list - Closes #15620 # Before  # After  --------- Signed-off-by: Yarden Shoham <git@yardenshoham.com> Co-authored-by: delvh <dev.lh@web.de> Co-authored-by: Giteabot <teabot@gitea.io>
This commit is contained in:
		
							parent
							
								
									68081c4721
								
							
						
					
					
						commit
						4810fe55e3
					
				
					 10 changed files with 152 additions and 20 deletions
				
			
		| 
						 | 
					@ -23,6 +23,7 @@ import (
 | 
				
			||||||
	api "code.gitea.io/gitea/modules/structs"
 | 
						api "code.gitea.io/gitea/modules/structs"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/timeutil"
 | 
						"code.gitea.io/gitea/modules/timeutil"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"xorm.io/builder"
 | 
				
			||||||
	"xorm.io/xorm"
 | 
						"xorm.io/xorm"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -240,6 +241,55 @@ func GetLatestCommitStatus(ctx context.Context, repoID int64, sha string, listOp
 | 
				
			||||||
	return statuses, count, db.GetEngine(ctx).In("id", ids).Find(&statuses)
 | 
						return statuses, count, db.GetEngine(ctx).In("id", ids).Find(&statuses)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetLatestCommitStatusForPairs returns all statuses with a unique context for a given list of repo-sha pairs
 | 
				
			||||||
 | 
					func GetLatestCommitStatusForPairs(ctx context.Context, repoIDsToLatestCommitSHAs map[int64]string, listOptions db.ListOptions) (map[int64][]*CommitStatus, error) {
 | 
				
			||||||
 | 
						type result struct {
 | 
				
			||||||
 | 
							ID     int64
 | 
				
			||||||
 | 
							RepoID int64
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						results := make([]result, 0, len(repoIDsToLatestCommitSHAs))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sess := db.GetEngine(ctx).Table(&CommitStatus{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Create a disjunction of conditions for each repoID and SHA pair
 | 
				
			||||||
 | 
						conds := make([]builder.Cond, 0, len(repoIDsToLatestCommitSHAs))
 | 
				
			||||||
 | 
						for repoID, sha := range repoIDsToLatestCommitSHAs {
 | 
				
			||||||
 | 
							conds = append(conds, builder.Eq{"repo_id": repoID, "sha": sha})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						sess = sess.Where(builder.Or(conds...)).
 | 
				
			||||||
 | 
							Select("max( id ) as id, repo_id").
 | 
				
			||||||
 | 
							GroupBy("context_hash, repo_id").OrderBy("max( id ) desc")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sess = db.SetSessionPagination(sess, &listOptions)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err := sess.Find(&results)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ids := make([]int64, 0, len(results))
 | 
				
			||||||
 | 
						repoStatuses := make(map[int64][]*CommitStatus)
 | 
				
			||||||
 | 
						for _, result := range results {
 | 
				
			||||||
 | 
							ids = append(ids, result.ID)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						statuses := make([]*CommitStatus, 0, len(ids))
 | 
				
			||||||
 | 
						if len(ids) > 0 {
 | 
				
			||||||
 | 
							err = db.GetEngine(ctx).In("id", ids).Find(&statuses)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Group the statuses by repo ID
 | 
				
			||||||
 | 
							for _, status := range statuses {
 | 
				
			||||||
 | 
								repoStatuses[status.RepoID] = append(repoStatuses[status.RepoID], status)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return repoStatuses, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FindRepoRecentCommitStatusContexts returns repository's recent commit status contexts
 | 
					// FindRepoRecentCommitStatusContexts returns repository's recent commit status contexts
 | 
				
			||||||
func FindRepoRecentCommitStatusContexts(ctx context.Context, repoID int64, before time.Duration) ([]string, error) {
 | 
					func FindRepoRecentCommitStatusContexts(ctx context.Context, repoID int64, before time.Duration) ([]string, error) {
 | 
				
			||||||
	start := timeutil.TimeStampNow().AddDuration(-before)
 | 
						start := timeutil.TimeStampNow().AddDuration(-before)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -106,6 +106,17 @@ func GetBranchesByPath(ctx context.Context, path string, skip, limit int) ([]*Br
 | 
				
			||||||
	return gitRepo.GetBranches(skip, limit)
 | 
						return gitRepo.GetBranches(skip, limit)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetBranchCommitID returns a branch commit ID by its name
 | 
				
			||||||
 | 
					func GetBranchCommitID(ctx context.Context, path, branch string) (string, error) {
 | 
				
			||||||
 | 
						gitRepo, err := OpenRepository(ctx, path)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return "", err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer gitRepo.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return gitRepo.GetBranchCommitID(branch)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetBranches returns a slice of *git.Branch
 | 
					// GetBranches returns a slice of *git.Branch
 | 
				
			||||||
func (repo *Repository) GetBranches(skip, limit int) ([]*Branch, int, error) {
 | 
					func (repo *Repository) GetBranches(skip, limit int) ([]*Branch, int, error) {
 | 
				
			||||||
	brs, countAll, err := repo.GetBranchNames(skip, limit)
 | 
						brs, countAll, err := repo.GetBranchNames(skip, limit)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,9 +9,11 @@ import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
						"sync"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/models"
 | 
						"code.gitea.io/gitea/models"
 | 
				
			||||||
	"code.gitea.io/gitea/models/db"
 | 
						"code.gitea.io/gitea/models/db"
 | 
				
			||||||
 | 
						git_model "code.gitea.io/gitea/models/git"
 | 
				
			||||||
	"code.gitea.io/gitea/models/organization"
 | 
						"code.gitea.io/gitea/models/organization"
 | 
				
			||||||
	access_model "code.gitea.io/gitea/models/perm/access"
 | 
						access_model "code.gitea.io/gitea/models/perm/access"
 | 
				
			||||||
	repo_model "code.gitea.io/gitea/models/repo"
 | 
						repo_model "code.gitea.io/gitea/models/repo"
 | 
				
			||||||
| 
						 | 
					@ -576,23 +578,49 @@ func SearchRepo(ctx *context.Context) {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	results := make([]*api.Repository, len(repos))
 | 
						// collect the latest commit of each repo
 | 
				
			||||||
 | 
						repoIDsToLatestCommitSHAs := make(map[int64]string)
 | 
				
			||||||
 | 
						wg := sync.WaitGroup{}
 | 
				
			||||||
 | 
						wg.Add(len(repos))
 | 
				
			||||||
 | 
						for _, repo := range repos {
 | 
				
			||||||
 | 
							go func(repo *repo_model.Repository) {
 | 
				
			||||||
 | 
								defer wg.Done()
 | 
				
			||||||
 | 
								commitID, err := repo_service.GetBranchCommitID(ctx, repo, repo.DefaultBranch)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								repoIDsToLatestCommitSHAs[repo.ID] = commitID
 | 
				
			||||||
 | 
							}(repo)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						wg.Wait()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// call the database O(1) times to get the commit statuses for all repos
 | 
				
			||||||
 | 
						repoToItsLatestCommitStatuses, err := git_model.GetLatestCommitStatusForPairs(ctx, repoIDsToLatestCommitSHAs, db.ListOptions{})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Error("GetLatestCommitStatusForPairs: %v", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						results := make([]*repo_service.WebSearchRepository, len(repos))
 | 
				
			||||||
	for i, repo := range repos {
 | 
						for i, repo := range repos {
 | 
				
			||||||
		results[i] = &api.Repository{
 | 
							results[i] = &repo_service.WebSearchRepository{
 | 
				
			||||||
			ID:       repo.ID,
 | 
								Repository: &api.Repository{
 | 
				
			||||||
			FullName: repo.FullName(),
 | 
									ID:       repo.ID,
 | 
				
			||||||
			Fork:     repo.IsFork,
 | 
									FullName: repo.FullName(),
 | 
				
			||||||
			Private:  repo.IsPrivate,
 | 
									Fork:     repo.IsFork,
 | 
				
			||||||
			Template: repo.IsTemplate,
 | 
									Private:  repo.IsPrivate,
 | 
				
			||||||
			Mirror:   repo.IsMirror,
 | 
									Template: repo.IsTemplate,
 | 
				
			||||||
			Stars:    repo.NumStars,
 | 
									Mirror:   repo.IsMirror,
 | 
				
			||||||
			HTMLURL:  repo.HTMLURL(),
 | 
									Stars:    repo.NumStars,
 | 
				
			||||||
			Link:     repo.Link(),
 | 
									HTMLURL:  repo.HTMLURL(),
 | 
				
			||||||
			Internal: !repo.IsPrivate && repo.Owner.Visibility == api.VisibleTypePrivate,
 | 
									Link:     repo.Link(),
 | 
				
			||||||
 | 
									Internal: !repo.IsPrivate && repo.Owner.Visibility == api.VisibleTypePrivate,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								LatestCommitStatus: git_model.CalcCommitStatus(repoToItsLatestCommitStatuses[repo.ID]),
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx.JSON(http.StatusOK, api.SearchResults{
 | 
						ctx.JSON(http.StatusOK, repo_service.WebSearchResults{
 | 
				
			||||||
		OK:   true,
 | 
							OK:   true,
 | 
				
			||||||
		Data: results,
 | 
							Data: results,
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -53,6 +53,10 @@ func GetBranches(ctx context.Context, repo *repo_model.Repository, skip, limit i
 | 
				
			||||||
	return git.GetBranchesByPath(ctx, repo.RepoPath(), skip, limit)
 | 
						return git.GetBranchesByPath(ctx, repo.RepoPath(), skip, limit)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func GetBranchCommitID(ctx context.Context, repo *repo_model.Repository, branch string) (string, error) {
 | 
				
			||||||
 | 
						return git.GetBranchCommitID(ctx, repo.RepoPath(), branch)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// checkBranchName validates branch name with existing repository branches
 | 
					// checkBranchName validates branch name with existing repository branches
 | 
				
			||||||
func checkBranchName(ctx context.Context, repo *repo_model.Repository, name string) error {
 | 
					func checkBranchName(ctx context.Context, repo *repo_model.Repository, name string) error {
 | 
				
			||||||
	_, err := git.WalkReferences(ctx, repo.RepoPath(), func(_, refName string) error {
 | 
						_, err := git.WalkReferences(ctx, repo.RepoPath(), func(_, refName string) error {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,6 +9,7 @@ import (
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/gitea/models"
 | 
						"code.gitea.io/gitea/models"
 | 
				
			||||||
	"code.gitea.io/gitea/models/db"
 | 
						"code.gitea.io/gitea/models/db"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/models/git"
 | 
				
			||||||
	issues_model "code.gitea.io/gitea/models/issues"
 | 
						issues_model "code.gitea.io/gitea/models/issues"
 | 
				
			||||||
	"code.gitea.io/gitea/models/organization"
 | 
						"code.gitea.io/gitea/models/organization"
 | 
				
			||||||
	packages_model "code.gitea.io/gitea/models/packages"
 | 
						packages_model "code.gitea.io/gitea/models/packages"
 | 
				
			||||||
| 
						 | 
					@ -20,9 +21,22 @@ import (
 | 
				
			||||||
	"code.gitea.io/gitea/modules/notification"
 | 
						"code.gitea.io/gitea/modules/notification"
 | 
				
			||||||
	repo_module "code.gitea.io/gitea/modules/repository"
 | 
						repo_module "code.gitea.io/gitea/modules/repository"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/setting"
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/structs"
 | 
				
			||||||
	pull_service "code.gitea.io/gitea/services/pull"
 | 
						pull_service "code.gitea.io/gitea/services/pull"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// WebSearchRepository represents a repository returned by web search
 | 
				
			||||||
 | 
					type WebSearchRepository struct {
 | 
				
			||||||
 | 
						Repository         *structs.Repository `json:"repository"`
 | 
				
			||||||
 | 
						LatestCommitStatus *git.CommitStatus   `json:"latest_commit_status"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// WebSearchResults results of a successful web search
 | 
				
			||||||
 | 
					type WebSearchResults struct {
 | 
				
			||||||
 | 
						OK   bool                   `json:"ok"`
 | 
				
			||||||
 | 
						Data []*WebSearchRepository `json:"data"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// CreateRepository creates a repository for the user/organization.
 | 
					// CreateRepository creates a repository for the user/organization.
 | 
				
			||||||
func CreateRepository(ctx context.Context, doer, owner *user_model.User, opts repo_module.CreateRepoOptions) (*repo_model.Repository, error) {
 | 
					func CreateRepository(ctx context.Context, doer, owner *user_model.User, opts repo_module.CreateRepoOptions) (*repo_model.Repository, error) {
 | 
				
			||||||
	repo, err := repo_module.CreateRepository(doer, owner, opts)
 | 
						repo, err := repo_module.CreateRepository(doer, owner, opts)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -79,6 +79,8 @@
 | 
				
			||||||
                  <svg-icon name="octicon-archive" :size="16" class-name="gt-ml-2"/>
 | 
					                  <svg-icon name="octicon-archive" :size="16" class-name="gt-ml-2"/>
 | 
				
			||||||
                </span>
 | 
					                </span>
 | 
				
			||||||
              </div>
 | 
					              </div>
 | 
				
			||||||
 | 
					              <!-- the commit status icon logic is taken from templates/repo/commit_status.tmpl -->
 | 
				
			||||||
 | 
					              <svg-icon v-if="repo.latest_commit_status_state" :name="statusIcon(repo.latest_commit_status_state)" :class-name="'commit-status icon text ' + statusColor(repo.latest_commit_status_state)" :size="16"/>
 | 
				
			||||||
            </a>
 | 
					            </a>
 | 
				
			||||||
          </li>
 | 
					          </li>
 | 
				
			||||||
        </ul>
 | 
					        </ul>
 | 
				
			||||||
| 
						 | 
					@ -154,6 +156,15 @@ import {SvgIcon} from '../svg.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const {appSubUrl, assetUrlPrefix, pageData} = window.config;
 | 
					const {appSubUrl, assetUrlPrefix, pageData} = window.config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const commitStatus = {
 | 
				
			||||||
 | 
					  pending: {name: 'octicon-dot-fill', color: 'grey'},
 | 
				
			||||||
 | 
					  running: {name: 'octicon-dot-fill', color: 'yellow'},
 | 
				
			||||||
 | 
					  success: {name: 'octicon-check', color: 'green'},
 | 
				
			||||||
 | 
					  error: {name: 'gitea-exclamation', color: 'red'},
 | 
				
			||||||
 | 
					  failure: {name: 'octicon-x', color: 'red'},
 | 
				
			||||||
 | 
					  warning: {name: 'gitea-exclamation', color: 'yellow'},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const sfc = {
 | 
					const sfc = {
 | 
				
			||||||
  components: {SvgIcon},
 | 
					  components: {SvgIcon},
 | 
				
			||||||
  data() {
 | 
					  data() {
 | 
				
			||||||
| 
						 | 
					@ -387,7 +398,7 @@ const sfc = {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (searchedURL === this.searchURL) {
 | 
					      if (searchedURL === this.searchURL) {
 | 
				
			||||||
        this.repos = json.data;
 | 
					        this.repos = json.data.map((webSearchRepo) => {return {...webSearchRepo.repository, latest_commit_status_state: webSearchRepo.latest_commit_status.State}});
 | 
				
			||||||
        const count = response.headers.get('X-Total-Count');
 | 
					        const count = response.headers.get('X-Total-Count');
 | 
				
			||||||
        if (searchedQuery === '' && searchedMode === '' && this.archivedFilter === 'both') {
 | 
					        if (searchedQuery === '' && searchedMode === '' && this.archivedFilter === 'both') {
 | 
				
			||||||
          this.reposTotalCount = count;
 | 
					          this.reposTotalCount = count;
 | 
				
			||||||
| 
						 | 
					@ -412,6 +423,14 @@ const sfc = {
 | 
				
			||||||
        return 'octicon-repo';
 | 
					        return 'octicon-repo';
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      return 'octicon-repo';
 | 
					      return 'octicon-repo';
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    statusIcon(status) {
 | 
				
			||||||
 | 
					      return commitStatus[status].name;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    statusColor(status) {
 | 
				
			||||||
 | 
					      return commitStatus[status].color;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,8 +26,8 @@ export function initOrgTeamSearchRepoBox() {
 | 
				
			||||||
        const items = [];
 | 
					        const items = [];
 | 
				
			||||||
        $.each(response.data, (_i, item) => {
 | 
					        $.each(response.data, (_i, item) => {
 | 
				
			||||||
          items.push({
 | 
					          items.push({
 | 
				
			||||||
            title: item.full_name.split('/')[1],
 | 
					            title: item.repository.full_name.split('/')[1],
 | 
				
			||||||
            description: item.full_name
 | 
					            description: item.repository.full_name
 | 
				
			||||||
          });
 | 
					          });
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -291,8 +291,8 @@ export function initRepoIssueReferenceRepositorySearch() {
 | 
				
			||||||
          const filteredResponse = {success: true, results: []};
 | 
					          const filteredResponse = {success: true, results: []};
 | 
				
			||||||
          $.each(response.data, (_r, repo) => {
 | 
					          $.each(response.data, (_r, repo) => {
 | 
				
			||||||
            filteredResponse.results.push({
 | 
					            filteredResponse.results.push({
 | 
				
			||||||
              name: htmlEscape(repo.full_name),
 | 
					              name: htmlEscape(repo.repository.full_name),
 | 
				
			||||||
              value: repo.full_name
 | 
					              value: repo.repository.full_name
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
          });
 | 
					          });
 | 
				
			||||||
          return filteredResponse;
 | 
					          return filteredResponse;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,8 +34,8 @@ export function initRepoTemplateSearch() {
 | 
				
			||||||
            // Parse the response from the api to work with our dropdown
 | 
					            // Parse the response from the api to work with our dropdown
 | 
				
			||||||
            $.each(response.data, (_r, repo) => {
 | 
					            $.each(response.data, (_r, repo) => {
 | 
				
			||||||
              filteredResponse.results.push({
 | 
					              filteredResponse.results.push({
 | 
				
			||||||
                name: htmlEscape(repo.full_name),
 | 
					                name: htmlEscape(repo.repository.full_name),
 | 
				
			||||||
                value: repo.id
 | 
					                value: repo.repository.id
 | 
				
			||||||
              });
 | 
					              });
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
            return filteredResponse;
 | 
					            return filteredResponse;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,10 +2,12 @@ import {h} from 'vue';
 | 
				
			||||||
import giteaDoubleChevronLeft from '../../public/img/svg/gitea-double-chevron-left.svg';
 | 
					import giteaDoubleChevronLeft from '../../public/img/svg/gitea-double-chevron-left.svg';
 | 
				
			||||||
import giteaDoubleChevronRight from '../../public/img/svg/gitea-double-chevron-right.svg';
 | 
					import giteaDoubleChevronRight from '../../public/img/svg/gitea-double-chevron-right.svg';
 | 
				
			||||||
import giteaEmptyCheckbox from '../../public/img/svg/gitea-empty-checkbox.svg';
 | 
					import giteaEmptyCheckbox from '../../public/img/svg/gitea-empty-checkbox.svg';
 | 
				
			||||||
 | 
					import giteaExclamation from '../../public/img/svg/gitea-exclamation.svg';
 | 
				
			||||||
import octiconArchive from '../../public/img/svg/octicon-archive.svg';
 | 
					import octiconArchive from '../../public/img/svg/octicon-archive.svg';
 | 
				
			||||||
import octiconArrowSwitch from '../../public/img/svg/octicon-arrow-switch.svg';
 | 
					import octiconArrowSwitch from '../../public/img/svg/octicon-arrow-switch.svg';
 | 
				
			||||||
import octiconBlocked from '../../public/img/svg/octicon-blocked.svg';
 | 
					import octiconBlocked from '../../public/img/svg/octicon-blocked.svg';
 | 
				
			||||||
import octiconBold from '../../public/img/svg/octicon-bold.svg';
 | 
					import octiconBold from '../../public/img/svg/octicon-bold.svg';
 | 
				
			||||||
 | 
					import octiconCheck from '../../public/img/svg/octicon-check.svg';
 | 
				
			||||||
import octiconCheckbox from '../../public/img/svg/octicon-checkbox.svg';
 | 
					import octiconCheckbox from '../../public/img/svg/octicon-checkbox.svg';
 | 
				
			||||||
import octiconCheckCircleFill from '../../public/img/svg/octicon-check-circle-fill.svg';
 | 
					import octiconCheckCircleFill from '../../public/img/svg/octicon-check-circle-fill.svg';
 | 
				
			||||||
import octiconChevronDown from '../../public/img/svg/octicon-chevron-down.svg';
 | 
					import octiconChevronDown from '../../public/img/svg/octicon-chevron-down.svg';
 | 
				
			||||||
| 
						 | 
					@ -19,6 +21,7 @@ import octiconDiffAdded from '../../public/img/svg/octicon-diff-added.svg';
 | 
				
			||||||
import octiconDiffModified from '../../public/img/svg/octicon-diff-modified.svg';
 | 
					import octiconDiffModified from '../../public/img/svg/octicon-diff-modified.svg';
 | 
				
			||||||
import octiconDiffRemoved from '../../public/img/svg/octicon-diff-removed.svg';
 | 
					import octiconDiffRemoved from '../../public/img/svg/octicon-diff-removed.svg';
 | 
				
			||||||
import octiconDiffRenamed from '../../public/img/svg/octicon-diff-renamed.svg';
 | 
					import octiconDiffRenamed from '../../public/img/svg/octicon-diff-renamed.svg';
 | 
				
			||||||
 | 
					import octiconDotFill from '../../public/img/svg/octicon-dot-fill.svg';
 | 
				
			||||||
import octiconEye from '../../public/img/svg/octicon-eye.svg';
 | 
					import octiconEye from '../../public/img/svg/octicon-eye.svg';
 | 
				
			||||||
import octiconFile from '../../public/img/svg/octicon-file.svg';
 | 
					import octiconFile from '../../public/img/svg/octicon-file.svg';
 | 
				
			||||||
import octiconFileDirectoryFill from '../../public/img/svg/octicon-file-directory-fill.svg';
 | 
					import octiconFileDirectoryFill from '../../public/img/svg/octicon-file-directory-fill.svg';
 | 
				
			||||||
| 
						 | 
					@ -67,10 +70,12 @@ const svgs = {
 | 
				
			||||||
  'gitea-double-chevron-left': giteaDoubleChevronLeft,
 | 
					  'gitea-double-chevron-left': giteaDoubleChevronLeft,
 | 
				
			||||||
  'gitea-double-chevron-right': giteaDoubleChevronRight,
 | 
					  'gitea-double-chevron-right': giteaDoubleChevronRight,
 | 
				
			||||||
  'gitea-empty-checkbox': giteaEmptyCheckbox,
 | 
					  'gitea-empty-checkbox': giteaEmptyCheckbox,
 | 
				
			||||||
 | 
					  'gitea-exclamation': giteaExclamation,
 | 
				
			||||||
  'octicon-archive': octiconArchive,
 | 
					  'octicon-archive': octiconArchive,
 | 
				
			||||||
  'octicon-arrow-switch': octiconArrowSwitch,
 | 
					  'octicon-arrow-switch': octiconArrowSwitch,
 | 
				
			||||||
  'octicon-blocked': octiconBlocked,
 | 
					  'octicon-blocked': octiconBlocked,
 | 
				
			||||||
  'octicon-bold': octiconBold,
 | 
					  'octicon-bold': octiconBold,
 | 
				
			||||||
 | 
					  'octicon-check': octiconCheck,
 | 
				
			||||||
  'octicon-check-circle-fill': octiconCheckCircleFill,
 | 
					  'octicon-check-circle-fill': octiconCheckCircleFill,
 | 
				
			||||||
  'octicon-checkbox': octiconCheckbox,
 | 
					  'octicon-checkbox': octiconCheckbox,
 | 
				
			||||||
  'octicon-chevron-down': octiconChevronDown,
 | 
					  'octicon-chevron-down': octiconChevronDown,
 | 
				
			||||||
| 
						 | 
					@ -84,6 +89,7 @@ const svgs = {
 | 
				
			||||||
  'octicon-diff-modified': octiconDiffModified,
 | 
					  'octicon-diff-modified': octiconDiffModified,
 | 
				
			||||||
  'octicon-diff-removed': octiconDiffRemoved,
 | 
					  'octicon-diff-removed': octiconDiffRemoved,
 | 
				
			||||||
  'octicon-diff-renamed': octiconDiffRenamed,
 | 
					  'octicon-diff-renamed': octiconDiffRenamed,
 | 
				
			||||||
 | 
					  'octicon-dot-fill': octiconDotFill,
 | 
				
			||||||
  'octicon-eye': octiconEye,
 | 
					  'octicon-eye': octiconEye,
 | 
				
			||||||
  'octicon-file': octiconFile,
 | 
					  'octicon-file': octiconFile,
 | 
				
			||||||
  'octicon-file-directory-fill': octiconFileDirectoryFill,
 | 
					  'octicon-file-directory-fill': octiconFileDirectoryFill,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue