Add top author stats to activity page (#9615)
This commit is contained in:
		
							parent
							
								
									7d7ab1eeae
								
							
						
					
					
						commit
						81cfe243f9
					
				
					 13 changed files with 524 additions and 906 deletions
				
			
		| 
						 | 
					@ -19,6 +19,7 @@ type ActivityAuthorData struct {
 | 
				
			||||||
	Name       string `json:"name"`
 | 
						Name       string `json:"name"`
 | 
				
			||||||
	Login      string `json:"login"`
 | 
						Login      string `json:"login"`
 | 
				
			||||||
	AvatarLink string `json:"avatar_link"`
 | 
						AvatarLink string `json:"avatar_link"`
 | 
				
			||||||
 | 
						HomeLink   string `json:"home_link"`
 | 
				
			||||||
	Commits    int64  `json:"commits"`
 | 
						Commits    int64  `json:"commits"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -91,12 +92,20 @@ func GetActivityStatsTopAuthors(repo *Repository, timeFrom time.Time, count int)
 | 
				
			||||||
		return nil, nil
 | 
							return nil, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	users := make(map[int64]*ActivityAuthorData)
 | 
						users := make(map[int64]*ActivityAuthorData)
 | 
				
			||||||
	for k, v := range code.Authors {
 | 
						var unknownUserID int64
 | 
				
			||||||
		if len(k) == 0 {
 | 
						unknownUserAvatarLink := NewGhostUser().AvatarLink()
 | 
				
			||||||
 | 
						for _, v := range code.Authors {
 | 
				
			||||||
 | 
							if len(v.Email) == 0 {
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		u, err := GetUserByEmail(k)
 | 
							u, err := GetUserByEmail(v.Email)
 | 
				
			||||||
		if u == nil || IsErrUserNotExist(err) {
 | 
							if u == nil || IsErrUserNotExist(err) {
 | 
				
			||||||
 | 
								unknownUserID--
 | 
				
			||||||
 | 
								users[unknownUserID] = &ActivityAuthorData{
 | 
				
			||||||
 | 
									Name:       v.Name,
 | 
				
			||||||
 | 
									AvatarLink: unknownUserAvatarLink,
 | 
				
			||||||
 | 
									Commits:    v.Commits,
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
| 
						 | 
					@ -107,10 +116,11 @@ func GetActivityStatsTopAuthors(repo *Repository, timeFrom time.Time, count int)
 | 
				
			||||||
				Name:       u.DisplayName(),
 | 
									Name:       u.DisplayName(),
 | 
				
			||||||
				Login:      u.LowerName,
 | 
									Login:      u.LowerName,
 | 
				
			||||||
				AvatarLink: u.AvatarLink(),
 | 
									AvatarLink: u.AvatarLink(),
 | 
				
			||||||
				Commits:    v,
 | 
									HomeLink:   u.HomeLink(),
 | 
				
			||||||
 | 
									Commits:    v.Commits,
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			user.Commits += v
 | 
								user.Commits += v.Commits
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	v := make([]*ActivityAuthorData, 0)
 | 
						v := make([]*ActivityAuthorData, 0)
 | 
				
			||||||
| 
						 | 
					@ -119,7 +129,7 @@ func GetActivityStatsTopAuthors(repo *Repository, timeFrom time.Time, count int)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sort.Slice(v, func(i, j int) bool {
 | 
						sort.Slice(v, func(i, j int) bool {
 | 
				
			||||||
		return v[i].Commits < v[j].Commits
 | 
							return v[i].Commits > v[j].Commits
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cnt := count
 | 
						cnt := count
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,6 +8,7 @@ import (
 | 
				
			||||||
	"bufio"
 | 
						"bufio"
 | 
				
			||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"sort"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
| 
						 | 
					@ -21,7 +22,14 @@ type CodeActivityStats struct {
 | 
				
			||||||
	Additions                int64
 | 
						Additions                int64
 | 
				
			||||||
	Deletions                int64
 | 
						Deletions                int64
 | 
				
			||||||
	CommitCountInAllBranches int64
 | 
						CommitCountInAllBranches int64
 | 
				
			||||||
	Authors                  map[string]int64
 | 
						Authors                  []*CodeActivityAuthor
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CodeActivityAuthor represents git statistics data for commit authors
 | 
				
			||||||
 | 
					type CodeActivityAuthor struct {
 | 
				
			||||||
 | 
						Name    string
 | 
				
			||||||
 | 
						Email   string
 | 
				
			||||||
 | 
						Commits int64
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetCodeActivityStats returns code statistics for acitivity page
 | 
					// GetCodeActivityStats returns code statistics for acitivity page
 | 
				
			||||||
| 
						 | 
					@ -58,8 +66,9 @@ func (repo *Repository) GetCodeActivityStats(fromTime time.Time, branch string)
 | 
				
			||||||
	stats.CommitCount = 0
 | 
						stats.CommitCount = 0
 | 
				
			||||||
	stats.Additions = 0
 | 
						stats.Additions = 0
 | 
				
			||||||
	stats.Deletions = 0
 | 
						stats.Deletions = 0
 | 
				
			||||||
	authors := make(map[string]int64)
 | 
						authors := make(map[string]*CodeActivityAuthor)
 | 
				
			||||||
	files := make(map[string]bool)
 | 
						files := make(map[string]bool)
 | 
				
			||||||
 | 
						var author string
 | 
				
			||||||
	p := 0
 | 
						p := 0
 | 
				
			||||||
	for scanner.Scan() {
 | 
						for scanner.Scan() {
 | 
				
			||||||
		l := strings.TrimSpace(scanner.Text())
 | 
							l := strings.TrimSpace(scanner.Text())
 | 
				
			||||||
| 
						 | 
					@ -78,10 +87,17 @@ func (repo *Repository) GetCodeActivityStats(fromTime time.Time, branch string)
 | 
				
			||||||
		case 2: // Commit sha-1
 | 
							case 2: // Commit sha-1
 | 
				
			||||||
			stats.CommitCount++
 | 
								stats.CommitCount++
 | 
				
			||||||
		case 3: // Author
 | 
							case 3: // Author
 | 
				
			||||||
 | 
								author = l
 | 
				
			||||||
		case 4: // E-mail
 | 
							case 4: // E-mail
 | 
				
			||||||
			email := strings.ToLower(l)
 | 
								email := strings.ToLower(l)
 | 
				
			||||||
			i := authors[email]
 | 
								if _, ok := authors[email]; !ok {
 | 
				
			||||||
			authors[email] = i + 1
 | 
									authors[email] = &CodeActivityAuthor{
 | 
				
			||||||
 | 
										Name:    author,
 | 
				
			||||||
 | 
										Email:   email,
 | 
				
			||||||
 | 
										Commits: 0,
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								authors[email].Commits++
 | 
				
			||||||
		default: // Changed file
 | 
							default: // Changed file
 | 
				
			||||||
			if parts := strings.Fields(l); len(parts) >= 3 {
 | 
								if parts := strings.Fields(l); len(parts) >= 3 {
 | 
				
			||||||
				if parts[0] != "-" {
 | 
									if parts[0] != "-" {
 | 
				
			||||||
| 
						 | 
					@ -100,9 +116,19 @@ func (repo *Repository) GetCodeActivityStats(fromTime time.Time, branch string)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						a := make([]*CodeActivityAuthor, 0, len(authors))
 | 
				
			||||||
 | 
						for _, v := range authors {
 | 
				
			||||||
 | 
							a = append(a, v)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// Sort authors descending depending on commit count
 | 
				
			||||||
 | 
						sort.Slice(a, func(i, j int) bool {
 | 
				
			||||||
 | 
							return a[i].Commits > a[j].Commits
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	stats.AuthorCount = int64(len(authors))
 | 
						stats.AuthorCount = int64(len(authors))
 | 
				
			||||||
	stats.ChangedFiles = int64(len(files))
 | 
						stats.ChangedFiles = int64(len(files))
 | 
				
			||||||
	stats.Authors = authors
 | 
						stats.Authors = a
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return stats, nil
 | 
						return stats, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,7 +31,7 @@ func TestRepository_GetCodeActivityStats(t *testing.T) {
 | 
				
			||||||
	assert.EqualValues(t, 10, code.Additions)
 | 
						assert.EqualValues(t, 10, code.Additions)
 | 
				
			||||||
	assert.EqualValues(t, 1, code.Deletions)
 | 
						assert.EqualValues(t, 1, code.Deletions)
 | 
				
			||||||
	assert.Len(t, code.Authors, 3)
 | 
						assert.Len(t, code.Authors, 3)
 | 
				
			||||||
	assert.Contains(t, code.Authors, "tris.git@shoddynet.org")
 | 
						assert.EqualValues(t, "tris.git@shoddynet.org", code.Authors[1].Email)
 | 
				
			||||||
	assert.EqualValues(t, 3, code.Authors["tris.git@shoddynet.org"])
 | 
						assert.EqualValues(t, 3, code.Authors[1].Commits)
 | 
				
			||||||
	assert.EqualValues(t, 5, code.Authors[""])
 | 
						assert.EqualValues(t, 5, code.Authors[0].Commits)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -182,6 +182,13 @@ func NewFuncMap() []template.FuncMap {
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return path
 | 
								return path
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
							"Json": func(in interface{}) string {
 | 
				
			||||||
 | 
								out, err := json.Marshal(in)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return ""
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return string(out)
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
		"JsonPrettyPrint": func(in string) string {
 | 
							"JsonPrettyPrint": func(in string) string {
 | 
				
			||||||
			var out bytes.Buffer
 | 
								var out bytes.Buffer
 | 
				
			||||||
			err := json.Indent(&out, []byte(in), "", "  ")
 | 
								err := json.Indent(&out, []byte(in), "", "  ")
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										1206
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										1206
									
								
								package-lock.json
									
										
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -5,10 +5,12 @@
 | 
				
			||||||
    "node": ">=10"
 | 
					    "node": ">=10"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "swagger-ui": "3.24.3"
 | 
					    "swagger-ui": "3.24.3",
 | 
				
			||||||
 | 
					    "vue-bar-graph": "1.2.0"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
    "@babel/core": "7.7.7",
 | 
					    "@babel/core": "7.7.7",
 | 
				
			||||||
 | 
					    "@babel/plugin-proposal-object-rest-spread": "7.7.7",
 | 
				
			||||||
    "@babel/plugin-transform-runtime": "7.7.6",
 | 
					    "@babel/plugin-transform-runtime": "7.7.6",
 | 
				
			||||||
    "@babel/preset-env": "7.7.7",
 | 
					    "@babel/preset-env": "7.7.7",
 | 
				
			||||||
    "@babel/runtime": "7.7.7",
 | 
					    "@babel/runtime": "7.7.7",
 | 
				
			||||||
| 
						 | 
					@ -27,6 +29,8 @@
 | 
				
			||||||
    "stylelint-config-standard": "19.0.0",
 | 
					    "stylelint-config-standard": "19.0.0",
 | 
				
			||||||
    "terser-webpack-plugin": "2.3.2",
 | 
					    "terser-webpack-plugin": "2.3.2",
 | 
				
			||||||
    "updates": "9.3.3",
 | 
					    "updates": "9.3.3",
 | 
				
			||||||
 | 
					    "vue-loader": "15.8.3",
 | 
				
			||||||
 | 
					    "vue-template-compiler": "2.6.11",
 | 
				
			||||||
    "webpack": "4.41.5",
 | 
					    "webpack": "4.41.5",
 | 
				
			||||||
    "webpack-cli": "3.3.10"
 | 
					    "webpack-cli": "3.3.10"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -59,6 +59,11 @@ func Activity(ctx *context.Context) {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ctx.Data["ActivityTopAuthors"], err = models.GetActivityStatsTopAuthors(ctx.Repo.Repository, timeFrom, 10); err != nil {
 | 
				
			||||||
 | 
							ctx.ServerError("GetActivityStatsTopAuthors", err)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx.HTML(200, tplActivity)
 | 
						ctx.HTML(200, tplActivity)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -108,6 +108,12 @@
 | 
				
			||||||
						{{.i18n.Tr "repo.activity.git_stats_and_deletions" }}
 | 
											{{.i18n.Tr "repo.activity.git_stats_and_deletions" }}
 | 
				
			||||||
						<strong class="text red">{{.i18n.Tr (TrN .i18n.Lang .Activity.Code.Deletions "repo.activity.git_stats_deletion_1" "repo.activity.git_stats_deletion_n") .Activity.Code.Deletions }}</strong>.
 | 
											<strong class="text red">{{.i18n.Tr (TrN .i18n.Lang .Activity.Code.Deletions "repo.activity.git_stats_deletion_1" "repo.activity.git_stats_deletion_n") .Activity.Code.Deletions }}</strong>.
 | 
				
			||||||
					</div>
 | 
										</div>
 | 
				
			||||||
 | 
										<div class="ui attached segment" id="app">
 | 
				
			||||||
 | 
											<script type="text/javascript">
 | 
				
			||||||
 | 
											var ActivityTopAuthors = {{Json .ActivityTopAuthors | SafeJS}};
 | 
				
			||||||
 | 
											</script>
 | 
				
			||||||
 | 
											<activity-top-authors :data="activityTopAuthors" />
 | 
				
			||||||
 | 
										</div>
 | 
				
			||||||
				</div>
 | 
									</div>
 | 
				
			||||||
			{{end}}
 | 
								{{end}}
 | 
				
			||||||
		{{end}}
 | 
							{{end}}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										102
									
								
								web_src/js/components/ActivityTopAuthors.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								web_src/js/components/ActivityTopAuthors.vue
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,102 @@
 | 
				
			||||||
 | 
					<template>
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					        <div class="activity-bar-graph" ref="style" style="width:0px;height:0px"></div>
 | 
				
			||||||
 | 
					        <div class="activity-bar-graph-alt" ref="altStyle" style="width:0px;height:0px"></div>
 | 
				
			||||||
 | 
					        <vue-bar-graph
 | 
				
			||||||
 | 
					            :points="graphData"
 | 
				
			||||||
 | 
					            :show-x-axis="true"
 | 
				
			||||||
 | 
					            :show-y-axis="false"
 | 
				
			||||||
 | 
					            :show-values="true"
 | 
				
			||||||
 | 
					            :width="graphWidth"
 | 
				
			||||||
 | 
					            :bar-color="colors.barColor"
 | 
				
			||||||
 | 
					            :text-color="colors.textColor"
 | 
				
			||||||
 | 
					            :text-alt-color="colors.textAltColor"
 | 
				
			||||||
 | 
					            :height="100"
 | 
				
			||||||
 | 
					            :label-height="20"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					            <template v-slot:label="opt">
 | 
				
			||||||
 | 
					                <g v-for="(author, idx) in authors" :key="author.position">
 | 
				
			||||||
 | 
					                    <a
 | 
				
			||||||
 | 
					                        v-if="opt.bar.index === idx && author.home_link !== ''"
 | 
				
			||||||
 | 
					                        :href="author.home_link"
 | 
				
			||||||
 | 
					                    >
 | 
				
			||||||
 | 
					                        <image
 | 
				
			||||||
 | 
					                            :x="`${opt.bar.midPoint - 10}px`"
 | 
				
			||||||
 | 
					                            :y="`${opt.bar.yLabel}px`"
 | 
				
			||||||
 | 
					                            height="20"
 | 
				
			||||||
 | 
					                            width="20"
 | 
				
			||||||
 | 
					                            :href="author.avatar_link"
 | 
				
			||||||
 | 
					                        />
 | 
				
			||||||
 | 
					                    </a>
 | 
				
			||||||
 | 
					                    <image
 | 
				
			||||||
 | 
					                        v-else-if="opt.bar.index === idx"
 | 
				
			||||||
 | 
					                        :x="`${opt.bar.midPoint - 10}px`"
 | 
				
			||||||
 | 
					                        :y="`${opt.bar.yLabel}px`"
 | 
				
			||||||
 | 
					                        height="20"
 | 
				
			||||||
 | 
					                        width="20"
 | 
				
			||||||
 | 
					                        :href="author.avatar_link"
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
 | 
					                </g>
 | 
				
			||||||
 | 
					            </template>
 | 
				
			||||||
 | 
					            <template v-slot:title="opt">
 | 
				
			||||||
 | 
					                <tspan v-for="(author, idx) in authors" :key="author.position"><tspan v-if="opt.bar.index === idx">{{ author.name }}</tspan></tspan>
 | 
				
			||||||
 | 
					            </template>
 | 
				
			||||||
 | 
					        </vue-bar-graph>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					import VueBarGraph from 'vue-bar-graph';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default {
 | 
				
			||||||
 | 
					    components: {
 | 
				
			||||||
 | 
					        VueBarGraph,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    props: {
 | 
				
			||||||
 | 
					        data: { type: Array, default: () => [] },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    mounted() {
 | 
				
			||||||
 | 
					        const st = window.getComputedStyle(this.$refs.style);
 | 
				
			||||||
 | 
					        const stalt = window.getComputedStyle(this.$refs.altStyle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.colors.barColor = st.backgroundColor;
 | 
				
			||||||
 | 
					        this.colors.textColor = st.color;
 | 
				
			||||||
 | 
					        this.colors.textAltColor = stalt.color;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    data() {
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					            colors: {
 | 
				
			||||||
 | 
					                barColor: 'green',
 | 
				
			||||||
 | 
					                textColor: 'black',
 | 
				
			||||||
 | 
					                textAltColor: 'white',
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    computed: {
 | 
				
			||||||
 | 
					        graphData() {
 | 
				
			||||||
 | 
					            return this.data.map((item) => {
 | 
				
			||||||
 | 
					                return {
 | 
				
			||||||
 | 
					                    value: item.commits,
 | 
				
			||||||
 | 
					                    label: item.name,
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        authors() {
 | 
				
			||||||
 | 
					            return this.data.map((item, idx) => {
 | 
				
			||||||
 | 
					                return {
 | 
				
			||||||
 | 
					                    position: idx+1,
 | 
				
			||||||
 | 
					                    ...item,
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        graphWidth() {
 | 
				
			||||||
 | 
					            return this.data.length * 40;
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    methods: {
 | 
				
			||||||
 | 
					        hasHomeLink(i) {
 | 
				
			||||||
 | 
					            return this.graphData[i].homeLink !== '' && this.graphData[i].homeLink !== null;
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
| 
						 | 
					@ -7,6 +7,8 @@ import './gitGraphLoader.js';
 | 
				
			||||||
import './semanticDropdown.js';
 | 
					import './semanticDropdown.js';
 | 
				
			||||||
import initContextPopups from './features/contextPopup';
 | 
					import initContextPopups from './features/contextPopup';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import ActivityTopAuthors from './components/ActivityTopAuthors.vue';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function htmlEncode(text) {
 | 
					function htmlEncode(text) {
 | 
				
			||||||
  return jQuery('<div />').text(text).html();
 | 
					  return jQuery('<div />').text(text).html();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -2894,9 +2896,13 @@ function initVueApp() {
 | 
				
			||||||
    delimiters: ['${', '}'],
 | 
					    delimiters: ['${', '}'],
 | 
				
			||||||
    el,
 | 
					    el,
 | 
				
			||||||
    data: {
 | 
					    data: {
 | 
				
			||||||
      searchLimit: document.querySelector('meta[name=_search_limit]').content,
 | 
					      searchLimit: (document.querySelector('meta[name=_search_limit]') || {}).content,
 | 
				
			||||||
      suburl: document.querySelector('meta[name=_suburl]').content,
 | 
					      suburl: document.querySelector('meta[name=_suburl]').content,
 | 
				
			||||||
      uid: Number(document.querySelector('meta[name=_context_uid]').content),
 | 
					      uid: Number((document.querySelector('meta[name=_context_uid]') || {}).content),
 | 
				
			||||||
 | 
					      activityTopAuthors: window.ActivityTopAuthors || [],
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    components: {
 | 
				
			||||||
 | 
					      ActivityTopAuthors,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -999,6 +999,15 @@ footer {
 | 
				
			||||||
    background-color: #025900;
 | 
					    background-color: #025900;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.activity-bar-graph {
 | 
				
			||||||
 | 
					    background-color: #6cc644;
 | 
				
			||||||
 | 
					    color: #000000;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.activity-bar-graph-alt {
 | 
				
			||||||
 | 
					    color: #000000;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.archived-icon {
 | 
					.archived-icon {
 | 
				
			||||||
    color: lighten(#000000, 70%) !important;
 | 
					    color: lighten(#000000, 70%) !important;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1353,6 +1353,11 @@ a.ui.labels .label:hover {
 | 
				
			||||||
    .heatmap(100%);
 | 
					    .heatmap(100%);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.activity-bar-graph {
 | 
				
			||||||
 | 
					    background-color: #a0cc75;
 | 
				
			||||||
 | 
					    color: #9e9e9e;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* code mirror dark theme */
 | 
					/* code mirror dark theme */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.CodeMirror {
 | 
					.CodeMirror {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
const path = require('path');
 | 
					const path = require('path');
 | 
				
			||||||
const TerserPlugin = require('terser-webpack-plugin');
 | 
					const TerserPlugin = require('terser-webpack-plugin');
 | 
				
			||||||
const { SourceMapDevToolPlugin } = require('webpack');
 | 
					const { SourceMapDevToolPlugin } = require('webpack');
 | 
				
			||||||
 | 
					const VueLoaderPlugin = require('vue-loader/lib/plugin');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module.exports = {
 | 
					module.exports = {
 | 
				
			||||||
  mode: 'production',
 | 
					  mode: 'production',
 | 
				
			||||||
| 
						 | 
					@ -28,6 +29,11 @@ module.exports = {
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  module: {
 | 
					  module: {
 | 
				
			||||||
    rules: [
 | 
					    rules: [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        test: /\.vue$/,
 | 
				
			||||||
 | 
					        exclude: /node_modules/,
 | 
				
			||||||
 | 
					        loader: 'vue-loader'
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        test: /\.js$/,
 | 
					        test: /\.js$/,
 | 
				
			||||||
        exclude: /node_modules/,
 | 
					        exclude: /node_modules/,
 | 
				
			||||||
| 
						 | 
					@ -49,7 +55,8 @@ module.exports = {
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                  regenerator: true,
 | 
					                  regenerator: true,
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
              ]
 | 
					              ],
 | 
				
			||||||
 | 
					              '@babel/plugin-proposal-object-rest-spread',
 | 
				
			||||||
            ],
 | 
					            ],
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -61,6 +68,7 @@ module.exports = {
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  plugins: [
 | 
					  plugins: [
 | 
				
			||||||
 | 
					    new VueLoaderPlugin(),
 | 
				
			||||||
    new SourceMapDevToolPlugin({
 | 
					    new SourceMapDevToolPlugin({
 | 
				
			||||||
      filename: '[name].js.map',
 | 
					      filename: '[name].js.map',
 | 
				
			||||||
      exclude: [
 | 
					      exclude: [
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue