add cncf and redesign

Change-Id: I564bee5e74153fe6897361bcfa023546bf859034
This commit is contained in:
Jim Phillips 2019-01-23 15:43:44 -05:00
parent ab22641d51
commit 9f6fff8bb8
40 changed files with 3522 additions and 643 deletions

File diff suppressed because it is too large Load Diff

View File

@ -30,10 +30,10 @@ INFINITY_HTML = '∞'
def _extend_author_fields(record):
record['author_link'] = make_link(
record['author_name'], '/',
record['author_name'], '',
{'user_id': record['user_id'], 'company': ''})
record['company_link'] = make_link(
record['company_name'], '/',
record['company_name'], '',
{'company': record['company_name'], 'user_id': ''})
@ -41,7 +41,7 @@ def _extend_record_common_fields(record):
_extend_author_fields(record)
record['date_str'] = format_datetime(record['date'])
record['module_link'] = make_link(
record['module'], '/',
record['module'], '',
{'module': record['module'], 'company': '', 'user_id': ''})
record['blueprint_id_count'] = len(record.get('blueprint_id', []))
record['bug_id_count'] = len(record.get('bug_id', []))
@ -124,7 +124,7 @@ def extend_user(user):
if user['companies']:
company_name = get_current_company(user)
user['company_link'] = make_link(
company_name, '/', {'company': company_name, 'user_id': ''})
company_name, '', {'company': company_name, 'user_id': ''})
else:
user['company_link'] = ''
@ -286,7 +286,7 @@ def make_link(title, uri=None, options=None):
if param_values:
uri += '?' + '&'.join(['%s=%s' % (n, utils.safe_encode(v))
for n, v in six.iteritems(param_values)])
return '<a href="%(uri)s">%(title)s</a>' % {'uri': uri, 'title': title}
return {'uri': uri, 'title': title}
def make_blueprint_link(module, name):

View File

