mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-29 10:57:44 +09:00 
			
		
		
		
	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:
		| @@ -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, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user