@ -1,9 +1,10 @@
html, body {
font-family: 'PT Sans', arial, sans-serif;
font-family: 'Roboto', sans-serif;
font-size: 14px;
height: 100%;
color: #41454d;
margin: 0;
background: #fff;
}
a {
@ -22,13 +23,9 @@ p {
margin: 6px 0px 15px 0px;
}
div.page {
width: 960px;
margin: 0 auto;
}
h2 {
font-family: 'PT Sans Narrow', 'Arial Narrow', arial, sans-serif;
font-family: 'Roboto', sans-serif;
font-size: 23px;
font-weight: normal;
font-style: normal;
@ -38,7 +35,7 @@ h2 {
}
h3 {
font-family: 'PT Sans Narrow', 'Arial Narrow', arial, sans-serif;
font-family: 'Roboto', sans-serif;
font-size: 19px;
font-weight: normal;
font-style: normal;
@ -47,7 +44,7 @@ h3 {
}
h4 {
font-family: 'PT Sans Narrow', 'Arial Narrow', arial, sans-serif;
font-family: 'Roboto', sans-serif;
font-size: 16px;
font-weight: bold;
font-style: normal;
@ -88,26 +85,15 @@ input[type="submit"] {
}
div.drops {
height: 60px;
margin-top: 10px;
margin-bottom: 25px;
}
div.drop label {
color: #909cb5;
}
.drop {
height: 30px;
float: left;
margin-right: 23px;
}
.drop:last-child {
margin-right: 0;
}
.drop label {
display: block;
.drops label {
color: #90a4b7;
font-weight: 300;
text-transform: uppercase;
white-space: nowrap;
}
div.aheader {
@ -130,12 +116,10 @@ div.aheader h1 a {
}
div.page div.navigation {
text-shadow: 1px 1px 0 #fff;
padding: 4px 10px;
border-top: 1px dashed #e9eaef;
border-bottom: 1px dashed #e9eaef;
color: #909cb5;
font-size: 10pt;
padding: 10px;
margin: 35px 0 5px;
background: #fff;
box-shadow: 0px 0px 20px 0px rgba(0,0,0,0.1);
}
div.page div.navigation a {
@ -215,8 +199,17 @@ a[target]:not([target='']):after, .ext_link:after {
opacity: 0.3;
}
#analytics_header a:after {
content: "";
opacity: 1;
}
#analytics_header {
position: relative;
}
#analytics_header #logo {
font-family: 'PT Sans', 'Arial Narrow', arial, sans-serif;
font-family: 'Roboto', sans-serif;
font-weight: bolder;
font-style: normal;
font-size: 30px;
@ -226,6 +219,14 @@ a[target]:not([target='']):after, .ext_link:after {
padding-right: 10px;
}
#analytics_header #logo {
margin-top: 18px;
}
#analytics_header #logo a img {
max-width: 100%;
}
#analytics_header #slogan {
font-family: georgia, serif;
font-weight: lighter;
@ -406,75 +407,180 @@ body .ui-tooltip {
opacity: 0.8;
}
/* new top menu */
ul#menu-stackamenu {
margin: 0;
padding: 0;
list-style-image: none;
list-style-type: none;
font-family: 'PT Sans Narrow', arial, sans-serif;
div#company_container,
div#engineer_container,
div#module_container,
div#module_details_container,
div#contribution_container,
div#user_profile_container,
div#activity_container,
div#users_table_wrapper,
div#companies_container,
div#individuals_container,
div#new_compaines_container,
div#affiliation_container,
div#members_container {
background: #fff;
margin: 25px 0;
border: 1px solid #d9d9e2;
padding: 30px;
}
ul#menu-stackamenu li {
/*
div#company_container table.dataTable.display tbody td,
div#engineer_container table.dataTable.display tbody td,
div#module_container table.dataTable.display tbody td,
div#module_details_container table.dataTable.display tbody td,
div#contribution_container table.dataTable.display tbody td,
div#user_profile_container table.dataTable.display tbody td,
div#activity_container table.dataTable.display tbody td,
div#users_table_wrapper table.dataTable.display tbody td,
div#companies_container table.dataTable.display tbody td,
div#individuals_container table.dataTable.display tbody td,
div#new_compaines_container table.dataTable.display tbody td,
div#affiliation_container table.dataTable.display tbody td,
div#members_container table.dataTable.display tbody td {
white-space: nowrap;
}
*/
div#company_container .pad,
div#engineer_container .pad,
div#module_container .pad,
div#module_details_container .pad,
div#contribution_container .pad,
div#user_profile_container .pad,
div#activity_container .pad,
div#users_table_wrapper .pad,
div#companies_container .pad,
div#individuals_container .pad,
div#new_compaines_container .pad,
div#affiliation_container .pad,
div#members_container .pad {
padding: 15px;
}
div#affiliation_container > div#users_table_wrapper {
box-shadow: none;
}
div#company_container h2,
div#engineer_container h2,
div#module_container h2,
div#module_details_container h2,
div#contribution_container h2,
div#user_profile_container h2,
div#activity_container h2,
div#companies_container h2,
div#individuals_container h2,
div#new_compaines_container h2,
div#members_container h2 {
color: #1c1c1c;
margin-bottom: 35px;
}
#company_chart, #module_chart {
padding-top: 0;
width:100%;
min-height: 450px;
}
@media (max-width: 1199px) {
#company_chart, #module_chart {
padding-top: 0;
}
div#company_container h2,
div#engineer_container h2,
div#module_container h2,
div#module_details_container h2,
div#contribution_container h2,
div#user_profile_container h2,
div#activity_container h2,
div#companies_container h2,
div#individuals_container h2,
div#new_compaines_container h2,
div#members_container h2 {
text-align: center;
}
}
div#affiliation_container h1 {
margin-bottom: 25px;
}
div#footer_container {
background: #fff;
margin: 25px 0;
padding: 15px;
font-size: smaller;
}
/* new top menu */
#menu-stackamenu {
margin: 0;
padding: 0;
display: inline-block;
font-family: 'Roboto', sans-serif;
}
div.stackamenu {
text-align: left;
padding-bottom: 10px;
margin-left: 240px;
margin: 15px 0 30px;
}
div.stackamenu a {
#menu-stackamenu li a {
display: inline-block;
color: #972D24;
border-radius: 0;
color: #55575c;
font-size: 18px;
/*text-transform: uppercase;*/
margin: 5px 0;
padding: 5px 20px;
background: #eceef3;
/*box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.7);*/
padding: 10px;
font-weight: 300;
margin: 0 15px;
}
div.stackamenu a span {
color: #943a3a;
#menu-stackamenu li a span {
color: #55575c;
font-size: 110%;
position: relative;
top: 2px;
margin-right: 10px;
}
div.stackamenu a:hover {
background: #c8e7ed;
/*color: white;*/
#menu-stackamenu li a:hover, #menu-stackamenu li a:active, #menu-stackamenu li a:focus {
text-decoration: none;
border-bottom: 2px solid #ed1944;
}
div.stackamenu a:hover span {
#menu-stackamenu li a:hover span {
/*background: #c8e7ed;*/
/*color: white;*/
/*text-shadow: 0 -1px 0 #2c96c5;*/
}
div.stackamenu li.current-menu-item a {
background: #4bb2c5;
color: white;
/*box-shadow: 0 3px 0 #436281;*/
a.about {
color: #16c3de;
text-transform: lowercase;
border: 2px solid white;
border-radius: 20px;
padding: 2px 10px;
font-size: smaller;
position: absolute;
top: 30px;
}
div.stackamenu li.current-menu-item a:hover {
a.about:hover, a.about:active, a.about:focus {
background: #16c3de;
color: #fff;
border-color: #16c3de;
}
#menu-stackamenu .current-menu-item a {
border-bottom: 2px solid #ed1944;
}
#menu-stackamenu li .current-menu-item a:hover, #menu-stackamenu li .current-menu-item a:active, #menu-stackamenu li .current-menu-item a:focus {
background: #4bb2c5;
text-decoration: none;
/*color: white;*/
/*box-shadow: 0 3px 0 #2b99ca;*/
}
div.stackamenu li.current-menu-item a span {
color: white;
/*text-shadow: 0 -1px 0 #436281;*/
}
.select2-loading {
font-style: italic;
color: dimgray;
@ -506,4 +612,512 @@ div.stackamenu li.current-menu-item a span {
.disabled {
color: grey;
}
}
table.dataTable tbody tr {
background-color: #f6fafd;
font-weight: 300;
}
table.dataTable tbody tr a {
color: #727272;
}
table.dataTable.display tbody tr.even>.sorting_1, table.dataTable.order-column.stripe tbody tr.even>.sorting_1 {
background-color: #edf4fc;
}
table.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd {
background-color: #fff;
}
table.dataTable.display tbody tr.odd>.sorting_1, table.dataTable.order-column.stripe tbody tr.odd>.sorting_1 {
background-color: #f5fafe;
}
table.dataTable.display tbody tr td:first-child {
color: #c2d3dc;
}
table.dataTable.display tbody tr td:last-child {
color: #9da2a6;
}
table.dataTable.no-footer {
border-bottom: none;
}
table.dataTable thead th, table.dataTable thead td {
padding: 10px 18px;
border-bottom: 3px solid #e7f3fe;
}
.dataTables_filter, .dataTables_length, .dataTables_paginate {
display: inline-block;
}
.dataTables_paginate .paginate_button {
/* border: none;
border-radius: 50%; */
}
.dataTables_paginate .paginate_button:hover {
/* color: #000 !important;
border: none;
background-color: #fff;
background: #fff;
box-shadow: 0px 1px 1px 1px rgba(0,0,0,.3) inset; */
}
.dataTables_paginate .paginate_button:active {
/* outline: none;
background-color: #16c3de;
background: #16c3de;
box-shadow: none; */
}
.dataTables_paginate .paginate_button.current, .dataTables_paginate .paginate_button.current:hover {
/* color: #fff !important;
border: none;
background-color: #14c3de;
background: #14c3de;
border-radius: 50%;
transition: box-shadow 0.2s cubic-bezier(0.4, 0, 0.2, 1);
transition-delay: 0.2s;
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.26); */
font-weight: bold;
}
.select2-container--material {
width: 100% !important;
/**
* Textbox
*/
/**
* Dropdown
*/
/**
* Options
*/
/**
* Focused textbox
*/
/**
* Disabled textbox
*/
}
.select2-container--material ::-webkit-input-placeholder {
color: inherit;
}
.select2-container--material :-ms-input-placeholder {
color: inherit;
}
.select2-container--material :-ms-input-placeholder {
color: inherit;
}
.select2-container--material ::placeholder {
color: inherit;
}
.select2-container--material .select2-selection {
/* @extend input */
overflow: visible;
font: inherit;
touch-action: manipulation;
margin: 0;
line-height: inherit;
border-radius: 0;
box-sizing: inherit;
/* @extend .form-control */
display: block;
width: 100%;
color: #55595c;
background-clip: padding-box;
border: 1px solid rgba(0, 0, 0, 0.15);
padding: .5rem 0 .6rem;
font-size: 1rem;
line-height: 1.5;
background-color: transparent;
background-image: none;
border-radius: 0;
margin-top: .2rem;
margin-bottom: 1rem;
/* @extend input[type=text] */
background-color: transparent;
border: none;
border-bottom: 1px solid #ccc;
border-radius: 0;
outline: 0;
width: 100%;
font-size: 1rem;
box-shadow: none;
transition: all .3s;
min-height: 2.1rem;
}
.select2-container--material .select2-selection .select2-selection__rendered {
padding-left: 0;
}
.select2-container--material .select2-selection--single .select2-selection__rendered {
float: left;
}
.select2-container--material .select2-selection--single .select2-selection__arrow {
float: right;
}
.select2-container--material .select2-selection--multiple {
/**
* Multiple selected options
*/
/**
* Multiple selected option clear button
*/
}
.select2-container--material .select2-selection--multiple .select2-selection__rendered {
width: 100%;
}
.select2-container--material .select2-selection--multiple .select2-selection__rendered li {
list-style: none;
}
.select2-container--material .select2-selection--multiple .select2-selection__choice {
/* @extend .mdl-chip */
height: 32px;
line-height: 32px;
padding: 0 12px;
border: 0;
border-radius: 16px;
background-color: #dedede;
display: inline-block;
color: rgba(0, 0, 0, 0.87);
margin: 2px 0;
font-size: 0;
white-space: nowrap;
/* @extend .mdl-chip__text */
font-size: 13px;
vertical-align: middle;
display: inline-block;
float: left;
margin-right: 8px;
margin-bottom: 4px;
}
.select2-container--material .select2-selection--multiple .select2-selection__choice__remove {
/* Hide default content */
font-size: 0;
opacity: 0.38;
cursor: pointer;
float: right;
margin-top: 4px;
margin-right: -6px;
margin-left: 6px;
transition: opacity;
}
.select2-container--material .select2-selection--multiple .select2-selection__choice__remove::before {
content: "cancel";
/* @extend .material-icons */
font-family: 'Material Icons';
font-weight: normal;
font-style: normal;
font-size: 24px;
line-height: 1;
letter-spacing: normal;
text-transform: none;
display: inline-block;
white-space: nowrap;
word-wrap: normal;
direction: ltr;
-webkit-font-feature-settings: 'liga';
-webkit-font-smoothing: antialiased;
color: #000;
}
.select2-container--material .select2-selection--multiple .select2-selection__choice__remove:hover {
opacity: 0.54;
}
.select2-container--material .select2-search--inline .select2-search__field {
width: 100%;
margin-top: 0;
/* Match input[type=text] */
height: 34px;
line-height: 1;
}
.select2-container--material .select2-dropdown {
border: 0;
}
.select2-container--material .select2-dropdown .select2-search__field {
min-height: 2.1rem;
margin-bottom: 16px;
border: 0;
border-bottom: 1px solid #ccc;
transition: all .3s;
}
.select2-container--material .select2-dropdown .select2-search__field:focus {
border-bottom: 1px solid #4285f4;
box-shadow: 0 1px 0 0 #4585f4;
}
.select2-container--material .select2-results__options {
/* @extend .zf-shadow-depth* */
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
/* @extend .dropdown-content */
background-color: #fff;
margin: 0;
min-width: 100px;
max-height: 650px;
overflow-y: auto;
z-index: 999;
will-change: width,height;
/* @extend .dropdown-content inline styles */
}
.select2-container--material .select2-results__option {
/* @extend .dropdown-content li */
cursor: pointer;
clear: both;
color: rgba(0, 0, 0, 0.87);
line-height: 1.5rem;
text-align: left;
text-transform: none;
/* @extend .dropdown-content li>a, .dropdown-content li>span */
font-size: 1.2rem;
display: block;
padding: 1rem;
/**
* Disabled options
*/
/**
* Selected option
*/
/**
* Active/hovered option
*/
}
.select2-container--material .select2-results__option[aria-disabled=true] {
/* @extend .select-dropdown li.disabled */
color: rgba(0, 0, 0, 0.3);
background-color: transparent !important;
cursor: context-menu;
/* @extend .disabled */
cursor: not-allowed;
}
.select2-container--material .select2-results__option[aria-selected=true] {
/* @extend .dropdown-content li:active, .dropdow-content li:hover */
color: #4285f4;
background-color: #eee;
}
.select2-container--material .select2-results__option--highlighted[aria-selected] {
background-color: #ddd;
}
.select2-container--material.select2-container--focus .select2-selection {
/* @extend input[type=text]:focus */
border-bottom: 1px solid #4285f4;
box-shadow: 0 1px 0 0 #4585f4;
}
.select2-container--material.select2-container--disabled .select2-selection {
/* @extend .select-wrapper input.select-dropdown:disabled */
color: rgba(0, 0, 0, 0.3);
cursor: default;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
border-bottom: 1px solid rgba(0, 0, 0, 0.3);
}
.select2-container--material.select2-container--disabled.select2-container--focus .select2-selection {
box-shadow: none;
}
span.chartColor {
height: 10px;
width: 10px;
display: inline-block;
margin-right: 5px;
border-radius: 50%;
}
.dataTables_filter, .dataTables_length, .dataTables_paginate {
display: inline-block;
float: right;
}
.container_footer {
/* background: #f2f3f7;
background: -moz-linear-gradient(top, #f2f3f7 0%, #f4f2f6 100%);
background: -webkit-linear-gradient(top, #f2f3f7 0%,#f4f2f6 100%);
background: linear-gradient(to bottom, #f2f3f7 0%,#f4f2f6 100%);
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f2f3f7', endColorstr='#f4f2f6',GradientType=0 );
*/
padding: 15px;
}
@media (min-width: 576px) {
.container-fluid {
max-width: 540px;
}
}
@media (min-width: 768px) {
.container-fluid {
max-width: 720px;
}
}
@media (min-width: 992px) {
.container-fluid {
max-width: 960px;
}
}
@media (min-width: 1260px) {
.container-fluid {
max-width: 1140px;
}
}
@media (min-width: 1480px) {
.container-fluid {
max-width: 100%;
}
.container-fluid-padding { padding: 0 60px; }
}
.dataTables_length label {
/* color: #bacbd6; */
}
.dataTables_length label select {
/* background: #fff;
padding: 5px;
color: #4abed5;
border: none;
margin-left: 5px; */
}
#engineer_table tbody tr td:nth-child(3) {
color: #c97b7a;
}
#engineer_table tbody tr td:nth-child(4) {
color: #d1c17d;
}
#engineer_table tbody tr td:nth-child(5) {
color: #b1c361;
}
#engineer_table tbody tr td:nth-child(6) {
color: #9dd493;
}
#engineer_table tbody tr td:nth-child(7) {
color: #195d15;
}
#engineer_table tbody tr td:nth-child(8) {
color: #940e0d;
}
#engineer_table tbody tr td:nth-child(9) span {
color: #fff;
background: #05b175;
border-radius: 50%;
padding: 8px 4px;
font-size: smaller;
display: inline-block;
height: 30px;
width: 30px;
text-align: center;
}
#engineer_table tbody tr td:nth-child(9) span.red {
background: red;
}
.dataTables_filter input[type="search"] {
padding: 5px;
border: 1px solid #ccc;
max-width: 150px;
}
.dataTables_filter input[type="search"]::placeholder {
/* color: #c5d9e4; */
}
.dataTables_paginate .paginate_button {
border: none;
border-radius: 50%;
display: inline-block;
padding: 3px 10px;
cursor: pointer;
margin: 0 2px;
color: #aec4d0;
}
.dataTables_paginate .paginate_button:hover, .dataTables_paginate .paginate_button:active .dataTables_paginate .paginate_button:focus {
text-decoration: none;
color: #aec4d0;
}
.dataTables_paginate {
/* text-align: right; */
}
table.dataTable tbody th, table.dataTable tbody td {
padding: 5px 10px;
}
table.dataTable tbody tr td:nth-child(1) {
padding: 5px;
}
table.dataTable thead .sorting {
background: none;
padding: 4px 2px 4px 10px;
background: #00c3e0;
color: #fff;
}
table.dataTable thead .sorting_desc, table.dataTable thead .sorting_asc {
background: none;
padding: 4px 2px 4px 4px;
background: #00c3e0;
color: #fff;
}
table.dataTable thead .sorting:nth-of-type(1) {
padding: 4px 2px 4px 5px;
}
.select2-drop, .select2-container .select2-choice {
border-radius: 0;
}
.select2-container .select2-choice {
height: 30px;
line-height: 30px;
background: #fff;
background-image: none;
border: 1px solid #c6c2c2;
}
.select2-container .select2-dropdown-open .select2-choice {
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, white), color-stop(0.5, #eeeeee));
background-image: -webkit-linear-gradient(center bottom, white 0%, #eeeeee 50%);
background-image: -moz-linear-gradient(center bottom, white 0%, #eeeeee 50%);
background-image: -o-linear-gradient(bottom, white 0%, #eeeeee 50%);
background-image: -ms-linear-gradient(top, #ffffff 0%,#eeeeee 50%);
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#eeeeee', endColorstr='#ffffff',GradientType=0 );
background-image: linear-gradient(top, #ffffff 0%,#eeeeee 50%);
}
.select2-container .select2-choice .select2-arrow {
background: #f5f5f5;
background-image: none;
border-radius: 0;
border-left: 1px solid #c6c2c2;
width: 23px;
}
.select2-container.select2-dropdown-open .select2-choice .select2-arrow {
background: transparent;
border-left: 1px solid transparent;
}
.select2-container .select2-choice .select2-arrow b {
background-position-x: 3px;
}
.select2-drop-active, .select2-container-active .select2-choice, .select2-container-active .select2-choices {
border-color: #00c3e0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square150x150logo src="/mstile-150x150.png"/>
<TileColor>#603cba</TileColor>
</tile>
</msapplication>
</browserconfig>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

@ -0,0 +1,24 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="300.000000pt" height="300.000000pt" viewBox="0 0 300.000000 300.000000"
preserveAspectRatio="xMidYMid meet">
<metadata>
Created by potrace 1.11, written by Peter Selinger 2001-2013
</metadata>
<g transform="translate(0.000000,300.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M815 2649 c-253 -149 -522 -307 -597 -352 l-138 -82 0 -105 c-2 -844
1 -1324 7 -1330 4 -4 201 -121 438 -260 384 -226 641 -378 731 -431 l30 -18
425 250 c233 138 437 258 453 268 16 9 36 21 45 26 9 6 76 45 149 88 72 43
132 81 132 85 -1 4 -87 57 -193 119 -106 61 -277 162 -382 224 -104 62 -284
168 -400 236 -115 68 -211 127 -213 131 -2 6 87 61 242 150 23 13 61 36 86 51
25 16 101 61 170 101 69 40 179 105 245 145 66 39 193 113 282 165 90 52 163
98 163 101 0 4 -33 26 -72 49 -40 24 -158 94 -263 155 -732 433 -857 505 -868
505 -7 0 -220 -122 -472 -271z"/>
<path d="M2735 2101 c-99 -59 -308 -183 -465 -276 -157 -92 -345 -203 -418
-247 l-133 -80 213 -125 c280 -165 548 -323 790 -467 108 -64 199 -116 202
-116 3 0 6 320 6 710 0 391 -3 710 -7 709 -5 0 -89 -49 -188 -108z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 613 B

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 613 B

View File

@ -0,0 +1,19 @@
{
"name": "",
"short_name": "",
"icons": [
{
"src": "/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/android-chrome-256x256.png",
"sizes": "256x256",
"type": "image/png"
}
],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

View File

@ -15,14 +15,18 @@
limitations under the License.
*/
String.prototype.trunc =
function (n) {
if (this.length <= n) return this;
return this.substr(0, this.substr(0, n).lastIndexOf(' ')) + "&hellip;";
};
function stringTrunc(string, length) {
if (string.length <= length) {
return string;
}
return string.substr(0, string.substr(0, length).lastIndexOf(' ')) + "...";
}
function _createTimeline(data) {
var plot_attrs = {
var plot = $.jqplot('timeline', data, {
gridPadding: {
right: 35
},
@ -47,6 +51,10 @@ function _createTimeline(data) {
yaxis: {
min: 0,
label: ''
},
y2axis: {
min: 0,
label: ''
}
},
series: [
@ -61,30 +69,21 @@ function _createTimeline(data) {
fill: true,
color: '#4bb2c5',
fillColor: '#4bb2c5'
}
]
}
/* add the secondary line only if it is has positive values */
var has_2 = false;
for (var i=0; i<data[2].length; i++) {
if (data[2][i][1] > 0) {
has_2 = true;
break;
}
}
if (has_2) {
plot_attrs.axes.y2axis = {min: 0, label: ''};
plot_attrs.series.push({
},
{
shadow: false,
lineWidth: 1.5,
showMarker: true,
markerOptions: { size: 5 },
markerOptions: {size: 5},
yaxis: 'y2axis'
});
} else {
data.pop();
}
$.jqplot('timeline', data, plot_attrs);
}
]
});
$('.navigation').resize(function () {
plot.replot({resetAxes: true});
})
}
function renderTimeline(options) {
@ -109,6 +108,8 @@ function renderTableAndChart(url, container_id, table_id, chart_id, link_param,
success: function (data) {
var tableData = [];
//var chartData = [['name', 'metric']];
var chartData = [];
const limit = 10;
@ -124,14 +125,14 @@ function renderTableAndChart(url, container_id, table_id, chart_id, link_param,
for (i = 0; i < data.length; i++) {
if (i < limit - 1) {
chartData.push([data[i].name.trunc(36), data[i].metric]);
chartData.push([stringTrunc(data[i].name, 36), data[i].metric]);
} else {
aggregate += data[i].metric;
}
if (!data[i].link) {
if (data[i].id) {
data[i].link = makeLink(data[i].id, data[i].name, link_param);
data[i].link = makeLink(data[i].id, data[i].name, link_param, true);
} else {
data[i].link = data[i].name
}
@ -147,7 +148,7 @@ function renderTableAndChart(url, container_id, table_id, chart_id, link_param,
}
if (i == limit) {
chartData.push([data[i - 1].name.trunc(36), data[i - 1].metric]);
chartData.push([stringTrunc(data[i - 1].name, 36), data[i - 1].metric]);
} else if (i > limit) {
chartData.push(["others", aggregate]);
}
@ -166,30 +167,131 @@ function renderTableAndChart(url, container_id, table_id, chart_id, link_param,
if (table_id) {
$("#" + table_id).dataTable({
"oLanguage": {
"sLengthMenu": "Show _MENU_ entries",
"sSearch": "",
//"oPaginate": {
// "sPrevious": "&lt;",
// "sNext": "&gt;"
//}
},
"aLengthMenu": [
[10, 25, 50, -1],
[10, 25, 50, "All"]
],
"aaSorting": [
[ sort_by_column, "desc" ]
[sort_by_column, "desc"]
],
"sPaginationType": "full_numbers",
"iDisplayLength": 10,
"sPaginationType": "simple",
"iDisplayLength": chart_id == 10,
"aaData": tableData,
"aoColumns": tableColumns
"aoColumns": tableColumns,
"autoWidth": false,
//"sDom": '<"H"r><"clear">t<"F"pfl>',
"fnCreatedRow": function (row, data, dataIndex) {
var colors = [
"#754998",
"#d32473",
"#0090cd",
"#d12148",
"#f68121",
"#faef01",
"#b7cd44",
"#764a99",
"#d12148",
"#43cd6e"
]
if (dataIndex < 9 && table_id != 'engineer_table') {
var span = $('<span>', {
class: 'chartColor',
style: 'background-color: ' + colors[dataIndex]
});
$(row).children("td:nth-child(2)").prepend(span);
}
if (table_id == 'engineer_table') {
var value = Number($(row).children("td:nth-child(9)").text().replace('%', ''));
var color = 'green';
if (value < 60) {
color = 'red';
}
$(row).children("td:nth-child(9)").html('<span class="' + color + '">' + $(row).children("td:nth-child(9)").text().replace('%', '') + '</span>');
}
},
"fnDrawCallback": function () {
//$('#' + table_id + ' thead .sorting:first-child, #'+ table_id + ' thead .sorting:nth-child(2)').text('').removeClass('sorting');
//$('#' + table_id).parent().find('div:last-child').prependTo($('#' + table_id).parent().parent().parent().parent().parent().find('.container_footer'));
$(".dataTables_filter input").attr("placeholder", "Search");
if (table_id != 'engineer_table') {
$('#' + table_id + ' tbody tr td:nth-child(2) a').hover(function () {
if (chart.data($(this).text()).length != 0) {
chart.focus($(this).text());
}
}, function () {
if (chart.data($(this).text()).length != 0) {
chart.focus();
}
});
}
}
});
}
if (chart_id) {
var plot = $.jqplot(chart_id, [chartData], {
seriesDefaults: {
renderer: jQuery.jqplot.PieRenderer,
rendererOptions: {
showDataLabels: true
if (chart_id && chart_id != 'engineer_chart') {
var colors = [
"#754998",
"#d32473",
"#0090cd",
"#d12148",
"#f68121",
"#faef01",
"#b7cd44",
"#764a99",
"#d12148",
"#43cd6e"
];
var chartColors = {};
for (var i = 0; i < chartData.length; i++) {
chartColors[chartData[i][0]] = colors[i];
}
var chart = c3.generate({
bindto: d3.select("#" + chart_id),
legend: {
hide: true
},
tooltip: {
format: {
value: function (value, ratio, id, index) {
return value;
}
}
},
legend: { show: true, location: 'e' }
pie: {
expand: false
},
data: {
selection: {
enabled: true
},
columns: chartData,
type: "pie",
colors: chartColors,
onclick: function (d, i) {
var link = $('a[data-chart="' + d.name + '"]');
var href = $(link).attr('href');
if (link.length > 0 && href !== undefined) {
window.location.href = href;
}
},
}
});
}
}
});
@ -220,7 +322,7 @@ function renderBarChart(chart_id, chart_data) {
function renderPunchCard(chart_id, chart_data) {
$.jqplot(chart_id, chart_data, {
seriesDefaults:{
seriesDefaults: {
renderer: $.jqplot.BubbleRenderer,
rendererOptions: {
varyBubbleColors: false,
@ -240,7 +342,9 @@ function renderPunchCard(chart_id, chart_data) {
labelRenderer: $.jqplot.CanvasAxisLabelRenderer,
tickOptions: {
formatter: function (format, val) {
if (val < 0 || val > 23) { return "" }
if (val < 0 || val > 23) {
return ""
}
return val;
}
}
@ -250,7 +354,9 @@ function renderPunchCard(chart_id, chart_data) {
labelRenderer: $.jqplot.CanvasAxisLabelRenderer,
tickOptions: {
formatter: function (format, val) {
if (val < 0 || val > 6) { return "" }
if (val < 0 || val > 6) {
return ""
}
var labels = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"].reverse();
return labels[val];
}
@ -272,7 +378,7 @@ function extendWithGravatar(record, image_size) {
record.gravatar = $.gravatarImageURI(gravatar, {
"image": "wavatar",
"rating": "g",
"size": image_size? image_size: 64
"size": image_size ? image_size : 64
});
}
@ -292,7 +398,7 @@ function extendWithTweet(record) {
tweet = record.author_name + " abandoned patch in " + record.module;
} else {
var smile = [";(", ":(", "", ":)", ":D"][record.value + 2];
tweet = "Got " + ((record.value > 0)? "+": "") + record.value + " from " + record.author_name + " on patch in " + record.module + smile;
tweet = "Got " + ((record.value > 0) ? "+" : "") + record.value + " from " + record.author_name + " on patch in " + record.module + smile;
}
} else if (record.record_type == "review") {
tweet = record.status + " change request by " + record.author_name + " in " + record.module;
@ -326,26 +432,58 @@ function getUrlVars() {
return vars;
}
function makeLink(id, title, param_name) {
function makeLink(id, title, param_name, data_attr) {
var options = {};
var data = "";
if (data_attr) {
data = ' data-chart="' + title + '" ';
}
options[param_name] = id.toLowerCase();
var link = makeURI("/", options);
return "<a href=\"" + link + "\">" + title + "</a>"
var link = makeURI("/" + window.location.pathname.split('/')[1], options);
return "<a " + data + " href=\"" + link + "\">" + title + "</a>"
}
function makeURI(uri, options) {
var ops = {};
if (window.location.pathname.split('/')[1] == 'cncf') {
ops = makeDate({project_type: "cncf-group", release: "all", metric: "commits"});
}
if (window.location.pathname.split('/')[1] == 'unaffiliated') {
ops = makeDate({project_type: "unaffiliated", release: "all", metric: "commits"});
}
$.extend(ops, getUrlVars());
if (options != null) {
$.extend(ops, options);
}
var str = $.map(ops,function (val, index) {
var str = $.map(ops, function (val, index) {
return index + "=" + encodeURI(("" + val).replace("&", "")).toLowerCase();
}).join("&");
return (str == "") ? uri : uri + "?" + str;
}
function makeDate(ops) {
var date = getUrlVars()['date'];
var result = {};
if (!date || date == 'all') {
return ops;
}
var end_date = new Date();
var start_date = new Date().setDate(end_date.getDate() - Number(date));
return $.extend(ops, {start_date: toTimestamp(new Date(start_date)), end_date: toTimestamp(new Date())});
}
function toTimestamp(strDate) {
var datum = Date.parse(strDate);
return datum / 1000;
}
function getPageState() {
return {
release: $('#release').val(),
@ -353,13 +491,14 @@ function getPageState() {
module: $('#module').val(),
company: $('#company').val(),
user_id: $('#user').val(),
metric: $('#metric').val()
metric: $('#metric').val(),
date: $('#date').val()
};
}
function reload(extra) {
window.location.search = $.map($.extend(getUrlVars(), extra), function (val, index) {
return val? (index + "=" + val) : null;
return val ? (index + "=" + val) : null;
}).join("&")
}
@ -368,44 +507,114 @@ function initSingleSelector(name, api_url, select2_extra_options, change_handler
$(selectorId).val(0).select2({
data: [
{id: 0, text: "Loading..." }
{id: 0, text: "Loading..."}
],
formatSelection: function (item) {
return "<div class=\"select2-loading\">" + item.text + "</div>"
}
}).select2("enable", false);
});
$.ajax({
url: api_url,
dataType: "json",
success: function (data) {
var initial_value = getUrlVars()[name];
if (initial_value) {
initial_value = (initial_value).toLocaleLowerCase();
} else if (data["default"]) {
initial_value = data["default"];
if (name == 'date') {
var initial_value = getUrlVars()[name];
if (initial_value) {
initial_value = (initial_value).toLocaleLowerCase();
} else {
initial_value = 'all';
}
$(selectorId).val(initial_value).select2($.extend({
data: [{"text": "All", "id": "all"}, {"text": "7 days", "id": "7"}, {
"text": "30 days",
"id": "30"
}, {"text": "60 days", "id": "60"}, {"text": "90 days", "id": "90"}, {
"text": "180 days",
"id": "180"
}]
}, select2_extra_options)).on("select2-selecting", function (e) {
var options = {};
options[name] = e.val;
if (change_handler) {
change_handler(options);
}
$(selectorId).
val(initial_value).
select2($.extend({
data: data["data"]
}, select2_extra_options)).
on("select2-selecting",function (e) { /* don't use 'change' event, because it changes value and only after refreshes the page */
reload(options);
}).on("select2-removed", function (e) {
console.log('select2-removed');
var options = {};
options[name] = '';
reload(options);
}).select2("enable", true);
} else {
$.ajax({
url: api_url,
dataType: "json",
success: function (data) {
var initial_value = getUrlVars()[name];
if (initial_value) {
initial_value = (initial_value).toLocaleLowerCase();
} else if (window.location.pathname.split('/')[1] == 'cncf') {
switch (name) {
case "release":
initial_value = "all";
break;
case "metric":
initial_value = "commits";
break;
case "project_type":
initial_value = "cncf-group";
break;
default:
initial_value = data["default"];
break;
}
} else if (window.location.pathname.split('/')[1] == 'unaffiliated') {
switch (name) {
case "release":
initial_value = "all";
break;
case "metric":
initial_value = "commits";
break;
case "project_type":
initial_value = "unaffiliated";
break;
default:
initial_value = data["default"];
break;
}
} else if (data["default"]) {
initial_value = data["default"];
}
var selectData = data["data"];
if (name == 'project_type') {
selectData = processProjects(data["data"]);
}
if (name == 'release') {
var filter = "openstack";
}
$(selectorId).val(initial_value).select2($.extend({
data: selectData
}, select2_extra_options)).on("select2-selecting", function (e) {
var options = {};
options[name] = e.val;
if (change_handler) {
change_handler(options);
}
reload(options);
}).
on("select2-removed",function (e) {
}).on("select2-removed", function (e) {
console.log('select2-removed');
var options = {};
options[name] = '';
reload(options);
}).
select2("enable", true);
}
});
}).select2("enable", true);
}
});
}
}
function initSelectors(base_url) {
@ -419,11 +628,40 @@ function initSelectors(base_url) {
});
initSingleSelector("module", makeURI(base_url + "/api/1.0/modules", {tags: "module,program,group"}), {
formatResultCssClass: function (item) {
return (item.tag)? ("select_module_" + item.tag): "";
return (item.tag) ? ("select_module_" + item.tag) : "";
},
allowClear: true
});
initSingleSelector("company", makeURI(base_url + "/api/1.0/companies"), {allowClear: true});
initSingleSelector("user_id", makeURI(base_url + "/api/1.0/users"), {allowClear: true});
initSingleSelector("metric", makeURI(base_url + "/api/1.0/metrics"));
initSingleSelector("date", "", {allowClear: false});
}
function processProjects(data) {
var result = {};
var parent = "";
for (i = 0; i < data.length; i++) {
if (!data[i].child) {
//create new array
parent = data[i].id;
result[parent] = [data[i]]
} else {
result[parent].push(data[i]);
}
}
var url = window.location.pathname.split('/')[1];
var projects = result["all"];
if (url == "cncf") {
projects = result["cncf-group"];
}
if (url == "unaffiliated") {
projects = result["unaffiliated"];
}
return projects;
}

View File

@ -2,6 +2,8 @@
show_record_type=True, show_user_gravatar=True, gravatar_size=32, show_all=True,
show_twitter=False) -%}
{% set page_url = request.base_url %}
{% if show_twitter %}
<script>window.twttr = (function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0],
@ -40,13 +42,14 @@ show_twitter=False) -%}
{% endif %}
function load_activity(extra_options) {
var options = {page_size: page_size, start_record: start_record};
var options = {page_size: page_size, start_record: start_record, };
$.extend(options, extra_options);
$.ajax({
url: makeURI("/api/1.0/activity", options),
dataType: "json",
success: function (data) {
if (data["activity"].length < page_size) {
$('#activity_more').hide();
}
@ -55,11 +58,12 @@ show_twitter=False) -%}
}
$.each(data["activity"], function() {
extendWithGravatar(this, {{ gravatar_size }});
$.extend(this, {page_url: document.location.pathname});
{% if show_twitter %}
extendWithTweet(this);
{% endif %}
});
$("#activity_template").tmpl(data["activity"]).appendTo("#activity_container");
$("#activity_template").tmpl(data["activity"]).insertBefore('#more_button');
$('.ext_link').click(function (event) {
event.preventDefault();
event.stopPropagation();
@ -103,12 +107,12 @@ show_twitter=False) -%}
{% raw %}
{%if coauthor %}
<div class="header">
{%each(index,value) coauthor %}{%if index>0 %}, {%/if%}{%html value.author_link %} ({%html value.company_link %}){%/each%}
{%each(index,value) coauthor %}{%if index>0 %}, {%/if%} <a href="{%html + value.author_link.uri %}">{%html value.author_link.title%}</a> (<a href="{%html page_url + value.company_link.uri %}">{%html value.company_link.title %}</a>){%/each%}
</div>
{%else%}
<div class="header">{%html author_link %} ({%html company_link %})</div>
<div class="header"><a href="{%html page_url + author_link.uri %}">{%html author_link.title %}</a> (<a href="{%html page_url + company_link.uri %}">{%html company_link.title %}</a>)</div>
{%/if%}
<div class="header">${date_str} in {%html module_link%}
<div class="header">${date_str} in {%html module_link.title%}
{%if record_type == "mark" || record_type == "review" || record_type == "patch" || record_type == "tr" %}
{%if branch != "master" %}(${branch}){%/if%}
{%/if%}
@ -131,9 +135,9 @@ show_twitter=False) -%}
<span style="color: blue">- <span>${lines_deleted}</span></span></div>
{%elif record_type == "mark" %}
<div class="header">Review &ldquo;${parent_subject}&rdquo;</div>
<div>Change request by: {%html parent_author_link %} ({%html parent_company_link %})</div>
<div>Change request by: <a href="{%html page_url + parent_author_link.uri %}">{%html parent_author_link.title %}</a> (<a href="{%html parent_company_link.uri %}">{%html parent_company_link.title %}</a>)</div>
{%if patch_author_link != parent_author_link %}
<div>Patch by: {%html patch_author_link %} ({%html patch_company_link %})</div>
<div>Patch by: <a href="{%html patch_author_link.uri %}">{%html patch_author_link.title %}</a> (<a href="{%html patch_company_link.uri %}">{%html patch_company_link.title %}</a>)</div>
{%/if%}
<div>Change Id: <a href="${parent_url}" target="_blank">${review_id}</a></div>
<div style="color: {%if value > 0 %} green {%else%} blue {%/if%}">
@ -208,13 +212,17 @@ show_twitter=False) -%}
{% endraw %}
</script>
<h2 id="activity_header">Activity Log</h2>
<div id="activity_container"></div>
<div style="height: 44px;">
<div class="paging_full_numbers" id="activity_paginate" style="margin-left: {{ gravatar_size * 1.4 }}px;">
<a class="last paginate_button" tabindex="0" id="activity_more">More...</a>
<div id="activity_container">
<h2 id="activity_header">Activity Log {% if company %} | {{ company_original }}{% endif %} </h2>
<div id="more_button" style="height: 44px;">
<div class="paging_full_numbers" id="activity_paginate" style="margin-left: {{ gravatar_size * 1.4 }}px;">
<a class="last paginate_button" tabindex="0" id="activity_more">More...</a>
</div>
</div>
</div>
{%- endmacro %}

View File

@ -52,7 +52,9 @@
{% endraw %}
</script>
<h2>Contribution Summary</h2>
<div id="contribution_container"></div>
<div id="contribution_container">
<h2>Contribution Summary</h2>
</div>
{%- endmacro %}

View File

@ -11,7 +11,7 @@
var module = data["module"];
for (var i=0; i < module.modules.length; i++) {
if(!obj.hasOwnProperty(module.modules[i].module_name)){
module.modules[i].uri = makeURI('/', {module: module.modules[i].module_name});
module.modules[i].uri = makeURI(document.location.pathname, {module: module.modules[i].module_name});
unique_array.push(module.modules[i]);
}
obj[module.modules[i].module_name] = module.modules[i];

View File

@ -25,7 +25,7 @@
<div style="float: left;"><img src="${gravatar}"></div>
<div style="margin-left: 90px;">
<h2>${user_name}</h2>
<div>Company: {%html company_link %}
<div>Company: <a href="{%html company_link.uri %}">{%html company_link.title %}</a>
[<span style="font-style: italic;"><a
href="https://wiki.openstack.org/wiki/Stackalytics#Company_affiliation" style="color: grey" target="_blank">how to change</a></span>]
</div>

View File

@ -2,12 +2,13 @@
<html lang="en" prefix="og: http://ogp.me/ns#">
<head profile="http://gmpg.org/xfn/11">
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<title>Stackalytics {% if page_title %}| {{ page_title }} {% endif %}</title>
{% if not page_title %}
<meta name="description" content="OpenStack contribution dashboard collects and processes development activity data such as commits, lines of code changed, code reviews, statistics on bugs, blueprints and emails"/>
<meta name="description"
content="OpenStack contribution dashboard collects and processes development activity data such as commits, lines of code changed, code reviews, statistics on bugs, blueprints and emails"/>
{% else %}
<meta name="description" content="{{ page_title }}"/>
{% endif %}
@ -17,41 +18,61 @@
<meta name="runtime_storage_update_time" content="{{ runtime_storage_update_time }}"/>
{% if page_title %}
<meta property="og:site_name" content="Stackalytics" />
<meta property="og:title" content="Stackalytics | {{ page_title }}" />
<meta property="og:type" content="website" />
<meta property="og:locale" content="en_US" />
<meta property="og:description" content="{{ page_title }}" />
<meta property="og:image" content="http://stackalytics.com/static/images/stackalytics_logo.png" />
<meta property="og:site_name" content="Stackalytics"/>
<meta property="og:title" content="Stackalytics | {{ page_title }}"/>
<meta property="og:type" content="website"/>
<meta property="og:locale" content="en_US"/>
<meta property="og:description" content="{{ page_title }}"/>
<meta property="og:image" content="http://stackalytics.com/static/images/stackalytics_logo.png"/>
{% endif %}
<link href='//fonts.googleapis.com/css?family=PT+Sans:400,700,400italic&subset=latin,cyrillic' rel='stylesheet' type='text/css' />
<link href='//fonts.googleapis.com/css?family=PT+Sans+Caption&subset=latin,cyrillic' rel='stylesheet' type='text/css' />
<link href='//fonts.googleapis.com/css?family=PT+Sans+Narrow:400,700&subset=latin,cyrillic' rel='stylesheet' type='text/css' />
<link rel="apple-touch-icon" sizes="180x180" href="{{ url_for('static', filename='images/apple-touch-icon.png') }}"
">
<link rel="icon" type="image/png" sizes="32x32" href="{{ url_for('static', filename='images/favicon-32x32.png') }}">
<link rel="icon" type="image/png" sizes="16x16" href="{{ url_for('static', filename='images/favicon-16x16.png') }}">
<link rel="manifest" href="{{ url_for('static', filename='images/site.webmanifest') }}">
<link rel="mask-icon" href="{{ url_for('static', filename='images/safari-pinned-tab.svg') }}" color="#14c3de">
<meta name="msapplication-TileColor" content="#603cba">
<meta name="theme-color" content="#ffffff">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700">
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/jquery.jqplot.min.css') }}">
<link rel="stylesheet" type="text/css" href="//cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css">
<link rel="stylesheet" type="text/css"
href="{{ url_for('static', filename='css/jquery-ui/jquery-ui-1.10.4.custom.css') }}">
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/select2.css') }}">
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/style.css') }}">
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/moonfonts.css') }}">
<!-- <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.css"> -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/c3/0.6.8/c3.min.css">
<link rel="icon" href="{{ url_for('static', filename='images/favicon.png') }}" type="image/png"/>
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='css/jquery.jqplot.min.css') }}">
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='css/jquery.dataTables.css') }}">
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='css/jquery-ui/jquery-ui-1.10.4.custom.css') }}">
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='css/select2.css') }}">
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='css/style.css') }}">
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='css/moonfonts.css') }}">
<script type="text/javascript" src="{{ url_for('static', filename='js/jquery-1.9.1.min.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/jquery-ui.min.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/jquery.dataTables.min.js') }}"></script>
<script type="text/javascript" src="//cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/jquery.jqplot.min.js') }}"></script>
<!--[if lt IE 9]><script type="text/javascript" src="{{ url_for('static', filename='js/excanvas.min.js') }}"></script><![endif]-->
<!--[if lt IE 9]>
<script type="text/javascript" src="{{ url_for('static', filename='js/excanvas.min.js') }}"></script><![endif]-->
<script type="text/javascript" src="{{ url_for('static', filename='js/jqplot.json2.min.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/jqplot.pieRenderer.min.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/jqplot.barRenderer.min.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/jqplot.bubbleRenderer.min.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/jqplot.categoryAxisRenderer.min.js') }}"></script>
<script type="text/javascript"
src="{{ url_for('static', filename='js/jqplot.categoryAxisRenderer.min.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/jqplot.dateAxisRenderer.min.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/jqplot.canvasTextRenderer.min.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/jqplot.canvasAxisLabelRenderer.min.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/jqplot.canvasAxisTickRenderer.min.js') }}"></script>
<script type="text/javascript"
src="{{ url_for('static', filename='js/jqplot.canvasTextRenderer.min.js') }}"></script>
<script type="text/javascript"
src="{{ url_for('static', filename='js/jqplot.canvasAxisLabelRenderer.min.js') }}"></script>
<script type="text/javascript"
src="{{ url_for('static', filename='js/jqplot.canvasAxisTickRenderer.min.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/jqplot.cursor.min.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/jqplot.highlighter.min.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/select2.min.js') }}"></script>
@ -61,6 +82,19 @@
<script type="text/javascript" src="{{ url_for('static', filename='js/jquery.gravatar.js') }}"></script>
<script type="text/javascript" src="{{ url_for('static', filename='js/js-yaml.min.js') }}"></script>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-8933515-9"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-8933515-9');
</script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.6.8/c3.min.js"></script>
{% if active_tab == 'driverlog' %}
<script type="text/javascript" src="{{ url_for('static', filename='js/driverlog-ui.js') }}"></script>
{% else %}
@ -73,10 +107,8 @@
</head>
<body>
<div id="content">
{% block body %}{% endblock %}
</div>
<div id="content">
{% block body %}{% endblock %}
</div>
</body>
</html>

View File

@ -0,0 +1,226 @@
{% extends "cncf_layout.html" %}
{% import '_macros/activity_log.html' as activity_log %}
{% import '_macros/contribution_summary.html' as contribution_summary %}
{% import '_macros/user_profile.html' as user_profile %}
{% import '_macros/module_details.html' as module_details %}
{% set show_company_breakdown = (not company) and (not user_id) %}
{% set show_engineer_breakdown = (not user_id) %}
{% set show_bp_breakdown = (metric in ['bpd', 'bpc']) %}
{% set show_module_breakdown = (not module) %}
{% set show_languages_breakdown = (metric in ['translations']) %}
{% set show_user_activity = (user_id) %}
{% set show_module_activity = (module) and (not user_id) %}
{% set show_activity = (show_user_activity) or (show_module_activity) %}
{% set show_contribution_on_left = (not user_id) and (module) %}
{% set show_contribution_on_right = (user_id) or (company and not module) %}
{% set show_user_profile = (user_id) %}
{% set show_module_details = (module) %}
{% set show_review_ratio = (metric in ['marks']) %}
{% block scripts %}
<script type="text/javascript">
{% if show_module_details %}
//renderTimeline();
{% endif %}
{% if show_company_breakdown %}
renderTableAndChart("/api/1.0/stats/companies", "company_container", "company_table", "company_chart", "company");
{% endif %}
{% if show_engineer_breakdown %}
renderTableAndChart("/api/1.0/stats/engineers", "engineer_container", "engineer_table", "engineer_chart", "user_id");
{% endif %}
{% if show_bp_breakdown %}
renderTableAndChart("/api/1.0/stats/bp", "bp_container", "bp_table", "bp_chart", "name",
["index", "link", "status", "date", "metric"]);
{% endif %}
{% if show_module_breakdown %}
renderTableAndChart("/api/1.0/stats/modules", "module_container", "module_table", "module_chart", "module");
{% endif %}
{% if show_languages_breakdown %}
renderTableAndChart("/api/1.0/stats/languages", "language_container", "language_table", "language_chart", "language");
{% endif %}
</script>
{% endblock %}
{% block left_frame %}
{% if show_module_details %}
{{ module_details.show_module_details(module=module) }}
{% endif %}
{% if show_user_profile %}
{{ user_profile.show_user_profile(user_id=user_id) }}
{% endif %}
{% if show_company_breakdown %}
<div id="company_container">
<div class="row">
<div class="col-xl-12">
<h2>Commits by Company {% if user_id %} <span style="color: #15c3de;">|</span> {{ user_inst.user_name }}{% endif %}</h2>
</div>
</div>
<div class="row">
<div class="col-xl-6 order-xl-last">
<div id="company_chart"></div>
</div>
<div class="col-xl-6 order-xl-first">
<table id="company_table" class="display">
<thead>
<tr>
<th>#</th>
<th>Company</th>
<th>Commits</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
{% endif %}
{% if show_module_breakdown %}
<div id="module_container">
<div class="row">
<div class="col-xl-12">
<h2>Commits by Project {% if company %} <span style="color: #15c3de;">|</span> {{ company_original }}{% endif %} {% if user_id %} <span style="color: #15c3de;">|</span> {{ user_inst.user_name }}{% endif %}</h2>
</div>
</div>
<div class="row">
<div class="col-xl-6 order-xl-last">
<div id="module_chart"></div>
</div>
<div class="col-xl-6 order-xl-first">
<table id="module_table" class="display">
<thead>
<tr>
<th>#</th>
<th>Project</th>
<th>Commits</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
{% endif %}
{% if show_engineer_breakdown %}
<div id="engineer_container">
<h2>Commits by Contributor {% if company %} <span style="color: #15c3de;">|</span> {{ company_original }}{% endif %} {% if user_id %} <span style="color: #15c3de;">|</span> {{ user_inst.user_name }}{% endif %}</h2>
<table id="engineer_table" class="display">
<thead>
<tr>
<th>#</th>
<th>Contributor</th>
<th>Commits</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
{% endif %}
{% if show_contribution_on_left %}
{{ contribution_summary.show_contribution_summary(show_all=False) }}
{% endif %}
{% if show_contribution_on_right %}
{{ contribution_summary.show_contribution_summary(show_all=False) }}
{% endif %}
{% if show_user_activity %}
{{ activity_log.show_activity_log(gravatar_size=32, show_all=False) }}
{% endif %}
{% if show_module_activity %}
{{ activity_log.show_activity_log(gravatar_size=32, show_all=False) }}
{% endif %}
{% if show_contribution_on_left %}
{% endif %}
{% if show_contribution_on_right %}
{% endif %}
{% if show_bp_breakdown %}
<div id="bp_container">
<h2>Blueprint popularity</h2>
<div style="font-style: italic;">
This metric shows how many times a blueprint was mentioned in emails and commit messages.
</div>
<div id="bp_chart" style="width: 300px;height:285px;" width="300" height="285"></div>
<table id="bp_table" class="display">
<thead>
<tr>
<th>#</th>
<th>Blueprint</th>
<th>Status</th>
<th>Date</th>
<th>Mentions</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div class="spacer"></div>
</div>
{% endif %}
{% if show_languages_breakdown %}
<div id="language_container">
<h2>Languages</h2>
<div id="language_chart" style="width: 300px;height:285px;" width="300" height="285"></div>
<table id="language_table" class="display">
<thead>
<tr>
<th>#</th>
<th>Language</th>
<th>Translations</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div class="spacer"></div>
</div>
{% endif %}
{% endblock %}
{% block center_frame %}
{% endblock %}
{% block right_frame %}
{% endblock %}

View File

@ -0,0 +1,172 @@
{% extends "base.html" %}
{% block head %}
<script type="text/javascript">
$(document).ready(function () {
initSelectors("");
$(".select2-selection__arrow")
.addClass("material-icons")
.html("arrow_drop_down");
});
$(function () {
$(document).tooltip();
});
</script>
{% block scripts %}{% endblock %}
{% endblock %}
{% block body %}
<div class="page">
{% if not runtime_storage_update_time %}
<div class="banner">The data is being loaded now and is not complete</div>
{% set update_time_title = '' %}
{% else %}
{% if runtime_storage_update_time is too_old %}
<div class="banner">The data was last updated on {{ runtime_storage_update_time_str }}</div>
{% endif %}
{% set update_time_title = 'Last updated on ' + runtime_storage_update_time_str %}
{% endif %}
<div class="container">
<div class="aheader">
<div id="analytics_header">
<div class="row">
<div class="col-lg-3">
<div id="logo" class="text-center">
<a href="{{ url_for('overview') }}">
<img
src="{{ url_for('static', filename='images/stackalytics_logo.png') }}"
class="img-fluid" alt="Stackalytics">
</a>
</div>
</div>
<div class="col-lg-8">
<div class="stackamenu text-center">
<ul id="menu-stackamenu" class="list-inline">
<li class="list-inline-item"><a href="/"><span class="menu-item">OpenStack Foundation</span></a></li>
<li class="list-inline-item current-menu-item"><a href="/cncf"><span class="menu-item">CNCF</span></a></li>
<li class="list-inline-item"><a href="/unaffiliated"><span class="menu-item">Other Projects</span></a></li>
</ul>
</div>
</div>
<div class="col-lg-1">
<a class="about" href="https://wiki.openstack.org/wiki/Stackalytics" target="_blank"
title="{{ update_time_title }}">
About
</a>
</div>
</div>
<div class="drops">
<div class="row">
<div class="col-md" style="display:none;">
<label for="release_selector" title="Official releases of OpenStack">Release</label>
<input type="hidden" id="release_selector" style="width: 100%"
data-placeholder="Select release"/>
</div>
<div class="col-md">
<label for="date_selector" title="Official releases of OpenStack">Date</label>
<input type="hidden" id="date_selector" style="width: 100%"
data-placeholder="Select date"/>
</div>
<div class="col-md" style="display:none;">
<label for="project_type_selector" title="Project type groups modules of the same kind. 'OpenStack' are projects defined in the official governance projects.yaml.
'OpenStack Others' are projects not included into any program. 'Complementary' are projects related to OpenStack ecosystem">Project
Type</label>
<input type="hidden" id="project_type_selector" style="width: 100%"
data-placeholder="Select project type"/>
</div>
<div class="col-md">
<label for="module_selector"
title="CNCF Projects">Project</label>
<input type="hidden" id="module_selector" style="width: 100%"
data-placeholder="Any project"/>
</div>
<div class="col-md">
<label for="company_selector" title="Company name">Company</label>
<input type="hidden" id="company_selector" style="width: 100%"
data-placeholder="Any company"/>
</div>
<div class="col-md">
<label for="user_id_selector"
title="Name of contributor as configured in Launchpad or default_data.json">Contributor</label>
<input type="hidden" id="user_id_selector" style="width: 100%"
data-placeholder="Any contributor"/>
</div>
<div class="col-md" style="display: none;">
<label for="metric_selector" title="One of available metrics">Metric</label>
<input type="hidden" id="metric_selector" style="width: 100%"
data-placeholder="Select metric"/>
</div>
</div>
</div>
{% if show_module_details %}
{% endif %}
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-xl-12">
{% block left_frame %}{% endblock %}
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-lg-12">
{% block right_frame %}{% endblock %}
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-lg-12">
{% block center_frame %}{% endblock %}
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-lg-12">
<div id="footer_container">
<div class="row">
<div class="col-lg-9">
Stackalytics displays information collected from open sources, including
<a href="https://git.openstack.org/cgit" style="color: grey;">git.openstack.org</a>
,
<a href="https://review.openstack.org/" style="color: grey;">review.openstack.org</a>
,
<a href="https://launchpad.net/" style="color: grey;">Launchpad</a>
,
<a href="https://github.com/" style="color: grey;">GitHub</a>
,
<a href="https://www.openstack.org/" style="color: grey;">OpenStack.org</a>
,
<a href="http://lists.openstack.org/cgi-bin/mailman/listinfo" style="color: grey;">OpenStack
mailing lists
</a>
.
{% if update_time_title %}{{ update_time_title }}{% endif %}
</div>
<div class="col-lg-3">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -5,6 +5,9 @@
<script type="text/javascript">
$(document).ready(function () {
initSelectors("");
$(".select2-selection__arrow")
.addClass("material-icons")
.html("arrow_drop_down");
});
$(function () {
@ -18,98 +21,147 @@
{% block body %}
<div class="page">
{% if not runtime_storage_update_time %}
<div class="banner">The data is being loaded now and is not complete</div>
{% set update_time_title = '' %}
{% else %}
{% if runtime_storage_update_time is too_old %}
<div class="banner">The data was last updated on {{ runtime_storage_update_time_str }}</div>
{% endif %}
{% set update_time_title = 'Last updated on ' + runtime_storage_update_time_str %}
{% endif %}
<div class="aheader">
<div style="float: right; margin-top: 10px; margin-right: 20px;">
<a href="https://wiki.openstack.org/wiki/Stackalytics" target="_blank" title="{{ update_time_title }}">About</a>
</div>
<div id="analytics_header">
<div style="float: left;">
<span id="logo"><a href="{{ url_for('overview') }}"><img src="{{ url_for('static', filename='images/stackalytics_logo.png') }}" alt="Stackalytics" style="width: 100%; max-width: 190px;"></a></span>
</div>
<div class="stackamenu" style="margin-left: 240px">
<ul id="menu-stackamenu">
<li class="menu-item current-menu-item"><a href="/"><span class="icon-pie"></span>Code Contribution</a></li>
<li class="menu-item"><a href="/report/driverlog"><span class="icon-cogs"></span>Vendor Drivers <span style="vertical-align: top; font-size: 60%;">&beta;</span></a></li>
<li class="menu-item"><a href="/report/members"><span class="icon-users"></span>Member Directory</a></li>
</ul>
</div>
</div>
<div class="page">
{% if not runtime_storage_update_time %}
<div class="banner">The data is being loaded now and is not complete</div>
{% set update_time_title = '' %}
{% else %}
{% if runtime_storage_update_time is too_old %}
<div class="banner">The data was last updated on {{ runtime_storage_update_time_str }}</div>
{% endif %}
{% set update_time_title = 'Last updated on ' + runtime_storage_update_time_str %}
{% endif %}
<div class="container">
<div class="aheader">
<div class="drops">
<div class="drop">
<label for="release_selector" title="Official releases of OpenStack">Release</label>
<input type="hidden" id="release_selector" style="width: 140px" data-placeholder="Select release"/>
</div>
<div class="drop">
<label for="project_type_selector" title="Project type groups modules of the same kind. 'OpenStack' are projects defined in the official governance projects.yaml.
'OpenStack Others' are projects not included into any program. 'Complementary' are projects related to OpenStack ecosystem">Project Type</label>
<input type="hidden" id="project_type_selector" style="width: 140px" data-placeholder="Select project type"/>
</div>
<div class="drop">
<label for="module_selector" title="Module represents a repo (black), official project (violet) or pre-configured group of modules (cyan)">Module</label>
<input type="hidden" id="module_selector" style="width: 140px" data-placeholder="Any module"/>
</div>
<div class="drop">
<label for="company_selector" title="Company name">Company</label>
<input type="hidden" id="company_selector" style="width: 140px" data-placeholder="Any company"/>
</div>
<div class="drop">
<label for="user_id_selector" title="Name of contributor as configured in Launchpad or default_data.json">Contributor</label>
<input type="hidden" id="user_id_selector" style="width: 140px" data-placeholder="Any contributor"/>
</div>
<div class="drop">
<label for="metric_selector" title="One of available metrics">Metric</label>
<input type="hidden" id="metric_selector" style="width: 140px" data-placeholder="Select metric"/>
</div>
</div>
</div>
<div class="navigation">
<div id="timeline" style="width: 100%; height: 120px; margin-top: 15px;"></div>
</div>
<table style="width: 100%" cellspacing="0">
<tr>
<td style="width: 50%; vertical-align: top;">
<div class="body" style="margin-right: 1em;">
{% block left_frame %}{% endblock %}
<div id="analytics_header">
<div class="row">
<div class="col-lg-3">
<div id="logo" class="text-center">
<a href="{{ url_for('overview') }}">
<img
src="{{ url_for('static', filename='images/stackalytics_logo.png') }}"
class="img-fluid" alt="Stackalytics">
</a>
</div>
</div>
<div class="col-lg-8">
<div class="stackamenu text-center">
<ul id="menu-stackamenu" class="list-inline">
<li class="list-inline-item current-menu-item"><a href="/"><span class="menu-item">OpenStack Foundation</span></a></li>
<li class="list-inline-item"><a href="/cncf"><span class="menu-item">CNCF</span></a></li>
<li class="list-inline-item"><a href="/unaffiliated"><span class="menu-item">Other Projects</span></a></li>
</ul>
</div>
</div>
<div class="col-lg-1">
<a class="about" href="https://wiki.openstack.org/wiki/Stackalytics" target="_blank"
title="{{ update_time_title }}">
About
</a>
</div>
</div>
</td>
<td style="width: 50%; vertical-align: top;">
<div class="body" style="margin-left: 1em;">
{% block right_frame %}{% endblock %}
</div>
</td>
</tr>
</table>
<div style="font-size: 10px; color: grey;">
Stackalytics displays information collected from open sources, including
<a href="https://git.openstack.org/cgit" style="color: grey;">git.openstack.org</a>,
<a href="https://review.openstack.org/" style="color: grey;">review.openstack.org</a>,
<a href="https://launchpad.net/" style="color: grey;">Launchpad</a>,
<a href="https://github.com/" style="color: grey;">GitHub</a>,
<a href="https://www.openstack.org/" style="color: grey;">OpenStack.org</a>,
<a href="http://lists.openstack.org/cgi-bin/mailman/listinfo" style="color: grey;">OpenStack mailing lists</a>.
{% if update_time_title %}{{ update_time_title }}{% endif %}
<div class="drops">
<div class="row">
<div class="col-md">
<label for="release_selector" title="Official releases of OpenStack">Release</label>
<input type="hidden" id="release_selector" style="width: 100%"
data-placeholder="Select release"/>
</div>
<div class="col-md">
<label for="project_type_selector" title="Project type groups modules of the same kind. 'OpenStack' are projects defined in the official governance projects.yaml.
'OpenStack Others' are projects not included into any program. 'Complementary' are projects related to OpenStack ecosystem">Project
Type</label>
<input type="hidden" id="project_type_selector" style="width: 100%"
data-placeholder="Select project type"/>
</div>
<div class="col-md">
<label for="module_selector"
title="Module represents a repo (black), official project (violet) or pre-configured group of modules (cyan)">Module</label>
<input type="hidden" id="module_selector" style="width: 100%"
data-placeholder="Any module"/>
</div>
<div class="col-md">
<label for="company_selector" title="Company name">Company</label>
<input type="hidden" id="company_selector" style="width: 100%"
data-placeholder="Any company"/>
</div>
<div class="col-md">
<label for="user_id_selector"
title="Name of contributor as configured in Launchpad or default_data.json">Contributor</label>
<input type="hidden" id="user_id_selector" style="width: 100%"
data-placeholder="Any contributor"/>
</div>
<div class="col-md">
<label for="metric_selector" title="One of available metrics">Metric</label>
<input type="hidden" id="metric_selector" style="width: 100%"
data-placeholder="Select metric"/>
</div>
</div>
</div>
{% if show_module_details %}
{% endif %}
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-xl-12">
{% block left_frame %}{% endblock %}
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-lg-12">
{% block right_frame %}{% endblock %}
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-lg-12">
{% block center_frame %}{% endblock %}
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-lg-12">
<div id="footer_container">
<div class="row">
<div class="col-lg-9">
Stackalytics displays information collected from open sources, including
<a href="https://git.openstack.org/cgit" style="color: grey;">git.openstack.org</a>
,
<a href="https://review.openstack.org/" style="color: grey;">review.openstack.org</a>
,
<a href="https://launchpad.net/" style="color: grey;">Launchpad</a>
,
<a href="https://github.com/" style="color: grey;">GitHub</a>
,
<a href="https://www.openstack.org/" style="color: grey;">OpenStack.org</a>
,
<a href="http://lists.openstack.org/cgi-bin/mailman/listinfo" style="color: grey;">OpenStack
mailing lists
</a>
.
{% if update_time_title %}{{ update_time_title }}{% endif %}
</div>
<div class="col-lg-3">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -36,7 +36,9 @@
{% block scripts %}
<script type="text/javascript">
renderTimeline();
{% if show_module_details %}
//renderTimeline();
{% endif %}
{% if show_company_breakdown %}
renderTableAndChart("/api/1.0/stats/companies", "company_container", "company_table", "company_chart", "company");
@ -44,7 +46,7 @@
{% if show_engineer_breakdown %}
{% if show_review_ratio %}
renderTableAndChart("/api/1.0/stats/engineers", "engineer_container", "engineer_table", "engineer_chart", "user_id",
["index", "link", "mark_ratio", "metric"]);
["index", "link", "-2", "-1", "1", "2", "A", "x", "positive_ratio", "metric"]);
{% else %}
renderTableAndChart("/api/1.0/stats/engineers", "engineer_container", "engineer_table", "engineer_chart", "user_id");
{% endif %}
@ -66,49 +68,99 @@
{% block left_frame %}
{% if show_module_details %}
{{ module_details.show_module_details(module=module) }}
{% endif %}
{% if show_company_breakdown %}
<div id="company_container">
<h2>Contribution by companies</h2>
<div id="company_chart" style="width: 100%; height: 350px; margin-bottom: 1em;"></div>
<div class="row">
<div class="col-xl-12">
<h2>{{ metric_label }} by Company</h2>
</div>
</div>
<div class="row">
<table id="company_table" class="display">
<thead>
<tr>
<th>#</th>
<th>Company</th>
<th>{{ metric_label }}</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div class="spacer"></div>
<div class="col-xl-6 order-xl-last">
<div id="company_chart"></div>
</div>
<div class="col-xl-6 order-xl-first">
<table id="company_table" class="display">
<thead>
<tr>
<th>#</th>
<th>Company</th>
<th>{{ metric_label }}</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
{% endif %}
{% if show_module_breakdown %}
<div id="module_container">
<div class="row">
<div class="col-xl-12">
<h2>{{ metric_label }} by Module</h2>
</div>
</div>
<div class="row">
<div class="col-xl-6 order-xl-last">
<div id="module_chart"></div>
</div>
<div class="col-xl-6 order-xl-first">
<table id="module_table" class="display">
<thead>
<tr>
<th>#</th>
<th>Module</th>
<th>{{ metric_label }}</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
{% endif %}
{% if show_engineer_breakdown %}
<div id="engineer_container">
<h2>Contribution by contributors</h2>
<div id="engineer_container">
<h2>{{ metric_label }} by Contributor</h2>
<table id="engineer_table" class="display">
<thead>
<tr>
<th>#</th>
<th>Contributor</th>
{% if show_review_ratio %}
<th>-2</th>
<th>-1</th>
<th>+1</th>
<th>+2</th>
<th>A</th>
<th>x</th>
<th>+ ratio</th>
{% endif %}
<th>{{ metric_label }}</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<div id="engineer_chart" style="width: 100%; height: 350px; margin-bottom: 1em;"></div>
<table id="engineer_table" class="display">
<thead>
<tr>
<th>#</th>
<th>Contributor</th>
{% if show_review_ratio %}
<th>-2|-1|+1|+2|A|x (+ ratio)</th>
{% endif %}
<th>{{ metric_label }}</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div class="spacer"></div>
</div>
{% endif %}
{% if show_user_profile %}
@ -123,102 +175,73 @@
{{ show_report_links(module, company, user_id) }}
{% endif %}
{% endblock %}
{% if show_bp_breakdown %}
<div id="bp_container">
<h2>Blueprint popularity</h2>
{% block right_frame %}
<div style="font-style: italic;">
This metric shows how many times a blueprint was mentioned in emails and commit messages.
</div>
<div id="bp_chart" style="width: 300px;height:285px;" width="300" height="285"></div>
<table id="bp_table" class="display">
<thead>
<tr>
<th>#</th>
<th>Blueprint</th>
<th>Status</th>
<th>Date</th>
<th>Mentions</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div class="spacer"></div>
</div>
{% endif %}
{% if show_languages_breakdown %}
<div id="language_container">
{% if language %}
<div class="drop" style="margin-top: 16px;">
<label for="language_selector" title="One of available languages">Language</label>
<input type="hidden" id="language_selector" style="width: 200px" data-placeholder="Select language"/>
</div>
<script>
$(document).ready(function () {
initSingleSelector("language", makeURI("/api/1.0/languages"), {allowClear: true});
});
</script>
{% else %}
<h2>Languages</h2>
<h2>Languages</h2>
<div id="language_chart" style="width: 100%; height: 350px; margin-bottom: 1em;"></div>
<div id="language_chart" style="width: 300px;height:285px;" width="300" height="285"></div>
<table id="language_table" class="display">
<thead>
<table id="language_table" class="display">
<thead>
<tr>
<th>#</th>
<th>Language</th>
<th>Translations</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
{% endif %}
<div class="spacer"></div>
</div>
{% endif %}
{% if show_module_breakdown %}
<div id="module_container">
<h2>Contribution by modules</h2>
<div id="module_chart" style="width: 100%; height: 350px; margin-bottom: 1em;"></div>
<table id="module_table" class="display">
<thead>
<tr>
<th>#</th>
<th>Module</th>
<th>{{ metric_label }}</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div class="spacer"></div>
</div>
{% endif %}
{% if show_module_details %}
{{ module_details.show_module_details(module=module) }}
{% endif %}
{% if show_bp_breakdown %}
<div id="bp_container">
<h2>Blueprint popularity</h2>
<div style="font-style: italic;">
This metric shows how many times a blueprint was mentioned in emails and commit messages.
</div>
<div id="bp_chart" style="width: 100%; height: 350px; margin-bottom: 1em;"></div>
<table id="bp_table" class="display">
<thead>
<tr>
<th>#</th>
<th>Blueprint</th>
<th>Status</th>
<th>Date</th>
<th>Mentions</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div class="spacer"></div>
</thead>
<tbody>
</tbody>
</table>
<div class="spacer"></div>
</div>
{% endif %}
{% if show_contribution_on_right %}
{{ contribution_summary.show_contribution_summary(show_all=False) }}
{{ show_report_links(module, company, user_id) }}
{{ contribution_summary.show_contribution_summary(show_all=False) }}
{{ show_report_links(module, company, user_id) }}
{% endif %}
{% if show_module_activity %}
{{ activity_log.show_activity_log(gravatar_size=32, show_all=False) }}
{{ activity_log.show_activity_log(gravatar_size=32, show_all=False) }}
{% endif %}
{% endblock %}
{% block center_frame %}
{% endblock %}
{% block right_frame %}
{% endblock %}

View File

@ -3,7 +3,7 @@
{% set page_title = 'Company Affiliation Changes' %}
{% block scripts %}
<script type="text/javascript">
<script type="text/javascript">
function show_users_table(options) {
var table_column_names = ["from", "to", "count", "users"];
@ -63,7 +63,7 @@
if (table_id) {
$("#" + table_id).dataTable({
"aaSorting": [
[ sort_by_column, "desc" ]
[sort_by_column, "desc"]
],
"bFilter": true,
"bInfo": true,
@ -90,7 +90,7 @@
}
function reload() {
window.location.search = $.map(make_options(),function (val, index) {
window.location.search = $.map(make_options(), function (val, index) {
return index + "=" + val;
}).join("&")
}
@ -111,16 +111,16 @@
show_page();
});
$(function() {
$( "#start_days_selector" ).datepicker({
$(function () {
$("#start_days_selector").datepicker({
dateFormat: 'yy-M-d',
changeMonth: true,
changeYear: true
});
});
$(function() {
$( "#end_days_selector" ).datepicker({
$(function () {
$("#end_days_selector").datepicker({
dateFormat: 'yy-M-d',
changeMonth: true,
changeYear: true
@ -133,28 +133,29 @@
show_page();
});
</script>
</script>
{% endblock %}
{% block content %}
<h1>Company Affiliation Changes</h1>
<div id="affiliation_container">
<h1>Company Affiliation Changes</h1>
<p>Start of the period: <input type="text" id="start_days_selector"/> &nbsp; End of the period: <input type="text" id="end_days_selector"/></p>
<div class="body" style="margin-right: 1em;">
<table id="users_table" style="width: 100%">
<thead>
<tr>
<th>From</th>
<th>To</th>
<th>Count</th>
<th>Users</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<table id="users_table" style="width: 100%">
<thead>
<tr>
<th>From</th>
<th>To</th>
<th>Count</th>
<th>Users</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
{% endblock %}

View File

@ -7,9 +7,9 @@
{% block body %}
<div style="margin: 2em;">
<div id="analytics_header" style="padding-bottom: 1em; border-bottom: 1px solid darkgrey;">
<div id="analytics_header" style="padding-bottom: 1em;">
<span id="logo"><a href="{{ url_for('overview') }}"><img src="{{ url_for('static', filename='images/stackalytics_logo.png') }}" alt="Stackalytics" style="width: 100%; max-width: 190px;"></a></span>
<span id="slogan" style="position: relative; top: -15px;">| community heartbeat</span>
<span id="slogan">| community heartbeat</span>
</div>
{% block content %}

View File

@ -20,40 +20,52 @@
<div class="page">
<div class="banner">Information on drivers is in beta and may contain some inaccuracies. If you see an error, <br/> please help us make the service better by
<a href="https://wiki.openstack.org/wiki/DriverLog#How_To:_Add_a_new_driver_to_DriverLog" target="_blank">filing a bug or an update request</a></div>
<div class="aheader">
<div style="float: right; margin-top: 10px; margin-right: 20px;">
<a href="https://wiki.openstack.org/wiki/DriverLog#How_To:_Add_a_new_driver_to_DriverLog" target="_blank">Add / Edit Driver</a>
</div>
<div id="analytics_header">
<div style="float: left;">
<span id="logo"><a href="{{ url_for('overview') }}"><img src="{{ url_for('static', filename='images/stackalytics_logo.png') }}" alt="Stackalytics" style="width: 100%; max-width: 190px;"></a></span>
<div class="container">
<div class="aheader">
<div id="analytics_header">
<div class="row">
<div class="col-lg-3">
<div id="logo" class="text-center">
<a href="{{ url_for('overview') }}">
<img
src="{{ url_for('static', filename='images/stackalytics_logo.png') }}"
class="img-fluid" alt="Stackalytics">
</a>
</div>
</div>
<div class="stackamenu" style="margin-left: 240px">
<ul id="menu-stackamenu">
<li class="menu-item"><a href="/"><span class="icon-pie"></span>Code Contribution</a></li>
<li class="menu-item current-menu-item"><a href="/report/driverlog"><span class="icon-cogs"></span>Vendor Drivers <span style="vertical-align: top; font-size: 60%;">&beta;</span></a></li>
<li class="menu-item"><a href="/report/members"><span class="icon-users"></span>Member Directory</a></li>
</ul>
<div class="col-lg-8">
<div class="stackamenu text-center">
<ul id="menu-stackamenu" class="list-inline">
<li class="list-inline-item current-menu-item"><a href="/"><span class="menu-item">OpenStack Foundation</span></a></li>
<li class="list-inline-item"><a href="/?project_type=cncf-group&amp;release=all&amp;metric=commits"><span class="menu-item">CNCF</span></a></li>
<li class="list-inline-item"><a href="/unaffiliated"><span class="menu-item">Unaffiliated Projects</span></a></li>
</ul>
</div>
</div>
<div class="col-lg-1">
<a class="about" href="https://wiki.openstack.org/wiki/DriverLog#How_To:_Add_a_new_driver_to_DriverLog" target="_blank" title="{{ update_time_title }}">
Add / Edit Driver
</a>
</div>
</div>
<div class="drops">
<div class="row">
<div class="col-md">
<label for="project_id" title="OpenStack Project">Project</label>
<input type="hidden" id="project_id" style="width:240px" data-placeholder="Any project"/>
</div>
<div class="col-md">
<label for="vendor" title="Vendor">Vendor</label>
<input type="hidden" id="vendor" style="width:240px" data-placeholder="Any vendor"/>
</div>
<div class="col-md">
<label for="release" title="OpenStack Release">Release</label>
<input type="hidden" id="release" style="width:240px" data-placeholder="Any release"/>
</div>
<div class="drops">
</div>
<div class="drop">
<label for="project_id" title="OpenStack Project">Project</label>
<input type="hidden" id="project_id" style="width:240px" data-placeholder="Any project"/>
</div>
<div class="drop">
<label for="vendor" title="Vendor">Vendor</label>
<input type="hidden" id="vendor" style="width:240px" data-placeholder="Any vendor"/>
</div>
<div class="drop">
<label for="release" title="OpenStack Release">Release</label>
<input type="hidden" id="release" style="width:240px" data-placeholder="Any release"/>
</div>
</div>
<div style="margin-top: 2em;">
@ -145,5 +157,6 @@
</div>
</div>
</div>
{% endblock %}

View File

@ -4,7 +4,7 @@
{% set page_title = 'OpenStack Foundation members' %}
{% block head %}
<script type="text/javascript">
<script type="text/javascript">
function get_start_date() {
var days = {{ days }};
@ -39,7 +39,7 @@
if (table_id) {
$("#" + table_id).dataTable({
"aaSorting": [
[ sort_by_column, "desc" ]
[sort_by_column, "desc"]
],
"bFilter": true,
"bInfo": true,
@ -74,7 +74,7 @@
}
for (i = 0; i < tableData.length; i++) {
var company_link = makeURI('/report/members', {company:tableData[i].name});
var company_link = makeURI('/report/members', {company: tableData[i].name});
tableData[i].link = "<a href=\"" + company_link + "\">" + tableData[i].name + "</a>";
tableData[i].date = tableData[i].date_str;
}
@ -82,7 +82,7 @@
if (table_id) {
$("#" + table_id).dataTable({
"aaSorting": [
[ sort_by_column, "desc" ]
[sort_by_column, "desc"]
],
"bFilter": true,
"bInfo": true,
@ -117,7 +117,7 @@
}
for (i = 0; i < tableData.length; i++) {
var company_link = makeURI('/report/members', {company:tableData[i].name});
var company_link = makeURI('/report/members', {company: tableData[i].name});
tableData[i].link = "<a href=\"" + company_link + "\">" + tableData[i].name + "</a>";
tableData[i].count = tableData[i].metric;
}
@ -125,7 +125,7 @@
if (table_id) {
$("#" + table_id).dataTable({
"aaSorting": [
[ sort_by_column, "desc" ]
[sort_by_column, "desc"]
],
"bFilter": true,
"bInfo": true,
@ -182,7 +182,7 @@
showDataLabels: true
}
},
legend: { show: true, location: 'e' }
legend: {show: true, location: 'e'}
});
}
}
@ -211,7 +211,7 @@
function show_page() {
var start_date = get_start_date();
var base_options = { metric: 'members', project_type: 'all', release: 'all', start_date: start_date };
var base_options = { metric: 'members', project_type: 'all', release: 'all', start_date: start_date};
renderTimeline(base_options);
show_engineers_table(base_options);
@ -221,16 +221,16 @@
show_new_companies_table(base_options);
renderChart("/api/1.0/stats/companies", "members_chart", base_options);
{% else %}
$('#companies_block').hide();
$('#new_companies_table_header').hide();
$('#new_companies_table').hide();
$('#companies_container').hide();
$('#new_compaines_container').hide();
$('#members_container').hide();
{% endif %}
}
$(document).ready(function () {
var start_date = get_start_date();
var base_options = { metric: 'members', project_type: 'all', release: 'all', start_date: start_date };
var base_options = {metric: 'members', project_type: 'all', release: 'all', start_date: start_date};
initSingleSelector("company", makeURI("/api/1.0/companies", base_options), {allowClear: true});
@ -241,95 +241,116 @@
show_page();
});
</script>
</script>
<style type="text/css">
table.dataTable tr.even {
background-color: #EEF1F4;
}
<style type="text/css">
table.dataTable tr.even {
background-color: #EEF1F4;
}
table.dataTable tr.even:hover, table.dataTable tr.odd:hover {
background-color: #F8FFEC;
}
table.dataTable tr.even:hover, table.dataTable tr.odd:hover {
background-color: #F8FFEC;
}
table.dataTable tr.even td.sorting_1 {
background-color: #E0E8E8;
}
</style>
table.dataTable tr.even td.sorting_1 {
background-color: #E0E8E8;
}
</style>
<script type='text/javascript'>
$(document).ready(function () {
$('#days_selector').val({{ days }});
$("#days_selector").select2();
show_page();
});
<script type="text/javascript">
$(document).ready(function () {
$('#days_selector').val( {{days}} );
$("#days_selector").select2();
show_page();
});
$(document).on('change', '#days_selector', function (evt) {
reload();
});
$(document).on('change', '#days_selector', function (evt) {
reload();
});
$(document).on('change', '#company_selector', function (evt) {
reload();
});
</script>
$(document).on('change', '#company_selector', function (evt) {
reload();
});
</script>
{% endblock %}
{% block body %}
<div class="page">
<div class="aheader">
<div style="float: right; margin-top: 10px; margin-right: 20px;">
<a href="https://wiki.openstack.org/wiki/Stackalytics" target="_blank">About</a>
</div>
<div class="aheader">
<div id="analytics_header">
<div style="float: left;">
<span id="logo"><a href="{{ url_for('overview') }}"><img src="{{ url_for('static', filename='images/stackalytics_logo.png') }}" alt="Stackalytics" style="width: 100%; max-width: 190px;"></a></span>
</div>
<div class="stackamenu" style="margin-left: 240px;">
<ul id="menu-stackamenu">
<li class="menu-item"><a href="{{ url_for('overview') }}"><span class="icon-pie"></span>Code Contribution</a></li>
<li class="menu-item"><a href="/report/driverlog"><span class="icon-cogs"></span>Vendor Drivers <span style="vertical-align: top; font-size: 60%;">&beta;</span></a></li>
<li class="menu-item current-menu-item"><a href="/report/members"><span class="icon-users"></span>Member Directory</a></li>
</ul>
<div class="row">
<div class="col-lg-10 offset-lg-1">
<div id="logo" class="text-center">
<a href="{{ url_for('overview') }}">
<img
src="{{ url_for('static', filename='images/stackalytics_logo.png') }}"
alt="Stackalytics">
</a>
</div>
<div class="stackamenu text-center">
<a class="about" href="https://wiki.openstack.org/wiki/Stackalytics" target="_blank"
title="{{ update_time_title }}">
About
</a>
<ul id="menu-stackamenu">
<div class="row">
<div class="col-md text-center">
<span class="menu-item"><a href="/"><span class="icon-pie"></span>Code Contribution</a></span>
</div>
<div class="col-md text-center">
<span class="menu-item"><a href="/report/driverlog"><span class="icon-cogs"></span>Vendor Drivers <span
style="vertical-align: top; font-size: 60%;">&beta;</span></a></span>
</div>
<div class="col-md text-center">
<span class="menu-item current-menu-item"><a href="/report/members"><span
class="icon-users"></span>Member Directory</a></span>
</div>
</div>
</ul>
</div>
<div class="drops">
<div class="row">
<div class="col-md">
<label for="days_selector">Joined during period</label>
<select id="days_selector" name="days_selector"
style="width:100%"
data-placeholder="Select period">
<option value="7">week</option>
<option value="14">two weeks</option>
<option value="31">month</option>
<option value="93">quarter</option>
<option value="183">half year</option>
<option value="365">year</option>
<option value="{{ all_days }}">all</option>
</select>
</div>
<div class="col-md">
<label for="company_selector">Company</label>
<input id="company_selector" style="width:100%"
data-placeholder="Any company"/>
</div>
</div>
</div>
<div class="navigation hidden-md-down">
<div id="timeline" style="width: 100%; height: 120px; margin-top: 15px;"></div>
</div>
</div>
</div>
</div>
<div class="navigation">
<div id="timeline"
style="width: 100%; height: 120px; margin-top: 15px;"></div>
</div>
<div class="row">
<div class="col-lg-6">
<div id="companies_container">
<h2>OpenStack foundation member companies</h2>
<div class="drops">
<div class="drop" style="margin-top: 1em;">
<label for="days_selector">Joined during period</label>
<select id="days_selector" name="days_selector"
style="min-width: 140px;"
data-placeholder="Select period">
<option value="7">week</option>
<option value="14">two weeks</option>
<option value="31">month</option>
<option value="93">quarter</option>
<option value="183">half year</option>
<option value="365">year</option>
<option value="{{ all_days }}">all</option>
</select>
</div>
<div class="drop" style="margin-top: 1em;">
<label for="company_selector">Company</label>
<input id="company_selector" style="width: 140px"
data-placeholder="Any company"/>
</div>
</div>
<table style="width: 100%" cellspacing="0" id="companies_block">
<tr>
<td style="width: 50%; vertical-align: top; padding-right: 3em;">
<h2>OpenStack foundation member companies</h2>
<div class="body" style="margin-right: 1em;">
<table id="companies_table">
<thead>
<tr>
@ -342,26 +363,20 @@
</tbody>
</table>
</div>
</td>
<td style="width: 50%; vertical-align: top; padding-left: 3em">
<h2>Members by company</h2>
<div class="body" style="margin-left: 1em;">
<div id="members_container">
<div id="members_chart"
style="width: 100%; height: 350px; margin-bottom: 1em;"></div>
</div>
</div>
<div class="col-lg-6">
<div id="members_container">
<h2>Members by company</h2>
<div id="members_chart"
style="width: 100%; height: 350px; margin-bottom: 1em;"></div>
</div>
</td>
</tr>
</table>
</div>
</div>
<table style="width: 100%" cellspacing="0">
<tr>
<td style="width: 50%; vertical-align: top; padding-right: 3em;">
<h2>Individual Members</h2>
<div class="body" style="margin-right: 1em;">
<div class="row">
<div class="col-lg-6">
<div id="individuals_container">
<h2>Individual Members</h2>
<table id="members_table">
<thead>
<tr>
@ -375,14 +390,10 @@
</tbody>
</table>
</div>
</td>
<td style="width: 50%; vertical-align: top; padding-right: 3em;">
<div id="new_companies_table_header">
</div>
<div class="col-lg-6">
<div id="new_compaines_container">
<h2>New Companies</h2>
</div>
<div class="body" style="margin-right: 1em;">
<table id="new_companies_table">
<thead>
<tr>
@ -395,11 +406,9 @@
</tbody>
</table>
</div>
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,218 @@
{% extends "unaffiliated_layout.html" %}
{% import '_macros/activity_log.html' as activity_log %}
{% import '_macros/contribution_summary.html' as contribution_summary %}
{% import '_macros/user_profile.html' as user_profile %}
{% import '_macros/module_details.html' as module_details %}
{% set show_company_breakdown = (not company) and (not user_id) %}
{% set show_engineer_breakdown = (not user_id) %}
{% set show_bp_breakdown = (metric in ['bpd', 'bpc']) %}
{% set show_module_breakdown = (not module) %}
{% set show_languages_breakdown = (metric in ['translations']) %}
{% set show_user_activity = (user_id) %}
{% set show_module_activity = (module) and (not user_id) %}
{% set show_activity = (show_user_activity) or (show_module_activity) %}
{% set show_contribution_on_left = (not user_id) and (module) %}
{% set show_contribution_on_right = (user_id) or (company and not module) %}
{% set show_user_profile = (user_id) %}
{% set show_module_details = (module) %}
{% set show_review_ratio = (metric in ['marks']) %}
{% block scripts %}
<script type="text/javascript">
{% if show_module_details %}
// renderTimeline();
{% endif %}
{% if show_company_breakdown %}
renderTableAndChart("/api/1.0/stats/companies", "company_container", "company_table", "company_chart", "company");
{% endif %}
{% if show_engineer_breakdown %}
renderTableAndChart("/api/1.0/stats/engineers", "engineer_container", "engineer_table", "engineer_chart", "user_id");
{% endif %}
{% if show_bp_breakdown %}
renderTableAndChart("/api/1.0/stats/bp", "bp_container", "bp_table", "bp_chart", "name",
["index", "link", "status", "date", "metric"]);
{% endif %}
{% if show_module_breakdown %}
renderTableAndChart("/api/1.0/stats/modules", "module_container", "module_table", "module_chart", "module");
{% endif %}
{% if show_languages_breakdown %}
renderTableAndChart("/api/1.0/stats/languages", "language_container", "language_table", "language_chart", "language");
{% endif %}
</script>
{% endblock %}
{% block left_frame %}
{% if show_module_details %}
{{ module_details.show_module_details(module=module) }}
{% endif %}
{% if show_company_breakdown %}
<div id="company_container">
<div class="row">
<div class="col-xl-12">
<h2>Commits by Company</h2>
</div>
</div>
<div class="row">
<div class="col-xl-6 order-xl-last">
<div id="company_chart"></div>
</div>
<div class="col-xl-6 order-xl-first">
<table id="company_table" class="display">
<thead>
<tr>
<th>#</th>
<th>Company</th>
<th>Commits</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
{% endif %}
{% if show_module_breakdown %}
<div id="module_container">
<div class="row">
<div class="col-xl-12">
<h2>Commits by Module</h2>
</div>
</div>
<div class="row">
<div class="col-xl-6 order-xl-last">
<div id="module_chart"></div>
</div>
<div class="col-xl-6 order-xl-first">
<table id="module_table" class="display">
<thead>
<tr>
<th>#</th>
<th>Module</th>
<th>Commits</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
{% endif %}
{% if show_engineer_breakdown %}
<div id="engineer_container">
<h2>Commits by Contributor</h2>
<table id="engineer_table" class="display">
<thead>
<tr>
<th>#</th>
<th>Contributor</th>
<th>Commits</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
{% endif %}
{% if show_user_profile %}
{{ user_profile.show_user_profile(user_id=user_id) }}
{% endif %}
{% if show_user_activity %}
{{ activity_log.show_activity_log(gravatar_size=32, show_all=False) }}
{% endif %}
{% if show_contribution_on_left %}
{{ contribution_summary.show_contribution_summary(show_all=False) }}
{% endif %}
{% if show_bp_breakdown %}
<div id="bp_container">
<h2>Blueprint popularity</h2>
<div style="font-style: italic;">
This metric shows how many times a blueprint was mentioned in emails and commit messages.
</div>
<div id="bp_chart" style="width: 300px;height:285px;" width="300" height="285"></div>
<table id="bp_table" class="display">
<thead>
<tr>
<th>#</th>
<th>Blueprint</th>
<th>Status</th>
<th>Date</th>
<th>Mentions</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div class="spacer"></div>
</div>
{% endif %}
{% if show_languages_breakdown %}
<div id="language_container">
<h2>Languages</h2>
<div id="language_chart" style="width: 300px;height:285px;" width="300" height="285"></div>
<table id="language_table" class="display">
<thead>
<tr>
<th>#</th>
<th>Language</th>
<th>Translations</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div class="spacer"></div>
</div>
{% endif %}
{% if show_contribution_on_right %}
{{ contribution_summary.show_contribution_summary(show_all=False) }}
{% endif %}
{% if show_module_activity %}
{{ activity_log.show_activity_log(gravatar_size=32, show_all=False) }}
{% endif %}
{% endblock %}
{% block center_frame %}
{% endblock %}
{% block right_frame %}
{% endblock %}

View File

@ -0,0 +1,173 @@
{% extends "base.html" %}
{% block head %}
<script type="text/javascript">
$(document).ready(function () {
initSelectors("");
$(".select2-selection__arrow")
.addClass("material-icons")
.html("arrow_drop_down");
});
$(function () {
$(document).tooltip();
});
</script>
{% block scripts %}{% endblock %}
{% endblock %}
{% block body %}
<div class="page">
{% if not runtime_storage_update_time %}
<div class="banner">The data is being loaded now and is not complete</div>
{% set update_time_title = '' %}
{% else %}
{% if runtime_storage_update_time is too_old %}
<div class="banner">The data was last updated on {{ runtime_storage_update_time_str }}</div>
{% endif %}
{% set update_time_title = 'Last updated on ' + runtime_storage_update_time_str %}
{% endif %}
<div class="container">
<div class="aheader">
<div id="analytics_header">
<div class="row">
<div class="col-lg-3">
<div id="logo" class="text-center">
<a href="{{ url_for('overview') }}">
<img
src="{{ url_for('static', filename='images/stackalytics_logo.png') }}"
class="img-fluid" alt="Stackalytics">
</a>
</div>
</div>
<div class="col-lg-8">
<div class="stackamenu text-center">
<ul id="menu-stackamenu" class="list-inline">
<li class="list-inline-item"><a href="/"><span class="menu-item">OpenStack Foundation</span></a></li>
<li class="list-inline-item"><a href="/cncf"><span class="menu-item">CNCF</span></a></li>
<li class="list-inline-item current-menu-item"><a href="/unaffiliated"><span class="menu-item">Other Projects</span></a></li>
</ul>
</div>
</div>
<div class="col-lg-1">
<a class="about" href="https://wiki.openstack.org/wiki/Stackalytics" target="_blank"
title="{{ update_time_title }}">
About
</a>
</div>
</div>
<div class="drops">
<div class="row">
<div class="col-md" style="display: none;">
<label for="release_selector" title="Official releases of OpenStack">Release</label>
<input type="hidden" id="release_selector" style="width: 100%"
data-placeholder="Select release"/>
</div>
<div class="col-md">
<label for="date_selector" title="Official releases of OpenStack">Date</label>
<input type="hidden" id="date_selector" style="width: 100%"
data-placeholder="Select date"/>
</div>
<div class="col-md">
<label for="project_type_selector" title="Project type groups modules of the same kind. 'OpenStack' are projects defined in the official governance projects.yaml.
'OpenStack Others' are projects not included into any program. 'Complementary' are projects related to OpenStack ecosystem">Project
Type</label>
<input type="hidden" id="project_type_selector" style="width: 100%"
data-placeholder="Select project type"/>
</div>
<div class="col-md">
<label for="module_selector"
title="Module represents a repo (black), official project (violet) or pre-configured group of modules (cyan)">Module</label>
<input type="hidden" id="module_selector" style="width: 100%"
data-placeholder="Any module"/>
</div>
<div class="col-md">
<label for="company_selector" title="Company name">Company</label>
<input type="hidden" id="company_selector" style="width: 100%"
data-placeholder="Any company"/>
</div>
<div class="col-md">
<label for="user_id_selector"
title="Name of contributor as configured in Launchpad or default_data.json">Contributor</label>
<input type="hidden" id="user_id_selector" style="width: 100%"
data-placeholder="Any contributor"/>
</div>
<div class="col-md" style="display: none;">
<label for="metric_selector" title="One of available metrics">Metric</label>
<input type="hidden" id="metric_selector" style="width: 100%"
data-placeholder="Select metric"/>
</div>
</div>
</div>
{% if show_module_details %}
{% endif %}
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-xl-12">
{% block left_frame %}{% endblock %}
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-lg-12">
{% block right_frame %}{% endblock %}
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-lg-12">
{% block center_frame %}{% endblock %}
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-lg-12">
<div id="footer_container">
<div class="row">
<div class="col-lg-9">
Stackalytics displays information collected from open sources, including
<a href="https://git.openstack.org/cgit" style="color: grey;">git.openstack.org</a>
,
<a href="https://review.openstack.org/" style="color: grey;">review.openstack.org</a>
,
<a href="https://launchpad.net/" style="color: grey;">Launchpad</a>
,
<a href="https://github.com/" style="color: grey;">GitHub</a>
,
<a href="https://www.openstack.org/" style="color: grey;">OpenStack.org</a>
,
<a href="http://lists.openstack.org/cgi-bin/mailman/listinfo" style="color: grey;">OpenStack
mailing lists
</a>
.
{% if update_time_title %}{{ update_time_title }}{% endif %}
</div>
<div class="col-lg-3">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -55,6 +55,18 @@ def overview():
pass
@app.route('/cncf')
@decorators.templated()
def cncf():
pass
@app.route('/unaffiliated')
@decorators.templated()
def unaffiliated():
pass
@app.route('/widget')
def widget():
return flask.render_template('widget.html')
@ -504,7 +516,8 @@ def get_user(user_id):
@decorators.jsonify(root=('data', 'default'))
def get_releases_json(**kwargs):
releases = [{'id': release['release_name'],
'text': release['release_name'].capitalize()}
'text': release['release_name'].capitalize(),
'project': release.get('project')}
for release in vault.get_vault()['releases'].values()]
releases.append({'id': 'all', 'text': 'All'})
releases.reverse()

View File

@ -25,8 +25,8 @@ CONNECTION_OPTS = [
PROCESSOR_OPTS = [
cfg.StrOpt('default-data-uri',
default='https://git.openstack.org/cgit/'
'openstack/stackalytics/plain/etc/default_data.json',
default='https://raw.githubusercontent.com/stackalytics/'
'default_data/master/default_data.json',
help='URI for default data. A local file can be used with the '
'prefix "file://". For example, '
'default_data_uri = file:///path/to/default_data.json'),

View File

@ -76,6 +76,9 @@ default_data = {
"release_name": {
"type": "string"
},
"project": {
"type": "string"
},
"end_date": {
"$ref": "#/definitions/date_format"
},

View File

@ -181,6 +181,7 @@ class Git(Vcs):
LOG.debug('Parsing git log for repo uri %s', self.repo['uri'])
os.chdir(self.folder)
if not self._checkout(branch):
return
@ -281,6 +282,9 @@ class Git(Vcs):
def get_last_id(self, branch):
LOG.debug('Get head commit for repo uri: %s', self.repo['uri'])
if not os.path.exists(self.folder):
return None
os.chdir(self.folder)
if not self._checkout(branch):
return None

View File

@ -21,9 +21,12 @@ class TestAPIReleases(test_api.TestAPI):
def test_releases(self):
with test_api.make_runtime_storage(
{'releases': [
{'release_name': 'prehistory', 'end_date': 1365033600},
{'release_name': 'havana', 'end_date': 1381968000},
{'release_name': 'icehouse', 'end_date': 1397692800}],
{'release_name': 'prehistory', 'end_date': 1365033600,
'project': 'nova'},
{'release_name': 'havana', 'end_date': 1381968000,
'project': 'glance'},
{'release_name': 'icehouse', 'end_date': 1397692800,
'project': 'nova-cli'}],
'project_types': [
{'id': 'all', 'title': 'All',
'modules': ['nova', 'glance', 'nova-cli']},
@ -32,6 +35,9 @@ class TestAPIReleases(test_api.TestAPI):
test_api.make_records(record_type=['commit'])):
response = self.app.get('/api/1.0/releases')
releases = test_api.load_json(response)['data']
print(str(releases))
self.assertEqual(3, len(releases))
self.assertIn({'id': 'all', 'text': 'All'}, releases)
self.assertIn({'id': 'icehouse', 'text': 'Icehouse'}, releases)
self.assertIn(
{'project': 'nova-cli', 'id': 'icehouse',
'text': 'Icehouse'}, releases)

View File

@ -125,7 +125,8 @@ class TestConfigFiles(testtools.TestCase):
def _verify_users_in_alphabetical_order(self, file_name):
users = self._read_file(file_name)['users']
self._verify_ordering(
users, key=lambda x: (x.get('launchpad_id') or x.get('github_id')),
users,
key=lambda x: (x.get('launchpad_id') or x.get('github_id') or ''),
msg='List of users should be ordered by launchpad id or ldap id '
'or github id')

View File

@ -68,7 +68,7 @@ class TestHelpers(testtools.TestCase):
observed = helpers.extend_user(user)
self.assertEqual(expected, observed)
mock_make_link.assert_called_once_with('TheCompany', '/', mock.ANY)
mock_make_link.assert_called_once_with('TheCompany', '', mock.ANY)
@mock.patch('time.time')
@mock.patch('stackalytics.dashboard.helpers.make_link')
@ -92,4 +92,4 @@ class TestHelpers(testtools.TestCase):
helpers.extend_user(user)
mock_make_link.assert_called_once_with('Current', '/', mock.ANY)
mock_make_link.assert_called_once_with('Current', '', mock.ANY)