mirror of
https://github.com/tdurieux/anonymous_github.git
synced 2026-04-21 12:56:05 +02:00
Improve mobile layout and redesign admin interface (#665)
This commit is contained in:
Vendored
+1
-1
File diff suppressed because one or more lines are too long
+693
-2
@@ -21,6 +21,10 @@
|
||||
--primary-color: #ffffff;
|
||||
--primary-active-color: #dddddd;
|
||||
|
||||
--admin-nav-bg: rgb(35, 40, 46);
|
||||
--admin-nav-active: rgba(255, 255, 255, 0.1);
|
||||
--admin-stat-bg: rgb(45, 50, 56);
|
||||
|
||||
background-color: var(--canvas-bg-color);
|
||||
color: var(--color);
|
||||
}
|
||||
@@ -47,6 +51,10 @@ body {
|
||||
--primary-color: #ffffff;
|
||||
--primary-active-color: #dddddd;
|
||||
|
||||
--admin-nav-bg: #f1f3f5;
|
||||
--admin-nav-active: rgba(74, 80, 123, 0.1);
|
||||
--admin-stat-bg: #f8f9fa;
|
||||
|
||||
background-color: var(--canvas-bg-color);
|
||||
color: var(--color);
|
||||
}
|
||||
@@ -169,7 +177,13 @@ a:hover {
|
||||
}
|
||||
|
||||
#navbarSupportedContent {
|
||||
padding-right: 200px;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
#navbarSupportedContent {
|
||||
padding-right: 200px;
|
||||
}
|
||||
}
|
||||
|
||||
.generalMessage {
|
||||
@@ -431,7 +445,12 @@ notebook {
|
||||
display: block;
|
||||
text-align: left;
|
||||
padding: 15px;
|
||||
padding-left: 100px;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
notebook {
|
||||
padding-left: 100px;
|
||||
}
|
||||
}
|
||||
|
||||
.nb-output th,
|
||||
@@ -605,4 +624,676 @@ code {
|
||||
|
||||
.diff-remove {
|
||||
background: rgba(200, 100, 100, 0.5);
|
||||
}
|
||||
|
||||
/* ===== Anonymize Page Layout ===== */
|
||||
|
||||
.anonymize-page .sidePanel {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.anonymize-section-title {
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
margin: 16px 0 10px 0;
|
||||
padding-bottom: 6px;
|
||||
border-bottom: 2px solid var(--primary-bg);
|
||||
}
|
||||
|
||||
.anonymize-section-title i {
|
||||
color: var(--primary-bg);
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.anonymize-submit-bar {
|
||||
padding: 12px 0 4px 0;
|
||||
}
|
||||
|
||||
.anonymize-submit-bar .btn {
|
||||
font-size: 1rem;
|
||||
padding: 10px 20px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.anonymize-page .form-check {
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
.anonymize-page .form-check-label {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.anonymize-page .accordion .card-header {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.anonymize-page .accordion .btn {
|
||||
font-weight: 600;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
/* Preview column on desktop */
|
||||
.anonymize-preview-col {
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
/* PR diff overflow */
|
||||
.pr-diff pre {
|
||||
overflow-x: auto;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.anonymize-form-col {
|
||||
height: 100%;
|
||||
max-width: 50%;
|
||||
}
|
||||
|
||||
.anonymize-preview-col {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== Mobile Responsive Improvements ===== */
|
||||
|
||||
/* Mobile-friendly touch targets */
|
||||
@media (max-width: 767px) {
|
||||
.btn {
|
||||
min-height: 38px;
|
||||
padding: 6px 14px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.btn-sm {
|
||||
min-height: 34px;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
.navbar .nav-link {
|
||||
padding: 8px 12px;
|
||||
}
|
||||
|
||||
.navbar .nav-link .fa,
|
||||
.navbar .nav-link .fab {
|
||||
font-size: 24px;
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
.container.page {
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
h1 { font-size: 1.6rem; }
|
||||
h2 { font-size: 1.35rem; }
|
||||
h3 { font-size: 1.15rem; }
|
||||
|
||||
/* Dashboard list items */
|
||||
.col-12.d-flex.px-0.py-3 {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.col-12.d-flex.px-0.py-3 > .d-flex:last-child {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
/* Dropdown menus right-aligned on mobile */
|
||||
.dropdown-menu {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
left: auto;
|
||||
}
|
||||
|
||||
/* Form controls spacing */
|
||||
.form-group {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
font-size: 16px; /* Prevents iOS zoom */
|
||||
}
|
||||
|
||||
/* File explorer mobile layout */
|
||||
.leftCol {
|
||||
max-height: 40vh;
|
||||
border-bottom: 2px solid var(--border-color);
|
||||
}
|
||||
|
||||
/* Status bar wrapping */
|
||||
.status-bar {
|
||||
flex-wrap: wrap;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.status-bar .btn {
|
||||
font-size: 12px;
|
||||
padding: 3px 8px;
|
||||
min-height: 28px;
|
||||
}
|
||||
|
||||
/* Home hero section */
|
||||
#home .display-4 {
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
|
||||
#home h4.subtext-header {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* Progress bars on dashboard */
|
||||
.progress {
|
||||
min-width: 120px !important;
|
||||
}
|
||||
|
||||
/* Badge readability */
|
||||
.badge {
|
||||
font-size: 55%;
|
||||
padding: 3px 6px;
|
||||
}
|
||||
|
||||
/* Search & filter toolbar */
|
||||
.col-2.input-group {
|
||||
width: 100% !important;
|
||||
max-width: 100%;
|
||||
flex: 0 0 100%;
|
||||
}
|
||||
|
||||
/* Metadata spans wrapping */
|
||||
.color-text-secondary span {
|
||||
display: inline-block;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
/* Ko-fi widget hidden on mobile */
|
||||
.floatingchat-container-wrap {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Metrics cards on home */
|
||||
.col-md-4 h3 {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
/* ---- Anonymize page mobile ---- */
|
||||
|
||||
.anonymize-page > .row {
|
||||
height: auto !important;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
.anonymize-page .sidePanel {
|
||||
height: auto !important;
|
||||
overflow: visible !important;
|
||||
border-bottom: 2px solid var(--border-color);
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
|
||||
.anonymize-page .sidePanel .card,
|
||||
.anonymize-page .sidePanel .container {
|
||||
max-width: 100%;
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
.anonymize-form-col {
|
||||
max-width: 100% !important;
|
||||
flex: 0 0 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.anonymize-preview-col {
|
||||
height: auto !important;
|
||||
max-height: none;
|
||||
border-top: 1px solid var(--border-color);
|
||||
padding-top: 12px !important;
|
||||
}
|
||||
|
||||
.anonymize-section-title {
|
||||
font-size: 0.95rem;
|
||||
margin: 12px 0 8px 0;
|
||||
}
|
||||
|
||||
.anonymize-submit-bar {
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
background: var(--sidebar-bg-color);
|
||||
padding: 10px 0;
|
||||
margin: 0 -8px;
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
border-top: 1px solid var(--border-color);
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.anonymize-submit-bar .btn {
|
||||
font-size: 1rem;
|
||||
padding: 12px 20px;
|
||||
}
|
||||
|
||||
.anonymize-page .card-title {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
/* Compact checkboxes on mobile */
|
||||
.anonymize-page .form-check {
|
||||
padding-top: 6px;
|
||||
padding-bottom: 6px;
|
||||
min-height: 36px;
|
||||
}
|
||||
|
||||
.anonymize-page .form-check-label {
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.anonymize-page .card-body {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
/* PR preview on mobile */
|
||||
.pr-title {
|
||||
font-size: 1.15rem;
|
||||
}
|
||||
|
||||
.pr-diff pre {
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.pr-comment .mb-1 h5 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.nav-tabs .nav-link {
|
||||
padding: 8px 12px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Tablet tweaks */
|
||||
@media (min-width: 768px) and (max-width: 991px) {
|
||||
.container.page {
|
||||
max-width: 100%;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
.leftCol {
|
||||
flex: 0 0 250px;
|
||||
width: 250px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mobile toggle for file explorer sidebar */
|
||||
.sidebar-toggle {
|
||||
display: none;
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
text-align: center;
|
||||
background: var(--sidebar-bg-color);
|
||||
border: 1px solid var(--border-color);
|
||||
color: var(--color);
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.sidebar-toggle {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.leftCol.collapsed {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== Admin Interface Improvements ===== */
|
||||
|
||||
/* Admin navigation tabs */
|
||||
.admin-nav {
|
||||
display: flex;
|
||||
background: var(--admin-nav-bg);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 6px;
|
||||
padding: 4px;
|
||||
margin-bottom: 20px;
|
||||
gap: 4px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.admin-nav a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 8px 16px;
|
||||
border-radius: 4px;
|
||||
color: var(--color);
|
||||
text-decoration: none;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
transition: background-color 0.15s, color 0.15s;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.admin-nav a:hover {
|
||||
background: var(--admin-nav-active);
|
||||
color: var(--color);
|
||||
}
|
||||
|
||||
.admin-nav a.active {
|
||||
background: var(--primary-bg);
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.admin-nav a i {
|
||||
font-size: 14px;
|
||||
width: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.admin-nav {
|
||||
flex-direction: column;
|
||||
}
|
||||
.admin-nav a {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
/* Admin stat cards */
|
||||
.admin-stats {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
|
||||
gap: 12px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.admin-stat-card {
|
||||
background: var(--admin-stat-bg);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 6px;
|
||||
padding: 14px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.admin-stat-card .stat-value {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 700;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.admin-stat-card .stat-label {
|
||||
font-size: 0.8rem;
|
||||
opacity: 0.7;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
/* Admin toolbar */
|
||||
.admin-toolbar {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
padding: 12px 0;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.admin-toolbar .form-control {
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.admin-toolbar .form-control {
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.admin-toolbar .pagination-compact {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.admin-toolbar .pagination-compact input {
|
||||
width: 60px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.admin-toolbar .pagination-compact .btn {
|
||||
padding: 4px 10px;
|
||||
min-height: 34px;
|
||||
}
|
||||
|
||||
/* Admin list items */
|
||||
.admin-list-item {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
padding: 12px 0;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.admin-list-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.admin-list-item .item-main {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.admin-list-item .item-title {
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 4px;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.admin-list-item .item-meta {
|
||||
font-size: 0.85rem;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.admin-list-item .item-meta span {
|
||||
margin-right: 12px;
|
||||
display: inline-block;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.admin-list-item .item-actions {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.admin-list-item {
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
.admin-list-item .item-actions {
|
||||
align-self: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
/* Status badge improvements */
|
||||
.status-badge {
|
||||
display: inline-block;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
padding: 2px 8px;
|
||||
border-radius: 10px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.3px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.status-badge.status-ready {
|
||||
background: #28a745;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.status-badge.status-error {
|
||||
background: #dc3545;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.status-badge.status-preparing,
|
||||
.status-badge.status-download {
|
||||
background: #17a2b8;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.status-badge.status-expired,
|
||||
.status-badge.status-removed,
|
||||
.status-badge.status-removing,
|
||||
.status-badge.status-expiring {
|
||||
background: #ffc107;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.status-badge.status-active {
|
||||
background: #28a745;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Admin queue job cards */
|
||||
.queue-job-card {
|
||||
background: var(--admin-stat-bg);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 6px;
|
||||
padding: 12px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.queue-job-card .job-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 6px;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.queue-job-card .job-id {
|
||||
font-weight: 600;
|
||||
font-size: 0.95rem;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.queue-job-card .job-timestamps {
|
||||
font-size: 0.8rem;
|
||||
opacity: 0.7;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.queue-job-card .job-actions {
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.queue-job-card .job-actions .btn {
|
||||
font-size: 12px;
|
||||
padding: 3px 10px;
|
||||
}
|
||||
|
||||
/* Admin section headers */
|
||||
.admin-section-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 10px 0;
|
||||
margin-top: 12px;
|
||||
border-bottom: 2px solid var(--primary-bg);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.admin-section-header h2 {
|
||||
margin: 0;
|
||||
font-size: 1.15rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.admin-section-header .section-count {
|
||||
background: var(--primary-bg);
|
||||
color: var(--primary-color);
|
||||
font-size: 0.8rem;
|
||||
padding: 2px 10px;
|
||||
border-radius: 10px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* User detail card */
|
||||
.user-detail-card {
|
||||
background: var(--admin-stat-bg);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.user-detail-card .user-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
margin-bottom: 16px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.user-detail-card .user-header img {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.user-detail-card .user-header h1 {
|
||||
margin: 0;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.user-detail-grid {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
gap: 8px 16px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.user-detail-grid .detail-label {
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.user-detail-grid .detail-value {
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.user-detail-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.user-detail-grid .detail-label {
|
||||
margin-top: 8px;
|
||||
border-top: 1px solid var(--border-color);
|
||||
padding-top: 8px;
|
||||
}
|
||||
.user-detail-grid .detail-label:first-child {
|
||||
border-top: none;
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Empty state */
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 40px 20px;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.empty-state i {
|
||||
font-size: 2rem;
|
||||
margin-bottom: 10px;
|
||||
display: block;
|
||||
}
|
||||
@@ -1,290 +1,196 @@
|
||||
<div class="container page">
|
||||
<div class="row">
|
||||
<div class="border-bottom color-border-secondary py-3 w-100">
|
||||
<div class="d-flex flex-items-start w-100">
|
||||
<form class="w-100" aria-label="Conferences" accept-charset="UTF-8">
|
||||
<div class="d-flex flex-column flex-lg-row flex-auto">
|
||||
<div class="mb-1 mb-md-0 mr-md-3">
|
||||
<input
|
||||
type="search"
|
||||
id="search"
|
||||
class="form-control"
|
||||
aria-label="Find a conference…"
|
||||
placeholder="Find a conference…"
|
||||
autocomplete="off"
|
||||
ng-model="query.search"
|
||||
/>
|
||||
</div>
|
||||
<!-- Admin Navigation -->
|
||||
<nav class="admin-nav">
|
||||
<a href="/admin/">
|
||||
<i class="fas fa-code-branch"></i> Repositories
|
||||
</a>
|
||||
<a href="/admin/users">
|
||||
<i class="fas fa-users"></i> Users
|
||||
</a>
|
||||
<a href="/admin/conferences" class="active">
|
||||
<i class="fas fa-chalkboard-teacher"></i> Conferences
|
||||
</a>
|
||||
<a href="/admin/queues">
|
||||
<i class="fas fa-tasks"></i> Queues
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
<div class="mb-1 mb-md-0 mr-md-3 col-2 input-group">
|
||||
<input
|
||||
type="number"
|
||||
id="page"
|
||||
class="form-control"
|
||||
autocomplete="off"
|
||||
ng-model="query.page"
|
||||
min="1"
|
||||
max="{{totalPage}}"
|
||||
/>
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text">/{{totalPage}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Summary Stats -->
|
||||
<div class="admin-stats">
|
||||
<div class="admin-stat-card">
|
||||
<div class="stat-value" ng-bind="total >= 0 ? (total | number) : '...'"></div>
|
||||
<div class="stat-label">Total Conferences</div>
|
||||
</div>
|
||||
<div class="admin-stat-card">
|
||||
<div class="stat-value">{{query.page}}/{{totalPage || '...'}}</div>
|
||||
<div class="stat-label">Current Page</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-wrap">
|
||||
<div class="dropdown mt-1 mt-lg-0 mr-1">
|
||||
<button
|
||||
class="btn btn-secondary dropdown-toggle"
|
||||
type="button"
|
||||
id="dropdownSort"
|
||||
data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
>
|
||||
Sort
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdownSort">
|
||||
<h6 class="dropdown-header">Select order</h6>
|
||||
<div class="form-check dropdown-item">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="radio"
|
||||
name="sort"
|
||||
id="sortFullName"
|
||||
value="source.conferenceName"
|
||||
ng-model="query.sort"
|
||||
/>
|
||||
<label class="form-check-label" for="sortFullName">
|
||||
Conference
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check dropdown-item">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="radio"
|
||||
name="sort"
|
||||
id="sortAnonymizeDate"
|
||||
value="anonymizeDate"
|
||||
ng-model="query.sort"
|
||||
/>
|
||||
<label class="form-check-label" for="sortAnonymizeDate">
|
||||
Anonymize Date
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check dropdown-item">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="radio"
|
||||
name="sort"
|
||||
id="sortStatus"
|
||||
value="status"
|
||||
ng-model="query.sort"
|
||||
/>
|
||||
<label class="form-check-label" for="sortStatus">
|
||||
Status
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check dropdown-item">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="radio"
|
||||
name="sort"
|
||||
id="sortLastView"
|
||||
value="lastView"
|
||||
ng-model="query.sort"
|
||||
/>
|
||||
<label class="form-check-label" for="sortLastView">
|
||||
Last View
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check dropdown-item">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="radio"
|
||||
name="sort"
|
||||
id="sortPageView"
|
||||
value="pageView"
|
||||
ng-model="query.sort"
|
||||
/>
|
||||
<label class="form-check-label" for="sortPageView">
|
||||
Page View
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Toolbar -->
|
||||
<div class="admin-toolbar">
|
||||
<input
|
||||
type="search"
|
||||
class="form-control"
|
||||
aria-label="Search conferences..."
|
||||
placeholder="Search conferences..."
|
||||
autocomplete="off"
|
||||
ng-model="query.search"
|
||||
/>
|
||||
|
||||
<div class="dropdown mt-1 mt-lg-0 mr-1">
|
||||
<button
|
||||
class="btn btn-secondary dropdown-toggle"
|
||||
type="button"
|
||||
id="dropdownStatus"
|
||||
data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
>
|
||||
Status
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdownStatus">
|
||||
<h6 class="dropdown-header">Select status</h6>
|
||||
<div class="form-check dropdown-item">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="checkbox"
|
||||
name="sort"
|
||||
id="statusReady"
|
||||
value="ready"
|
||||
ng-model="query.ready"
|
||||
/>
|
||||
<label class="form-check-label" for="statusReady">
|
||||
Ready
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check dropdown-item">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="checkbox"
|
||||
name="sort"
|
||||
id="statusExpired"
|
||||
value="expired"
|
||||
ng-model="query.expired"
|
||||
/>
|
||||
<label class="form-check-label" for="statusExpired">
|
||||
Expired
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check dropdown-item">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="checkbox"
|
||||
name="sort"
|
||||
id="statusExpired"
|
||||
value="expired"
|
||||
ng-model="query.preparing"
|
||||
/>
|
||||
<label class="form-check-label" for="statusExpired">
|
||||
Preparing
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check dropdown-item">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="checkbox"
|
||||
name="sort"
|
||||
id="statusRemoved"
|
||||
value="removed"
|
||||
ng-model="query.removed"
|
||||
/>
|
||||
<label class="form-check-label" for="statusRemoved">
|
||||
Removed
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check dropdown-item">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="checkbox"
|
||||
name="sort"
|
||||
id="statusRemoved"
|
||||
value="removed"
|
||||
ng-model="query.error"
|
||||
/>
|
||||
<label class="form-check-label" for="statusRemoved">
|
||||
Error
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="pagination-compact">
|
||||
<button class="btn btn-sm" ng-click="query.page = Math.max(1, query.page - 1)" ng-disabled="query.page <= 1">
|
||||
<i class="fas fa-chevron-left"></i>
|
||||
</button>
|
||||
<input
|
||||
type="number"
|
||||
class="form-control form-control-sm"
|
||||
ng-model="query.page"
|
||||
min="1"
|
||||
max="{{totalPage}}"
|
||||
/>
|
||||
<span>/{{totalPage}}</span>
|
||||
<button class="btn btn-sm" ng-click="query.page = Math.min(totalPage, query.page + 1)" ng-disabled="query.page >= totalPage">
|
||||
<i class="fas fa-chevron-right"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="dropdown">
|
||||
<button
|
||||
class="btn btn-sm dropdown-toggle"
|
||||
type="button"
|
||||
id="dropdownSort"
|
||||
data-toggle="dropdown"
|
||||
>
|
||||
<i class="fas fa-sort"></i> Sort
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdownSort">
|
||||
<h6 class="dropdown-header">Sort by</h6>
|
||||
<a class="dropdown-item" href="#" ng-click="query.sort = 'source.conferenceName'">
|
||||
<i class="fas fa-check" ng-show="query.sort == 'source.conferenceName'"></i> Conference
|
||||
</a>
|
||||
<a class="dropdown-item" href="#" ng-click="query.sort = 'anonymizeDate'">
|
||||
<i class="fas fa-check" ng-show="query.sort == 'anonymizeDate'"></i> Anonymize Date
|
||||
</a>
|
||||
<a class="dropdown-item" href="#" ng-click="query.sort = 'status'">
|
||||
<i class="fas fa-check" ng-show="query.sort == 'status'"></i> Status
|
||||
</a>
|
||||
<a class="dropdown-item" href="#" ng-click="query.sort = 'lastView'">
|
||||
<i class="fas fa-check" ng-show="query.sort == 'lastView'"></i> Last View
|
||||
</a>
|
||||
<a class="dropdown-item" href="#" ng-click="query.sort = 'pageView'">
|
||||
<i class="fas fa-check" ng-show="query.sort == 'pageView'"></i> Page Views
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="p-0 m-0 w-100">
|
||||
<li
|
||||
class="col-12 d-flex px-0 py-3 border-bottom color-border-secondary"
|
||||
ng-class="{'expired': conference.status == 'expired','removed': conference.status == 'removed','error': conference.status == 'error' }"
|
||||
ng-repeat="conference in conferences| filter:conferenceFiler| orderBy:orderBy as filteredConferences"
|
||||
|
||||
<div class="dropdown">
|
||||
<button
|
||||
class="btn btn-sm dropdown-toggle"
|
||||
type="button"
|
||||
id="dropdownStatus"
|
||||
data-toggle="dropdown"
|
||||
>
|
||||
<div class="w-100">
|
||||
<div class="">
|
||||
<h3>
|
||||
<a
|
||||
ng-href="/conference/{{conference.conferenceID}}"
|
||||
ng-bind="conference.name"
|
||||
></a>
|
||||
<span
|
||||
class="badge"
|
||||
ng-class="{'badge-warning': conference.status == 'removed' || conference.status == 'expired', 'badge-success': conference.status == 'ready', 'badge-danger': ''}"
|
||||
ng-bind="conference.status | title"
|
||||
></span>
|
||||
</h3>
|
||||
<span class="color-text-secondary mb-1 ng-binding">
|
||||
Conference ID: '{{conference.conferenceID}}'
|
||||
</span>
|
||||
</div>
|
||||
<div class="color-text-secondary mt-2">
|
||||
<span
|
||||
class="ml-0 mr-3"
|
||||
title="# conference: {{conference.nbConference || 0 | number}}"
|
||||
data-toggle="tooltip"
|
||||
data-placement="bottom"
|
||||
>
|
||||
<i class="fas fa-table"></i>
|
||||
{{::conference.repositories.length || 0 | number}}</span
|
||||
>
|
||||
<span class="ml-0 mr-3">
|
||||
<i class="fas fa-euro-sign"></i>
|
||||
Total: {{conference.price || 0 | number}} €
|
||||
</span>
|
||||
<span class="ml-0 mr-3">
|
||||
<i class="fas fa-calendar-alt"></i>
|
||||
From {{conference.startDate | date}} to {{conference.endDate |
|
||||
date}}</span
|
||||
>
|
||||
</div>
|
||||
<i class="fas fa-filter"></i> Status
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdownStatus">
|
||||
<h6 class="dropdown-header">Filter by status</h6>
|
||||
<label class="dropdown-item mb-0">
|
||||
<input type="checkbox" ng-model="query.ready" /> Ready
|
||||
</label>
|
||||
<label class="dropdown-item mb-0">
|
||||
<input type="checkbox" ng-model="query.preparing" /> Preparing
|
||||
</label>
|
||||
<label class="dropdown-item mb-0">
|
||||
<input type="checkbox" ng-model="query.expired" /> Expired
|
||||
</label>
|
||||
<label class="dropdown-item mb-0">
|
||||
<input type="checkbox" ng-model="query.removed" /> Removed
|
||||
</label>
|
||||
<label class="dropdown-item mb-0">
|
||||
<input type="checkbox" ng-model="query.error" /> Error
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Conference List -->
|
||||
<div
|
||||
class="admin-list-item"
|
||||
ng-repeat="conference in conferences | filter:conferenceFiler | orderBy:orderBy as filteredConferences"
|
||||
>
|
||||
<div class="item-main">
|
||||
<div class="item-title">
|
||||
<a
|
||||
ng-href="/conference/{{conference.conferenceID}}"
|
||||
ng-bind="conference.name"
|
||||
></a>
|
||||
<span
|
||||
class="status-badge"
|
||||
ng-class="'status-' + conference.status"
|
||||
>{{conference.status | title}}</span>
|
||||
</div>
|
||||
<div class="item-meta">
|
||||
<span>
|
||||
<i class="fas fa-fingerprint"></i> ID: {{conference.conferenceID}}
|
||||
</span>
|
||||
<span>
|
||||
<i class="fas fa-table"></i> {{::conference.repositories.length || 0 | number}} repos
|
||||
</span>
|
||||
<span>
|
||||
<i class="fas fa-euro-sign"></i> {{conference.price || 0 | number}} €
|
||||
</span>
|
||||
<span>
|
||||
<i class="fas fa-calendar-alt"></i>
|
||||
{{conference.startDate | date}} – {{conference.endDate | date}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-actions">
|
||||
<div class="dropdown">
|
||||
<button
|
||||
class="btn dropdown-toggle btn-sm"
|
||||
type="button"
|
||||
data-toggle="dropdown"
|
||||
>
|
||||
Actions
|
||||
</button>
|
||||
<div class="dropdown-menu dropdown-menu-right">
|
||||
<a class="dropdown-item" href="/conference/{{conference.conferenceID}}/edit">
|
||||
<i class="far fa-edit"></i> Edit
|
||||
</a>
|
||||
<a class="dropdown-item" href="/conference/{{conference.conferenceID}}/">
|
||||
<i class="fa fa-eye"></i> View
|
||||
</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a
|
||||
class="dropdown-item text-danger"
|
||||
href="#"
|
||||
ng-show="conference.status != 'removed'"
|
||||
ng-click="removeConference(conference)"
|
||||
>
|
||||
<i class="fas fa-trash-alt"></i> Remove
|
||||
</a>
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<div class="dropdown">
|
||||
<button
|
||||
class="btn black_border dropdown-toggle btn-sm"
|
||||
type="button"
|
||||
id="dropdownMenuButton"
|
||||
data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
>
|
||||
Actions
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="/conference/{{conference.conferenceID}}/edit"
|
||||
>
|
||||
<i class="far fa-edit" aria-hidden="true"></i> Edit
|
||||
</a>
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="#"
|
||||
ng-show="conference.status != 'removed'"
|
||||
ng-click="removeConference(conference)"
|
||||
>
|
||||
<i class="fas fa-trash-alt"></i> Remove
|
||||
</a>
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="/conference/{{conference.conferenceID}}/"
|
||||
>
|
||||
<i class="fa fa-eye" aria-hidden="true"></i> View conference
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li
|
||||
class="col-12 d-flex px-0 py-3 border-bottom color-border-secondary"
|
||||
ng-if="filteredConferences.length == 0"
|
||||
>
|
||||
There is no conference to display.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="empty-state" ng-if="filteredConferences.length == 0">
|
||||
<i class="fas fa-chalkboard-teacher"></i>
|
||||
No conferences match the current filters.
|
||||
</div>
|
||||
|
||||
<!-- Bottom pagination -->
|
||||
<div class="admin-toolbar" ng-if="totalPage > 1" style="justify-content: center; border-bottom: none;">
|
||||
<div class="pagination-compact">
|
||||
<button class="btn btn-sm" ng-click="query.page = Math.max(1, query.page - 1)" ng-disabled="query.page <= 1">
|
||||
<i class="fas fa-chevron-left"></i> Previous
|
||||
</button>
|
||||
<span>Page {{query.page}} of {{totalPage}}</span>
|
||||
<button class="btn btn-sm" ng-click="query.page = Math.min(totalPage, query.page + 1)" ng-disabled="query.page >= totalPage">
|
||||
Next <i class="fas fa-chevron-right"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+192
-223
@@ -1,226 +1,195 @@
|
||||
<div class="container page">
|
||||
<div class="row">
|
||||
<h1>Download jobs</h1>
|
||||
<ul class="p-0 m-0 w-100">
|
||||
<li
|
||||
class="col-12 d-flex px-0 py-3 border-bottom color-border-secondary"
|
||||
ng-repeat="job in downloadJobs as filteredDownloadJobs"
|
||||
>
|
||||
<div class="w-100">
|
||||
<div class="">
|
||||
<h3>
|
||||
<a target="__blank" ng-href="/r/{{job.id}}" ng-bind="job.id"></a>
|
||||
<span class="badge" ng-bind="job.progress.status | title"></span>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="color-text-secondary mb-1">
|
||||
<span ng-if="job.timestamp">
|
||||
Created on:
|
||||
<span ng-bind="job.timestamp | humanTime"></span>
|
||||
</span>
|
||||
<span ng-if="job.finishedOn">
|
||||
Finished on:
|
||||
<span ng-bind="job.finishedOn | humanTime"></span>
|
||||
</span>
|
||||
<span ng-if="job.processedOn">
|
||||
Processed on:
|
||||
<span ng-bind="job.processedOn | humanTime"></span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<pre
|
||||
ng-repeat="stack in job.stacktrace track by $index"
|
||||
><code ng-bind="stack"></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<div class="dropdown">
|
||||
<button
|
||||
class="btn black_border dropdown-toggle btn-sm"
|
||||
type="button"
|
||||
id="dropdownMenuButton"
|
||||
data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
>
|
||||
Actions
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="#"
|
||||
ng-click="removeJob('download', job)"
|
||||
>
|
||||
<i class="fas fa-trash-alt"></i> Remove
|
||||
</a>
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="#"
|
||||
ng-click="retryJob('download', job)"
|
||||
>
|
||||
<i class="fas fa-sync"></i> Retry
|
||||
</a>
|
||||
<a class="dropdown-item" href="/anonymize/{{job.id}}">
|
||||
<i class="far fa-edit" aria-hidden="true"></i> Edit
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li
|
||||
class="col-12 d-flex px-0 py-3 border-bottom color-border-secondary"
|
||||
ng-if="filteredDownloadJobs.length == 0"
|
||||
>
|
||||
There is no job to display.
|
||||
</li>
|
||||
</ul>
|
||||
<h1>Remove jobs</h1>
|
||||
<ul class="p-0 m-0 w-100">
|
||||
<li
|
||||
class="col-12 d-flex px-0 py-3 border-bottom color-border-secondary"
|
||||
ng-repeat="job in removeJobs as filteredRemoveJobs"
|
||||
>
|
||||
<div class="w-100">
|
||||
<div class="">
|
||||
<h3>
|
||||
<a target="__blank" ng-href="/r/{{job.id}}" ng-bind="job.id"></a>
|
||||
<span class="badge" ng-bind="job.progress.status | title"></span>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="color-text-secondary mb-1">
|
||||
<span ng-if="job.timestamp">
|
||||
Created on:
|
||||
<span ng-bind="job.timestamp | humanTime"></span>
|
||||
</span>
|
||||
<span ng-if="job.finishedOn">
|
||||
Finished on:
|
||||
<span ng-bind="job.finishedOn | humanTime"></span>
|
||||
</span>
|
||||
<span ng-if="job.processedOn">
|
||||
Processed on:
|
||||
<span ng-bind="job.processedOn | humanTime"></span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<pre
|
||||
ng-repeat="stack in job.stacktrace track by $index"
|
||||
><code ng-bind="stack"></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<div class="dropdown">
|
||||
<button
|
||||
class="btn black_border dropdown-toggle btn-sm"
|
||||
type="button"
|
||||
id="dropdownMenuButton"
|
||||
data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
>
|
||||
Actions
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="#"
|
||||
ng-click="removeJob('remove', job)"
|
||||
>
|
||||
<i class="fas fa-trash-alt"></i> Remove
|
||||
</a>
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="#"
|
||||
ng-click="retryJob('remove', job)"
|
||||
>
|
||||
<i class="fas fa-sync"></i> Retry
|
||||
</a>
|
||||
<a class="dropdown-item" href="/anonymize/{{job.id}}">
|
||||
<i class="far fa-edit" aria-hidden="true"></i> Edit
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li
|
||||
class="col-12 d-flex px-0 py-3 border-bottom color-border-secondary"
|
||||
ng-if="filteredRemoveJobs.length == 0"
|
||||
>
|
||||
There is no job to display.
|
||||
</li>
|
||||
</ul>
|
||||
<h1>Remove Cache</h1>
|
||||
<ul class="p-0 m-0 w-100">
|
||||
<li
|
||||
class="col-12 d-flex px-0 py-3 border-bottom color-border-secondary"
|
||||
ng-repeat="job in removeCaches as filteredRemoveCache"
|
||||
>
|
||||
<div class="w-100">
|
||||
<div class="">
|
||||
<h3>
|
||||
<a target="__blank" ng-href="/r/{{job.id}}" ng-bind="job.id"></a>
|
||||
<span class="badge" ng-bind="job.progress.status | title"></span>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="color-text-secondary mb-1">
|
||||
<span ng-if="job.timestamp">
|
||||
Created on:
|
||||
<span ng-bind="job.timestamp | humanTime"></span>
|
||||
</span>
|
||||
<span ng-if="job.finishedOn">
|
||||
Finished on:
|
||||
<span ng-bind="job.finishedOn | humanTime"></span>
|
||||
</span>
|
||||
<span ng-if="job.processedOn">
|
||||
Processed on:
|
||||
<span ng-bind="job.processedOn | humanTime"></span>
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<pre
|
||||
ng-repeat="stack in job.stacktrace track by $index"
|
||||
><code ng-bind="stack"></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<div class="dropdown">
|
||||
<button
|
||||
class="btn black_border dropdown-toggle btn-sm"
|
||||
type="button"
|
||||
id="dropdownMenuButton"
|
||||
data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
>
|
||||
Actions
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="#"
|
||||
ng-click="removeJob('cache', job)"
|
||||
>
|
||||
<i class="fas fa-trash-alt"></i> Remove
|
||||
</a>
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="#"
|
||||
ng-click="retryJob('cache', job)"
|
||||
>
|
||||
<i class="fas fa-sync"></i> Retry
|
||||
</a>
|
||||
<a class="dropdown-item" href="/anonymize/{{job.id}}">
|
||||
<i class="far fa-edit" aria-hidden="true"></i> Edit
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li
|
||||
class="col-12 d-flex px-0 py-3 border-bottom color-border-secondary"
|
||||
ng-if="filteredRemoveCache.length == 0"
|
||||
>
|
||||
There is no job to display.
|
||||
</li>
|
||||
</ul>
|
||||
<!-- Admin Navigation -->
|
||||
<nav class="admin-nav">
|
||||
<a href="/admin/">
|
||||
<i class="fas fa-code-branch"></i> Repositories
|
||||
</a>
|
||||
<a href="/admin/users">
|
||||
<i class="fas fa-users"></i> Users
|
||||
</a>
|
||||
<a href="/admin/conferences">
|
||||
<i class="fas fa-chalkboard-teacher"></i> Conferences
|
||||
</a>
|
||||
<a href="/admin/queues" class="active">
|
||||
<i class="fas fa-tasks"></i> Queues
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
<!-- Summary Stats -->
|
||||
<div class="admin-stats">
|
||||
<div class="admin-stat-card">
|
||||
<div class="stat-value">{{downloadJobs.length || 0}}</div>
|
||||
<div class="stat-label">Download Jobs</div>
|
||||
</div>
|
||||
<div class="admin-stat-card">
|
||||
<div class="stat-value">{{removeJobs.length || 0}}</div>
|
||||
<div class="stat-label">Remove Jobs</div>
|
||||
</div>
|
||||
<div class="admin-stat-card">
|
||||
<div class="stat-value">{{removeCaches.length || 0}}</div>
|
||||
<div class="stat-label">Cache Jobs</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Download Jobs -->
|
||||
<div class="admin-section-header">
|
||||
<h2><i class="fas fa-download mr-1"></i> Download Jobs</h2>
|
||||
<span class="section-count">{{downloadJobs.length || 0}}</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="queue-job-card"
|
||||
ng-repeat="job in downloadJobs as filteredDownloadJobs"
|
||||
>
|
||||
<div class="job-header">
|
||||
<div class="job-id">
|
||||
<a target="_blank" ng-href="/r/{{job.id}}" ng-bind="job.id"></a>
|
||||
<span
|
||||
class="status-badge"
|
||||
ng-class="'status-' + job.progress.status"
|
||||
>{{job.progress.status | title}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="job-timestamps">
|
||||
<span ng-if="job.timestamp">
|
||||
<i class="fas fa-clock"></i> Created: {{job.timestamp | humanTime}}
|
||||
</span>
|
||||
<span ng-if="job.processedOn">
|
||||
<i class="fas fa-cog"></i> Processed: {{job.processedOn | humanTime}}
|
||||
</span>
|
||||
<span ng-if="job.finishedOn">
|
||||
<i class="fas fa-check"></i> Finished: {{job.finishedOn | humanTime}}
|
||||
</span>
|
||||
</div>
|
||||
<div ng-if="job.stacktrace.length">
|
||||
<pre
|
||||
ng-repeat="stack in job.stacktrace track by $index"
|
||||
style="font-size: 0.8rem; max-height: 100px; overflow: auto; margin: 6px 0 0 0"
|
||||
><code ng-bind="stack"></code></pre>
|
||||
</div>
|
||||
<div class="job-actions">
|
||||
<button class="btn btn-sm" ng-click="retryJob('download', job)">
|
||||
<i class="fas fa-sync"></i> Retry
|
||||
</button>
|
||||
<button class="btn btn-sm" ng-click="removeJob('download', job)">
|
||||
<i class="fas fa-trash-alt"></i> Remove
|
||||
</button>
|
||||
<a class="btn btn-sm" href="/anonymize/{{job.id}}">
|
||||
<i class="far fa-edit"></i> Edit
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="empty-state" ng-if="filteredDownloadJobs.length == 0" style="padding: 20px">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
No download jobs in the queue.
|
||||
</div>
|
||||
|
||||
<!-- Remove Jobs -->
|
||||
<div class="admin-section-header">
|
||||
<h2><i class="fas fa-trash mr-1"></i> Remove Jobs</h2>
|
||||
<span class="section-count">{{removeJobs.length || 0}}</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="queue-job-card"
|
||||
ng-repeat="job in removeJobs as filteredRemoveJobs"
|
||||
>
|
||||
<div class="job-header">
|
||||
<div class="job-id">
|
||||
<a target="_blank" ng-href="/r/{{job.id}}" ng-bind="job.id"></a>
|
||||
<span
|
||||
class="status-badge"
|
||||
ng-class="'status-' + job.progress.status"
|
||||
>{{job.progress.status | title}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="job-timestamps">
|
||||
<span ng-if="job.timestamp">
|
||||
<i class="fas fa-clock"></i> Created: {{job.timestamp | humanTime}}
|
||||
</span>
|
||||
<span ng-if="job.processedOn">
|
||||
<i class="fas fa-cog"></i> Processed: {{job.processedOn | humanTime}}
|
||||
</span>
|
||||
<span ng-if="job.finishedOn">
|
||||
<i class="fas fa-check"></i> Finished: {{job.finishedOn | humanTime}}
|
||||
</span>
|
||||
</div>
|
||||
<div ng-if="job.stacktrace.length">
|
||||
<pre
|
||||
ng-repeat="stack in job.stacktrace track by $index"
|
||||
style="font-size: 0.8rem; max-height: 100px; overflow: auto; margin: 6px 0 0 0"
|
||||
><code ng-bind="stack"></code></pre>
|
||||
</div>
|
||||
<div class="job-actions">
|
||||
<button class="btn btn-sm" ng-click="retryJob('remove', job)">
|
||||
<i class="fas fa-sync"></i> Retry
|
||||
</button>
|
||||
<button class="btn btn-sm" ng-click="removeJob('remove', job)">
|
||||
<i class="fas fa-trash-alt"></i> Remove
|
||||
</button>
|
||||
<a class="btn btn-sm" href="/anonymize/{{job.id}}">
|
||||
<i class="far fa-edit"></i> Edit
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="empty-state" ng-if="filteredRemoveJobs.length == 0" style="padding: 20px">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
No remove jobs in the queue.
|
||||
</div>
|
||||
|
||||
<!-- Cache Jobs -->
|
||||
<div class="admin-section-header">
|
||||
<h2><i class="fas fa-broom mr-1"></i> Cache Cleanup Jobs</h2>
|
||||
<span class="section-count">{{removeCaches.length || 0}}</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="queue-job-card"
|
||||
ng-repeat="job in removeCaches as filteredRemoveCache"
|
||||
>
|
||||
<div class="job-header">
|
||||
<div class="job-id">
|
||||
<a target="_blank" ng-href="/r/{{job.id}}" ng-bind="job.id"></a>
|
||||
<span
|
||||
class="status-badge"
|
||||
ng-class="'status-' + job.progress.status"
|
||||
>{{job.progress.status | title}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="job-timestamps">
|
||||
<span ng-if="job.timestamp">
|
||||
<i class="fas fa-clock"></i> Created: {{job.timestamp | humanTime}}
|
||||
</span>
|
||||
<span ng-if="job.processedOn">
|
||||
<i class="fas fa-cog"></i> Processed: {{job.processedOn | humanTime}}
|
||||
</span>
|
||||
<span ng-if="job.finishedOn">
|
||||
<i class="fas fa-check"></i> Finished: {{job.finishedOn | humanTime}}
|
||||
</span>
|
||||
</div>
|
||||
<div ng-if="job.stacktrace.length">
|
||||
<pre
|
||||
ng-repeat="stack in job.stacktrace track by $index"
|
||||
style="font-size: 0.8rem; max-height: 100px; overflow: auto; margin: 6px 0 0 0"
|
||||
><code ng-bind="stack"></code></pre>
|
||||
</div>
|
||||
<div class="job-actions">
|
||||
<button class="btn btn-sm" ng-click="retryJob('cache', job)">
|
||||
<i class="fas fa-sync"></i> Retry
|
||||
</button>
|
||||
<button class="btn btn-sm" ng-click="removeJob('cache', job)">
|
||||
<i class="fas fa-trash-alt"></i> Remove
|
||||
</button>
|
||||
<a class="btn btn-sm" href="/anonymize/{{job.id}}">
|
||||
<i class="far fa-edit"></i> Edit
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="empty-state" ng-if="filteredRemoveCache.length == 0" style="padding: 20px">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
No cache cleanup jobs in the queue.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,370 +1,260 @@
|
||||
<div class="container page">
|
||||
<div class="row">
|
||||
<div class="border-bottom color-border-secondary py-3 w-100">
|
||||
<div class="d-flex flex-items-start w-100">
|
||||
<form class="w-100" aria-label="Repositories" accept-charset="UTF-8">
|
||||
<div class="d-flex flex-column flex-lg-row flex-auto">
|
||||
<div class="mb-1 mb-md-0 mr-md-3">
|
||||
<input
|
||||
type="search"
|
||||
id="search"
|
||||
class="form-control"
|
||||
aria-label="Find a repository…"
|
||||
placeholder="Find a repository…"
|
||||
autocomplete="off"
|
||||
ng-model="query.search"
|
||||
/>
|
||||
</div>
|
||||
<!-- Admin Navigation -->
|
||||
<nav class="admin-nav">
|
||||
<a href="/admin/" class="active">
|
||||
<i class="fas fa-code-branch"></i> Repositories
|
||||
</a>
|
||||
<a href="/admin/users">
|
||||
<i class="fas fa-users"></i> Users
|
||||
</a>
|
||||
<a href="/admin/conferences">
|
||||
<i class="fas fa-chalkboard-teacher"></i> Conferences
|
||||
</a>
|
||||
<a href="/admin/queues">
|
||||
<i class="fas fa-tasks"></i> Queues
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
<div class="mb-1 mb-md-0 mr-md-3 col-2 input-group">
|
||||
<input
|
||||
type="number"
|
||||
id="page"
|
||||
class="form-control"
|
||||
autocomplete="off"
|
||||
ng-model="query.page"
|
||||
min="1"
|
||||
max="{{totalPage}}"
|
||||
/>
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text">/{{totalPage}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Summary Stats -->
|
||||
<div class="admin-stats">
|
||||
<div class="admin-stat-card">
|
||||
<div class="stat-value" ng-bind="total >= 0 ? (total | number) : '...'"></div>
|
||||
<div class="stat-label">Total Repos</div>
|
||||
</div>
|
||||
<div class="admin-stat-card">
|
||||
<div class="stat-value">{{query.page}}/{{totalPage || '...'}}</div>
|
||||
<div class="stat-label">Current Page</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-wrap">
|
||||
<div class="dropdown mt-1 mt-lg-0 mr-1">
|
||||
<button
|
||||
class="btn btn-secondary dropdown-toggle"
|
||||
type="button"
|
||||
id="dropdownSort"
|
||||
data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
>
|
||||
Sort
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdownSort">
|
||||
<h6 class="dropdown-header">Select order</h6>
|
||||
<div class="form-check dropdown-item">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="radio"
|
||||
name="sort"
|
||||
id="sortFullName"
|
||||
value="source.repositoryName"
|
||||
ng-model="query.sort"
|
||||
/>
|
||||
<label class="form-check-label" for="sortFullName">
|
||||
Repository
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check dropdown-item">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="radio"
|
||||
name="sort"
|
||||
id="sortAnonymizeDate"
|
||||
value="anonymizeDate"
|
||||
ng-model="query.sort"
|
||||
/>
|
||||
<label class="form-check-label" for="sortAnonymizeDate">
|
||||
Anonymize Date
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check dropdown-item">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="radio"
|
||||
name="sort"
|
||||
id="sortStatus"
|
||||
value="status"
|
||||
ng-model="query.sort"
|
||||
/>
|
||||
<label class="form-check-label" for="sortStatus">
|
||||
Status
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check dropdown-item">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="radio"
|
||||
name="sort"
|
||||
id="sortLastView"
|
||||
value="lastView"
|
||||
ng-model="query.sort"
|
||||
/>
|
||||
<label class="form-check-label" for="sortLastView">
|
||||
Last View
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check dropdown-item">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="radio"
|
||||
name="sort"
|
||||
id="sortPageView"
|
||||
value="pageView"
|
||||
ng-model="query.sort"
|
||||
/>
|
||||
<label class="form-check-label" for="sortPageView">
|
||||
Page View
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Toolbar -->
|
||||
<div class="admin-toolbar">
|
||||
<input
|
||||
type="search"
|
||||
class="form-control"
|
||||
aria-label="Search repositories..."
|
||||
placeholder="Search repositories..."
|
||||
autocomplete="off"
|
||||
ng-model="query.search"
|
||||
/>
|
||||
|
||||
<div class="dropdown mt-1 mt-lg-0 mr-1">
|
||||
<button
|
||||
class="btn btn-secondary dropdown-toggle"
|
||||
type="button"
|
||||
id="dropdownStatus"
|
||||
data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
>
|
||||
Status
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdownStatus">
|
||||
<h6 class="dropdown-header">Select status</h6>
|
||||
<div class="form-check dropdown-item">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="checkbox"
|
||||
name="sort"
|
||||
id="statusReady"
|
||||
value="ready"
|
||||
ng-model="query.ready"
|
||||
/>
|
||||
<label class="form-check-label" for="statusReady">
|
||||
Ready
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check dropdown-item">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="checkbox"
|
||||
name="sort"
|
||||
id="statusExpired"
|
||||
value="expired"
|
||||
ng-model="query.expired"
|
||||
/>
|
||||
<label class="form-check-label" for="statusExpired">
|
||||
Expired
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check dropdown-item">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="checkbox"
|
||||
name="sort"
|
||||
id="statusExpired"
|
||||
value="expired"
|
||||
ng-model="query.preparing"
|
||||
/>
|
||||
<label class="form-check-label" for="statusExpired">
|
||||
Preparing
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check dropdown-item">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="checkbox"
|
||||
name="sort"
|
||||
id="statusRemoved"
|
||||
value="removed"
|
||||
ng-model="query.removed"
|
||||
/>
|
||||
<label class="form-check-label" for="statusRemoved">
|
||||
Removed
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check dropdown-item">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="checkbox"
|
||||
name="sort"
|
||||
id="statusRemoved"
|
||||
value="removed"
|
||||
ng-model="query.error"
|
||||
/>
|
||||
<label class="form-check-label" for="statusRemoved">
|
||||
Error
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="pagination-compact">
|
||||
<button class="btn btn-sm" ng-click="query.page = Math.max(1, query.page - 1)" ng-disabled="query.page <= 1">
|
||||
<i class="fas fa-chevron-left"></i>
|
||||
</button>
|
||||
<input
|
||||
type="number"
|
||||
class="form-control form-control-sm"
|
||||
ng-model="query.page"
|
||||
min="1"
|
||||
max="{{totalPage}}"
|
||||
/>
|
||||
<span>/{{totalPage}}</span>
|
||||
<button class="btn btn-sm" ng-click="query.page = Math.min(totalPage, query.page + 1)" ng-disabled="query.page >= totalPage">
|
||||
<i class="fas fa-chevron-right"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="dropdown">
|
||||
<button
|
||||
class="btn btn-sm dropdown-toggle"
|
||||
type="button"
|
||||
id="dropdownSort"
|
||||
data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
>
|
||||
<i class="fas fa-sort"></i> Sort
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdownSort">
|
||||
<h6 class="dropdown-header">Sort by</h6>
|
||||
<a class="dropdown-item" href="#" ng-click="query.sort = 'source.repositoryName'">
|
||||
<i class="fas fa-check" ng-show="query.sort == 'source.repositoryName'"></i> Repository
|
||||
</a>
|
||||
<a class="dropdown-item" href="#" ng-click="query.sort = 'anonymizeDate'">
|
||||
<i class="fas fa-check" ng-show="query.sort == 'anonymizeDate'"></i> Anonymize Date
|
||||
</a>
|
||||
<a class="dropdown-item" href="#" ng-click="query.sort = 'status'">
|
||||
<i class="fas fa-check" ng-show="query.sort == 'status'"></i> Status
|
||||
</a>
|
||||
<a class="dropdown-item" href="#" ng-click="query.sort = 'lastView'">
|
||||
<i class="fas fa-check" ng-show="query.sort == 'lastView'"></i> Last View
|
||||
</a>
|
||||
<a class="dropdown-item" href="#" ng-click="query.sort = 'pageView'">
|
||||
<i class="fas fa-check" ng-show="query.sort == 'pageView'"></i> Page Views
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="p-0 m-0 w-100">
|
||||
<li
|
||||
class="col-12 d-flex px-0 py-3 border-bottom color-border-secondary"
|
||||
ng-class="{'expired': repo.status == 'expired','removed': repo.status == 'removed','error': repo.status == 'error' }"
|
||||
ng-repeat="repo in repositories| filter:repoFiler| orderBy:orderBy as filteredRepositories"
|
||||
|
||||
<div class="dropdown">
|
||||
<button
|
||||
class="btn btn-sm dropdown-toggle"
|
||||
type="button"
|
||||
id="dropdownStatus"
|
||||
data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
>
|
||||
<div class="w-100">
|
||||
<div class="">
|
||||
<h3>
|
||||
<a
|
||||
target="__blank"
|
||||
ng-href="/r/{{repo.repoId}}"
|
||||
ng-bind="repo.repoId"
|
||||
></a>
|
||||
<span
|
||||
class="badge"
|
||||
ng-class="{'badge-warning': repo.status == 'removed' || repo.status == 'expired' || repo.status == 'removing' || repo.status == 'expiring', 'badge-info': repo.status == 'preparing' || repo.status == 'download', 'badge-success': repo.status == 'ready', 'badge-danger': repo.status == 'error'}"
|
||||
><span ng-bind="repo.status | title"></span>
|
||||
<span
|
||||
ng-if="repo.status == 'error'"
|
||||
ng-bind="': ' + repo.statusMessage"
|
||||
></span
|
||||
></span>
|
||||
</h3>
|
||||
<span class="color-text-secondary mb-1">
|
||||
<span class="repository">
|
||||
<i class="fab fa-github" aria-hidden="true"></i>
|
||||
<a
|
||||
href="https://github.com/{{repo.source.repositoryName}}/"
|
||||
class="fullName"
|
||||
ng-bind="repo.source.repositoryName"
|
||||
></a>
|
||||
</span>
|
||||
<span class="branch" ng-if="repo.options.update">
|
||||
<i class="fas fa-code-branch" aria-hidden="true"></i>
|
||||
<a
|
||||
href="https://github.com/{{repo.source.fullName}}/tree/{{repo.source.branch}}"
|
||||
class="branch"
|
||||
ng-bind="repo.source.branch"
|
||||
></a>
|
||||
</span>
|
||||
<span class="commit" ng-if="!repo.options.update">
|
||||
@<a
|
||||
href="https://github.com/{{repo.source.fullName}}/tree/{{repo.source.commit}}"
|
||||
class="commit"
|
||||
ng-bind="repo.source.commit.substring(0, 8)"
|
||||
></a>
|
||||
</span>
|
||||
anonymized {{repo.anonymizeDate | humanTime}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="color-text-secondary mt-2">
|
||||
<span class="ml-0 mr-3" ng-if="::repo.conference">
|
||||
<i class="fas fa-chalkboard-teacher"></i>
|
||||
{{repo.conference}}
|
||||
</span>
|
||||
<span
|
||||
class="ml-0 mr-3"
|
||||
class="terms"
|
||||
title="Terms: {{::repo.options.terms.join(', ')}}"
|
||||
data-toggle="tooltip"
|
||||
data-placement="bottom"
|
||||
>
|
||||
<i class="fas fa-shield-alt"></i>
|
||||
{{::repo.options.terms.length | number}}
|
||||
</span>
|
||||
<span
|
||||
class="ml-0 mr-3"
|
||||
title="Size: {{::repo.size.storage | humanFileSize}}"
|
||||
data-toggle="tooltip"
|
||||
data-placement="bottom"
|
||||
>
|
||||
<i class="fas fa-database"></i> {{::repo.size.storage |
|
||||
humanFileSize}}</span
|
||||
>
|
||||
<span
|
||||
class="ml-0 mr-3"
|
||||
title="View: {{::repo.pageView || 0 | number}}"
|
||||
data-toggle="tooltip"
|
||||
data-placement="bottom"
|
||||
>
|
||||
<i class="far fa-eye" aria-hidden="true"></i>
|
||||
{{::repo.pageView || 0 | number}}
|
||||
</span>
|
||||
<span
|
||||
class="ml-0 mr-3"
|
||||
title="Last view: {{::repo.lastView | date}}"
|
||||
data-toggle="tooltip"
|
||||
data-placement="bottom"
|
||||
>
|
||||
<i class="far fa-calendar-alt" aria-hidden="true"></i>
|
||||
Last view: {{::repo.lastView | humanTime}}</span
|
||||
>
|
||||
<span
|
||||
class="ml-0 mr-3"
|
||||
ng-if="repo.options.expirationMode!='never' && repo.status == 'ready'"
|
||||
>
|
||||
<i class="far fa-clock" aria-hidden="true"></i>
|
||||
Expire: {{repo.options.expirationDate | humanTime}}</span
|
||||
>
|
||||
</div>
|
||||
<i class="fas fa-filter"></i> Status
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdownStatus">
|
||||
<h6 class="dropdown-header">Filter by status</h6>
|
||||
<label class="dropdown-item mb-0">
|
||||
<input type="checkbox" ng-model="query.ready" /> Ready
|
||||
</label>
|
||||
<label class="dropdown-item mb-0">
|
||||
<input type="checkbox" ng-model="query.preparing" /> Preparing
|
||||
</label>
|
||||
<label class="dropdown-item mb-0">
|
||||
<input type="checkbox" ng-model="query.expired" /> Expired
|
||||
</label>
|
||||
<label class="dropdown-item mb-0">
|
||||
<input type="checkbox" ng-model="query.removed" /> Removed
|
||||
</label>
|
||||
<label class="dropdown-item mb-0">
|
||||
<input type="checkbox" ng-model="query.error" /> Error
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Repository List -->
|
||||
<div
|
||||
class="admin-list-item"
|
||||
ng-repeat="repo in repositories | filter:repoFiler | orderBy:orderBy as filteredRepositories"
|
||||
>
|
||||
<div class="item-main">
|
||||
<div class="item-title">
|
||||
<a target="_blank" ng-href="/r/{{repo.repoId}}" ng-bind="repo.repoId"></a>
|
||||
<span
|
||||
class="status-badge"
|
||||
ng-class="'status-' + repo.status"
|
||||
>{{repo.status | title}}</span>
|
||||
<span
|
||||
ng-if="repo.status == 'error'"
|
||||
style="font-size: 0.8rem; color: #dc3545;"
|
||||
ng-bind="repo.statusMessage"
|
||||
></span>
|
||||
</div>
|
||||
<div class="item-meta">
|
||||
<span>
|
||||
<i class="fab fa-github"></i>
|
||||
<a
|
||||
href="https://github.com/{{repo.source.repositoryName}}/"
|
||||
ng-bind="repo.source.repositoryName"
|
||||
></a>
|
||||
</span>
|
||||
<span ng-if="repo.options.update">
|
||||
<i class="fas fa-code-branch"></i>
|
||||
<a
|
||||
href="https://github.com/{{repo.source.fullName}}/tree/{{repo.source.branch}}"
|
||||
ng-bind="repo.source.branch"
|
||||
></a>
|
||||
</span>
|
||||
<span ng-if="!repo.options.update">
|
||||
@<a
|
||||
href="https://github.com/{{repo.source.fullName}}/tree/{{repo.source.commit}}"
|
||||
ng-bind="repo.source.commit.substring(0, 8)"
|
||||
></a>
|
||||
</span>
|
||||
<span>anonymized {{repo.anonymizeDate | humanTime}}</span>
|
||||
</div>
|
||||
<div class="item-meta" style="margin-top: 4px">
|
||||
<span ng-if="::repo.conference">
|
||||
<i class="fas fa-chalkboard-teacher"></i> {{repo.conference}}
|
||||
</span>
|
||||
<span title="Terms: {{::repo.options.terms.join(', ')}}">
|
||||
<i class="fas fa-shield-alt"></i> {{::repo.options.terms.length | number}} terms
|
||||
</span>
|
||||
<span title="Size: {{::repo.size.storage | humanFileSize}}">
|
||||
<i class="fas fa-database"></i> {{::repo.size.storage | humanFileSize}}
|
||||
</span>
|
||||
<span>
|
||||
<i class="far fa-eye"></i> {{::repo.pageView || 0 | number}} views
|
||||
</span>
|
||||
<span>
|
||||
<i class="far fa-calendar-alt"></i> Last: {{::repo.lastView | humanTime}}
|
||||
</span>
|
||||
<span ng-if="repo.options.expirationMode != 'never' && repo.status == 'ready'">
|
||||
<i class="far fa-clock"></i> Expire: {{repo.options.expirationDate | humanTime}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-actions">
|
||||
<div class="dropdown">
|
||||
<button
|
||||
class="btn dropdown-toggle btn-sm"
|
||||
type="button"
|
||||
data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
>
|
||||
Actions
|
||||
</button>
|
||||
<div class="dropdown-menu dropdown-menu-right">
|
||||
<a class="dropdown-item" href="/anonymize/{{repo.repoId}}">
|
||||
<i class="far fa-edit"></i> Edit
|
||||
</a>
|
||||
<a class="dropdown-item" href="/r/{{repo.repoId}}/">
|
||||
<i class="fa fa-eye"></i> View Repo
|
||||
</a>
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="/w/{{repo.repoId}}/"
|
||||
target="_self"
|
||||
ng-if="repo.options.page && repo.status == 'ready'"
|
||||
>
|
||||
<i class="fas fa-globe"></i> View Page
|
||||
</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="#"
|
||||
ng-show="repo.status == 'ready' || repo.status == 'error'"
|
||||
ng-click="updateRepository(repo)"
|
||||
>
|
||||
<i class="fas fa-sync"></i> Force Update
|
||||
</a>
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="#"
|
||||
ng-show="repo.status == 'removed'"
|
||||
ng-click="updateRepository(repo)"
|
||||
>
|
||||
<i class="fas fa-check-circle"></i> Enable
|
||||
</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="#" ng-click="removeCache(repo)">
|
||||
<i class="fas fa-broom"></i> Remove Cache
|
||||
</a>
|
||||
<a
|
||||
class="dropdown-item text-danger"
|
||||
href="#"
|
||||
ng-show="repo.status == 'ready'"
|
||||
ng-click="removeRepository(repo)"
|
||||
>
|
||||
<i class="fas fa-trash-alt"></i> Remove
|
||||
</a>
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<div class="dropdown">
|
||||
<button
|
||||
class="btn black_border dropdown-toggle btn-sm"
|
||||
type="button"
|
||||
id="dropdownMenuButton"
|
||||
data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
>
|
||||
Actions
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
|
||||
<a class="dropdown-item" href="#" ng-click="removeCache(repo)">
|
||||
<i class="fas fa-trash-alt"></i> Remove Cache
|
||||
</a>
|
||||
<a class="dropdown-item" href="/anonymize/{{repo.repoId}}">
|
||||
<i class="far fa-edit" aria-hidden="true"></i> Edit
|
||||
</a>
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="#"
|
||||
ng-show="repo.status == 'ready' || repo.status == 'error'"
|
||||
ng-click="updateRepository(repo)"
|
||||
>
|
||||
<i class="fas fa-sync"></i> Force update
|
||||
</a>
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="#"
|
||||
ng-show="repo.status == 'removed'"
|
||||
ng-click="updateRepository(repo)"
|
||||
>
|
||||
<i class="fas fa-check-circle"></i>
|
||||
Enable
|
||||
</a>
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="#"
|
||||
ng-show="repo.status == 'ready'"
|
||||
ng-click="removeRepository(repo)"
|
||||
>
|
||||
<i class="fas fa-trash-alt"></i> Remove
|
||||
</a>
|
||||
<a class="dropdown-item" href="/r/{{repo.repoId}}/">
|
||||
<i class="fa fa-eye" aria-hidden="true"></i> View Repo
|
||||
</a>
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="/w/{{repo.repoId}}/"
|
||||
target="_self"
|
||||
ng-if="repo.options.page && repo.status == 'ready'"
|
||||
>
|
||||
<i class="fas fa-globe"></i> View Page
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li
|
||||
class="col-12 d-flex px-0 py-3 border-bottom color-border-secondary"
|
||||
ng-if="filteredRepositories.length == 0"
|
||||
>
|
||||
There is no repository to display.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="empty-state" ng-if="filteredRepositories.length == 0">
|
||||
<i class="fas fa-code-branch"></i>
|
||||
No repositories match the current filters.
|
||||
</div>
|
||||
|
||||
<!-- Bottom pagination -->
|
||||
<div class="admin-toolbar" ng-if="totalPage > 1" style="justify-content: center; border-bottom: none;">
|
||||
<div class="pagination-compact">
|
||||
<button class="btn btn-sm" ng-click="query.page = Math.max(1, query.page - 1)" ng-disabled="query.page <= 1">
|
||||
<i class="fas fa-chevron-left"></i> Previous
|
||||
</button>
|
||||
<span>Page {{query.page}} of {{totalPage}}</span>
|
||||
<button class="btn btn-sm" ng-click="query.page = Math.min(totalPage, query.page + 1)" ng-disabled="query.page >= totalPage">
|
||||
Next <i class="fas fa-chevron-right"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+253
-335
@@ -1,356 +1,274 @@
|
||||
<div class="container page">
|
||||
<div class="row">
|
||||
<h1>
|
||||
<!-- Admin Navigation -->
|
||||
<nav class="admin-nav">
|
||||
<a href="/admin/">
|
||||
<i class="fas fa-code-branch"></i> Repositories
|
||||
</a>
|
||||
<a href="/admin/users" class="active">
|
||||
<i class="fas fa-users"></i> Users
|
||||
</a>
|
||||
<a href="/admin/conferences">
|
||||
<i class="fas fa-chalkboard-teacher"></i> Conferences
|
||||
</a>
|
||||
<a href="/admin/queues">
|
||||
<i class="fas fa-tasks"></i> Queues
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
<!-- User Detail Card -->
|
||||
<div class="user-detail-card" ng-if="userInfo">
|
||||
<div class="user-header">
|
||||
<img
|
||||
ng-src="{{userInfo.photo}}"
|
||||
ng-if="userInfo.photo"
|
||||
width="30"
|
||||
height="30"
|
||||
class="rounded-circle ng-scope"
|
||||
width="48"
|
||||
height="48"
|
||||
/>
|
||||
{{userInfo.username}}
|
||||
<span class="badge"><span ng-bind="userInfo.status | title"></span></span>
|
||||
</h1>
|
||||
<div class="row mb-3 m-0 py-2 border">
|
||||
<div class="col-2 font-weight-bold">ID</div>
|
||||
<div class="col-10">{{userInfo._id}}</div>
|
||||
<div>
|
||||
<h1>
|
||||
{{userInfo.username}}
|
||||
<span
|
||||
class="status-badge"
|
||||
ng-class="'status-' + userInfo.status"
|
||||
>{{userInfo.status | title}}</span>
|
||||
<span
|
||||
class="status-badge status-active"
|
||||
ng-if="userInfo.isAdmin"
|
||||
>Admin</span>
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-2 font-weight-bold">Email</div>
|
||||
<div class="col-10">{{userInfo.emails[0].email}}</div>
|
||||
<div class="user-detail-grid">
|
||||
<div class="detail-label">ID</div>
|
||||
<div class="detail-value">{{userInfo._id}}</div>
|
||||
|
||||
<div class="col-2 font-weight-bold">accessTokens</div>
|
||||
<div class="col-10">{{userInfo.accessTokens.github}}</div>
|
||||
<div class="detail-label">Email</div>
|
||||
<div class="detail-value">{{userInfo.emails[0].email}}</div>
|
||||
|
||||
<div class="col-2 font-weight-bold">Github</div>
|
||||
<div class="col-10">
|
||||
<a ng-href="https://github.com/{{userInfo.username}}"
|
||||
>{{userInfo.username}}</a
|
||||
<div class="detail-label">Access Token</div>
|
||||
<div class="detail-value" style="font-family: monospace; font-size: 0.85rem;">{{userInfo.accessTokens.github}}</div>
|
||||
|
||||
<div class="detail-label">GitHub</div>
|
||||
<div class="detail-value">
|
||||
<a ng-href="https://github.com/{{userInfo.username}}" target="_blank">
|
||||
<i class="fab fa-github"></i> {{userInfo.username}}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="detail-label">GitHub Repos</div>
|
||||
<div class="detail-value">
|
||||
{{userInfo.repositories.length}} repositories
|
||||
<button
|
||||
class="btn btn-sm ml-2"
|
||||
ng-click="showRepos = !showRepos"
|
||||
>
|
||||
{{showRepos ? 'Hide' : 'Show'}}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-primary btn-sm ml-1"
|
||||
ng-click="getGitHubRepositories()"
|
||||
>
|
||||
<i class="fas fa-sync"></i> Refresh
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-2 font-weight-bold">Github Repositories</div>
|
||||
<div class="col-10" ng-click="showRepos =!showRepos">
|
||||
{{userInfo.repositories.length}}
|
||||
<!-- GitHub repos expandable list -->
|
||||
<div ng-if="showRepos" style="margin-top: 16px">
|
||||
<div
|
||||
class="admin-list-item"
|
||||
ng-repeat="repo in userInfo.repositories"
|
||||
>
|
||||
<div class="item-main">
|
||||
<div class="item-title" style="font-size: 0.9rem">{{repo.name}}</div>
|
||||
<div class="item-meta">
|
||||
<span title="Size">
|
||||
<i class="fas fa-database"></i> {{::repo.size | humanFileSize}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Repositories Section -->
|
||||
<div class="admin-section-header">
|
||||
<h2><i class="fas fa-code-branch mr-1"></i> Anonymized Repositories</h2>
|
||||
<span class="section-count">{{repositories.length}}</span>
|
||||
</div>
|
||||
|
||||
<!-- Toolbar -->
|
||||
<div class="admin-toolbar">
|
||||
<input
|
||||
type="search"
|
||||
class="form-control"
|
||||
aria-label="Search repositories..."
|
||||
placeholder="Search repositories..."
|
||||
autocomplete="off"
|
||||
ng-model="search"
|
||||
/>
|
||||
|
||||
<div class="dropdown">
|
||||
<button
|
||||
class="btn btn-primary m-1 mx-3"
|
||||
ng-click="getGitHubRepositories()"
|
||||
class="btn btn-sm dropdown-toggle"
|
||||
type="button"
|
||||
id="dropdownSort"
|
||||
data-toggle="dropdown"
|
||||
>
|
||||
Regresh Repositories
|
||||
<i class="fas fa-sort"></i> Sort
|
||||
</button>
|
||||
<ul class="m-0 col-12" ng-if="showRepos">
|
||||
<li
|
||||
class="col-12 d-flex px-0 py-3 border-bottom color-border-secondary"
|
||||
ng-repeat="repo in userInfo.repositories"
|
||||
>
|
||||
<div class="w-100">
|
||||
<div class="">
|
||||
{{repo.name}}
|
||||
</div>
|
||||
<div class="color-text-secondary mt-2">
|
||||
<span
|
||||
class="ml-0 mr-3"
|
||||
title="Size: {{::repo.size | humanFileSize}}"
|
||||
data-toggle="tooltip"
|
||||
data-placement="bottom"
|
||||
>
|
||||
<i class="fas fa-database"></i> {{::repo.size |
|
||||
humanFileSize}}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<h3>Repositories {{repositories.length}}</h3>
|
||||
<div class="border-bottom color-border-secondary py-3 w-100">
|
||||
<div class="d-flex flex-items-start w-100">
|
||||
<form class="w-100" aria-label="Repositories" accept-charset="UTF-8">
|
||||
<div class="d-flex flex-column flex-lg-row flex-auto">
|
||||
<div class="mb-1 mb-md-0 mr-md-3">
|
||||
<input
|
||||
type="search"
|
||||
id="search"
|
||||
class="form-control"
|
||||
aria-label="Find repositories"
|
||||
placeholder="Find repositories"
|
||||
autocomplete="off"
|
||||
ng-model="search"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-wrap">
|
||||
<div class="dropdown mt-1 mt-lg-0 mr-1">
|
||||
<button
|
||||
class="btn btn-secondary dropdown-toggle"
|
||||
type="button"
|
||||
id="dropdownSort"
|
||||
data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
>
|
||||
Sort
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdownSort">
|
||||
<h6 class="dropdown-header">Select order</h6>
|
||||
<div class="form-check dropdown-item">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="radio"
|
||||
name="sort"
|
||||
id="anonymizeDate"
|
||||
value="-anonymizeDate"
|
||||
ng-model="orderBy"
|
||||
/>
|
||||
<label class="form-check-label" for="anonymizeDate">
|
||||
Anonymize Date
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check dropdown-item">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="radio"
|
||||
name="sort"
|
||||
id="sortID"
|
||||
value="repoId"
|
||||
ng-model="orderBy"
|
||||
/>
|
||||
<label class="form-check-label" for="sortID"> ID </label>
|
||||
</div>
|
||||
<div class="form-check dropdown-item">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="radio"
|
||||
name="sort"
|
||||
id="sortStatus"
|
||||
value="-status"
|
||||
ng-model="orderBy"
|
||||
/>
|
||||
<label class="form-check-label" for="sortStatus">
|
||||
Status
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dropdown mt-1 mt-lg-0 mr-1">
|
||||
<button
|
||||
class="btn btn-secondary dropdown-toggle"
|
||||
type="button"
|
||||
id="dropdownStatus"
|
||||
data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
>
|
||||
Status
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdownStatus">
|
||||
<h6 class="dropdown-header">Select status</h6>
|
||||
<div class="form-check dropdown-item">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="checkbox"
|
||||
name="sort"
|
||||
id="statusReady"
|
||||
value="ready"
|
||||
ng-model="filters.status.ready"
|
||||
/>
|
||||
<label class="form-check-label" for="statusReady">
|
||||
Ready
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check dropdown-item">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="checkbox"
|
||||
name="sort"
|
||||
id="statusExpired"
|
||||
value="expired"
|
||||
ng-model="filters.status.expired"
|
||||
/>
|
||||
<label class="form-check-label" for="statusExpired">
|
||||
Expired
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check dropdown-item">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="checkbox"
|
||||
name="sort"
|
||||
id="statusRemoved"
|
||||
value="removed"
|
||||
ng-model="filters.status.removed"
|
||||
/>
|
||||
<label class="form-check-label" for="statusRemoved">
|
||||
Removed
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div
|
||||
class="d-none d-md-flex flex-md-items-center flex-md-justify-end"
|
||||
></div>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdownSort">
|
||||
<h6 class="dropdown-header">Sort by</h6>
|
||||
<a class="dropdown-item" href="#" ng-click="orderBy = '-anonymizeDate'">
|
||||
<i class="fas fa-check" ng-show="orderBy == '-anonymizeDate'"></i> Anonymize Date
|
||||
</a>
|
||||
<a class="dropdown-item" href="#" ng-click="orderBy = 'repoId'">
|
||||
<i class="fas fa-check" ng-show="orderBy == 'repoId'"></i> ID
|
||||
</a>
|
||||
<a class="dropdown-item" href="#" ng-click="orderBy = '-status'">
|
||||
<i class="fas fa-check" ng-show="orderBy == '-status'"></i> Status
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="p-0 m-0 w-100">
|
||||
<li
|
||||
class="col-12 d-flex px-0 py-3 border-bottom color-border-secondary"
|
||||
ng-class="{'expired': repo.status == 'expired','removed': repo.status == 'removed' }"
|
||||
ng-repeat="repo in repositories| filter:repoFiler| orderBy:orderBy as filteredRepositories"
|
||||
|
||||
<div class="dropdown">
|
||||
<button
|
||||
class="btn btn-sm dropdown-toggle"
|
||||
type="button"
|
||||
id="dropdownStatus"
|
||||
data-toggle="dropdown"
|
||||
>
|
||||
<div class="w-100">
|
||||
<div class="">
|
||||
<h3>
|
||||
<a ng-href="/r/{{repo.repoId}}" ng-bind="repo.repoId"></a>
|
||||
<span
|
||||
class="badge"
|
||||
ng-class="{'badge-warning': repo.status == 'removed' || repo.status == 'expired', 'badge-success': repo.status == 'ready', 'badge-danger': ''}"
|
||||
ng-bind="repo.status | title"
|
||||
></span>
|
||||
</h3>
|
||||
<span class="color-text-secondary mb-1">
|
||||
<span class="repository">
|
||||
<i class="fab fa-github" aria-hidden="true"></i>
|
||||
<a
|
||||
href="https://github.com/{{repo.source.fullName}}/"
|
||||
class="fullName"
|
||||
ng-bind="repo.source.fullName"
|
||||
></a>
|
||||
</span>
|
||||
<span class="branch" ng-if="repo.options.update">
|
||||
<i class="fas fa-code-branch" aria-hidden="true"></i>
|
||||
<a
|
||||
href="https://github.com/{{repo.source.fullName}}/tree/{{repo.source.branch}}"
|
||||
class="branch"
|
||||
ng-bind="repo.source.branch"
|
||||
></a>
|
||||
</span>
|
||||
<span class="commit" ng-if="!repo.options.update">
|
||||
@<a
|
||||
href="https://github.com/{{repo.source.fullName}}/tree/{{repo.source.commit}}"
|
||||
class="commit"
|
||||
ng-bind="repo.source.commit.substring(0, 8)"
|
||||
></a>
|
||||
</span>
|
||||
anonymized {{repo.anonymizeDate | humanTime}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="color-text-secondary mt-2">
|
||||
<span
|
||||
class="ml-0 mr-3"
|
||||
class="terms"
|
||||
title="Terms: {{::repo.options.terms.join(', ')}}"
|
||||
data-toggle="tooltip"
|
||||
data-placement="bottom"
|
||||
>
|
||||
<i class="fas fa-shield-alt"></i>
|
||||
{{::repo.options.terms.length | number}}
|
||||
</span>
|
||||
<span
|
||||
class="ml-0 mr-3"
|
||||
title="Size: {{::repo.size | humanFileSize}}"
|
||||
data-toggle="tooltip"
|
||||
data-placement="bottom"
|
||||
>
|
||||
<i class="fas fa-database"></i> {{::repo.size.storage |
|
||||
humanFileSize}}</span
|
||||
>
|
||||
<span
|
||||
class="ml-0 mr-3"
|
||||
title="View: {{::repo.pageView | number}}"
|
||||
data-toggle="tooltip"
|
||||
data-placement="bottom"
|
||||
>
|
||||
<i class="far fa-eye" aria-hidden="true"></i>
|
||||
{{::repo.pageView | number}}
|
||||
</span>
|
||||
<span
|
||||
class="ml-0 mr-3"
|
||||
title="Last view: {{::repo.lastView | date}}"
|
||||
data-toggle="tooltip"
|
||||
data-placement="bottom"
|
||||
>
|
||||
<i class="far fa-calendar-alt" aria-hidden="true"></i>
|
||||
Last view: {{::repo.lastView | humanTime}}</span
|
||||
>
|
||||
<span
|
||||
class="ml-0 mr-3"
|
||||
ng-if="repo.options.expirationMode!='never' && repo.status == 'ready'"
|
||||
>
|
||||
<i class="far fa-clock" aria-hidden="true"></i>
|
||||
Expire: {{repo.options.expirationDate | humanTime}}</span
|
||||
>
|
||||
</div>
|
||||
<i class="fas fa-filter"></i> Status
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdownStatus">
|
||||
<label class="dropdown-item mb-0">
|
||||
<input type="checkbox" ng-model="filters.status.ready" /> Ready
|
||||
</label>
|
||||
<label class="dropdown-item mb-0">
|
||||
<input type="checkbox" ng-model="filters.status.expired" /> Expired
|
||||
</label>
|
||||
<label class="dropdown-item mb-0">
|
||||
<input type="checkbox" ng-model="filters.status.removed" /> Removed
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Repository List -->
|
||||
<div
|
||||
class="admin-list-item"
|
||||
ng-repeat="repo in repositories | filter:repoFiler | orderBy:orderBy as filteredRepositories"
|
||||
>
|
||||
<div class="item-main">
|
||||
<div class="item-title">
|
||||
<a ng-href="/r/{{repo.repoId}}" ng-bind="repo.repoId"></a>
|
||||
<span
|
||||
class="status-badge"
|
||||
ng-class="'status-' + repo.status"
|
||||
>{{repo.status | title}}</span>
|
||||
</div>
|
||||
<div class="item-meta">
|
||||
<span>
|
||||
<i class="fab fa-github"></i>
|
||||
<a
|
||||
href="https://github.com/{{repo.source.fullName}}/"
|
||||
ng-bind="repo.source.fullName"
|
||||
></a>
|
||||
</span>
|
||||
<span ng-if="repo.options.update">
|
||||
<i class="fas fa-code-branch"></i>
|
||||
<a
|
||||
href="https://github.com/{{repo.source.fullName}}/tree/{{repo.source.branch}}"
|
||||
ng-bind="repo.source.branch"
|
||||
></a>
|
||||
</span>
|
||||
<span ng-if="!repo.options.update">
|
||||
@<a
|
||||
href="https://github.com/{{repo.source.fullName}}/tree/{{repo.source.commit}}"
|
||||
ng-bind="repo.source.commit.substring(0, 8)"
|
||||
></a>
|
||||
</span>
|
||||
<span>anonymized {{repo.anonymizeDate | humanTime}}</span>
|
||||
</div>
|
||||
<div class="item-meta" style="margin-top: 4px">
|
||||
<span title="Terms: {{::repo.options.terms.join(', ')}}">
|
||||
<i class="fas fa-shield-alt"></i> {{::repo.options.terms.length | number}}
|
||||
</span>
|
||||
<span title="Size">
|
||||
<i class="fas fa-database"></i> {{::repo.size.storage | humanFileSize}}
|
||||
</span>
|
||||
<span>
|
||||
<i class="far fa-eye"></i> {{::repo.pageView | number}}
|
||||
</span>
|
||||
<span>
|
||||
<i class="far fa-calendar-alt"></i> Last: {{::repo.lastView | humanTime}}
|
||||
</span>
|
||||
<span ng-if="repo.options.expirationMode != 'never' && repo.status == 'ready'">
|
||||
<i class="far fa-clock"></i> Expire: {{repo.options.expirationDate | humanTime}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-actions">
|
||||
<div class="dropdown">
|
||||
<button
|
||||
class="btn dropdown-toggle btn-sm"
|
||||
type="button"
|
||||
data-toggle="dropdown"
|
||||
>
|
||||
Actions
|
||||
</button>
|
||||
<div class="dropdown-menu dropdown-menu-right">
|
||||
<a class="dropdown-item" href="/anonymize/{{repo.repoId}}">
|
||||
<i class="far fa-edit"></i> Edit
|
||||
</a>
|
||||
<a class="dropdown-item" href="/r/{{repo.repoId}}/">
|
||||
<i class="fa fa-eye"></i> View Repo
|
||||
</a>
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="/w/{{repo.repoId}}/"
|
||||
target="_self"
|
||||
ng-if="repo.options.page && repo.status == 'ready'"
|
||||
>
|
||||
<i class="fas fa-globe"></i> View Page
|
||||
</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="#"
|
||||
ng-show="repo.status == 'ready' || repo.status == 'error'"
|
||||
ng-click="updateRepository(repo)"
|
||||
>
|
||||
<i class="fas fa-sync"></i> Force Update
|
||||
</a>
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="#"
|
||||
ng-show="repo.status == 'removed'"
|
||||
ng-click="updateRepository(repo)"
|
||||
>
|
||||
<i class="fas fa-check-circle"></i> Enable
|
||||
</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="#" ng-click="removeCache(repo)">
|
||||
<i class="fas fa-broom"></i> Remove Cache
|
||||
</a>
|
||||
<a
|
||||
class="dropdown-item text-danger"
|
||||
href="#"
|
||||
ng-show="repo.status == 'ready'"
|
||||
ng-click="removeRepository(repo)"
|
||||
>
|
||||
<i class="fas fa-trash-alt"></i> Remove
|
||||
</a>
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<div class="dropdown">
|
||||
<button
|
||||
class="btn black_border dropdown-toggle btn-sm"
|
||||
type="button"
|
||||
id="dropdownMenuButton"
|
||||
data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
>
|
||||
Actions
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
|
||||
<a class="dropdown-item" href="#" ng-click="removeCache(repo)">
|
||||
<i class="fas fa-trash-alt"></i> Remove Cache
|
||||
</a>
|
||||
<a class="dropdown-item" href="/anonymize/{{repo.repoId}}">
|
||||
<i class="far fa-edit" aria-hidden="true"></i> Edit
|
||||
</a>
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="#"
|
||||
ng-show="repo.status == 'ready' || repo.status == 'error'"
|
||||
ng-click="updateRepository(repo)"
|
||||
>
|
||||
<i class="fas fa-sync"></i> Force update
|
||||
</a>
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="#"
|
||||
ng-show="repo.status == 'removed'"
|
||||
ng-click="updateRepository(repo)"
|
||||
>
|
||||
<i class="fas fa-check-circle"></i>
|
||||
Enable
|
||||
</a>
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="#"
|
||||
ng-show="repo.status == 'ready'"
|
||||
ng-click="removeRepository(repo)"
|
||||
>
|
||||
<i class="fas fa-trash-alt"></i> Remove
|
||||
</a>
|
||||
<a class="dropdown-item" href="/r/{{repo.repoId}}/">
|
||||
<i class="fa fa-eye" aria-hidden="true"></i> View Repo
|
||||
</a>
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="/w/{{repo.repoId}}/"
|
||||
target="_self"
|
||||
ng-if="repo.options.page && repo.status == 'ready'"
|
||||
>
|
||||
<i class="fas fa-globe"></i> View Page
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li
|
||||
class="col-12 d-flex px-0 py-3 border-bottom color-border-secondary"
|
||||
ng-if="filteredRepositories.length == 0"
|
||||
>
|
||||
There is no repository to display.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="empty-state" ng-if="filteredRepositories.length == 0">
|
||||
<i class="fas fa-code-branch"></i>
|
||||
No repositories to display.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+160
-204
@@ -1,213 +1,169 @@
|
||||
<div class="container page">
|
||||
<div class="row">
|
||||
<div class="border-bottom color-border-secondary py-3 w-100">
|
||||
<div class="d-flex flex-items-start w-100">
|
||||
<form class="w-100" aria-label="Users" accept-charset="UTF-8">
|
||||
<div class="d-flex flex-column flex-lg-row flex-auto">
|
||||
<div class="mb-1 mb-md-0 mr-md-3">
|
||||
<input
|
||||
type="search"
|
||||
id="search"
|
||||
class="form-control"
|
||||
aria-label="Find a user…"
|
||||
placeholder="Find a user…"
|
||||
autocomplete="off"
|
||||
ng-model="query.search"
|
||||
/>
|
||||
</div>
|
||||
<!-- Admin Navigation -->
|
||||
<nav class="admin-nav">
|
||||
<a href="/admin/">
|
||||
<i class="fas fa-code-branch"></i> Repositories
|
||||
</a>
|
||||
<a href="/admin/users" class="active">
|
||||
<i class="fas fa-users"></i> Users
|
||||
</a>
|
||||
<a href="/admin/conferences">
|
||||
<i class="fas fa-chalkboard-teacher"></i> Conferences
|
||||
</a>
|
||||
<a href="/admin/queues">
|
||||
<i class="fas fa-tasks"></i> Queues
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
<div class="mb-1 mb-md-0 mr-md-3 col-2 input-group">
|
||||
<input
|
||||
type="number"
|
||||
id="page"
|
||||
class="form-control"
|
||||
autocomplete="off"
|
||||
ng-model="query.page"
|
||||
min="1"
|
||||
max="{{totalPage}}"
|
||||
/>
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text">/{{totalPage}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Summary Stats -->
|
||||
<div class="admin-stats">
|
||||
<div class="admin-stat-card">
|
||||
<div class="stat-value" ng-bind="total >= 0 ? (total | number) : '...'"></div>
|
||||
<div class="stat-label">Total Users</div>
|
||||
</div>
|
||||
<div class="admin-stat-card">
|
||||
<div class="stat-value">{{query.page}}/{{totalPage || '...'}}</div>
|
||||
<div class="stat-label">Current Page</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-wrap">
|
||||
<div class="dropdown mt-1 mt-lg-0 mr-1">
|
||||
<button
|
||||
class="btn btn-secondary dropdown-toggle"
|
||||
type="button"
|
||||
id="dropdownSort"
|
||||
data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
>
|
||||
Sort
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdownSort">
|
||||
<h6 class="dropdown-header">Select order</h6>
|
||||
<div class="form-check dropdown-item">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="radio"
|
||||
name="sort"
|
||||
id="username"
|
||||
value="username"
|
||||
ng-model="query.sort"
|
||||
/>
|
||||
<label class="form-check-label" for="username">
|
||||
Username
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Toolbar -->
|
||||
<div class="admin-toolbar">
|
||||
<input
|
||||
type="search"
|
||||
class="form-control"
|
||||
aria-label="Search users..."
|
||||
placeholder="Search users..."
|
||||
autocomplete="off"
|
||||
ng-model="query.search"
|
||||
/>
|
||||
|
||||
<div class="dropdown mt-1 mt-lg-0 mr-1">
|
||||
<button
|
||||
class="btn btn-secondary dropdown-toggle"
|
||||
type="button"
|
||||
id="dropdownStatus"
|
||||
data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
>
|
||||
Status
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdownStatus">
|
||||
<h6 class="dropdown-header">Select status</h6>
|
||||
<div class="form-check dropdown-item">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="checkbox"
|
||||
name="sort"
|
||||
id="statusReady"
|
||||
value="ready"
|
||||
ng-model="query.ready"
|
||||
/>
|
||||
<label class="form-check-label" for="statusReady">
|
||||
Active
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check dropdown-item">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="checkbox"
|
||||
name="sort"
|
||||
id="statusExpired"
|
||||
value="expired"
|
||||
ng-model="query.expired"
|
||||
/>
|
||||
<label class="form-check-label" for="statusExpired">
|
||||
Expired
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check dropdown-item">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="checkbox"
|
||||
name="sort"
|
||||
id="statusExpired"
|
||||
value="expired"
|
||||
ng-model="query.preparing"
|
||||
/>
|
||||
<label class="form-check-label" for="statusExpired">
|
||||
Preparing
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check dropdown-item">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="checkbox"
|
||||
name="sort"
|
||||
id="statusRemoved"
|
||||
value="removed"
|
||||
ng-model="query.removed"
|
||||
/>
|
||||
<label class="form-check-label" for="statusRemoved">
|
||||
Removed
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check dropdown-item">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="checkbox"
|
||||
name="sort"
|
||||
id="statusRemoved"
|
||||
value="removed"
|
||||
ng-model="query.error"
|
||||
/>
|
||||
<label class="form-check-label" for="statusRemoved">
|
||||
Error
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="pagination-compact">
|
||||
<button class="btn btn-sm" ng-click="query.page = Math.max(1, query.page - 1)" ng-disabled="query.page <= 1">
|
||||
<i class="fas fa-chevron-left"></i>
|
||||
</button>
|
||||
<input
|
||||
type="number"
|
||||
class="form-control form-control-sm"
|
||||
ng-model="query.page"
|
||||
min="1"
|
||||
max="{{totalPage}}"
|
||||
/>
|
||||
<span>/{{totalPage}}</span>
|
||||
<button class="btn btn-sm" ng-click="query.page = Math.min(totalPage, query.page + 1)" ng-disabled="query.page >= totalPage">
|
||||
<i class="fas fa-chevron-right"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="dropdown">
|
||||
<button
|
||||
class="btn btn-sm dropdown-toggle"
|
||||
type="button"
|
||||
id="dropdownSort"
|
||||
data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
>
|
||||
<i class="fas fa-sort"></i> Sort
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdownSort">
|
||||
<h6 class="dropdown-header">Sort by</h6>
|
||||
<a class="dropdown-item" href="#" ng-click="query.sort = 'username'">
|
||||
<i class="fas fa-check" ng-show="query.sort == 'username'"></i> Username
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="p-0 m-0 w-100">
|
||||
<li
|
||||
class="col-12 d-flex px-0 py-3 border-bottom color-border-secondary"
|
||||
ng-class="{'expired': user.status == 'expired','removed': user.status == 'removed','error': user.status == 'error' }"
|
||||
ng-repeat="user in users| filter:userFiler| orderBy:orderBy as filteredUsers"
|
||||
>
|
||||
<div class="w-100">
|
||||
<div class="">
|
||||
<h3>
|
||||
<a ng-href="/admin/users/{{user.username}}" ng-bind="user.username"></a>
|
||||
<span
|
||||
class="badge"
|
||||
ng-class="{'badge-warning': user.status == 'removed' || user.status == 'expired' || user.status == 'removing' || user.status == 'expiring', 'badge-info': user.status == 'preparing' || user.status == 'download', 'badge-success': user.status == 'active', 'badge-danger': user.status == 'error'}"
|
||||
><span ng-bind="user.status | title"></span>
|
||||
</span>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="color-text-secondary mt-2"></div>
|
||||
</div>
|
||||
|
||||
<!-- User List -->
|
||||
<div
|
||||
class="admin-list-item"
|
||||
ng-repeat="u in users | filter:userFiler | orderBy:orderBy as filteredUsers"
|
||||
>
|
||||
<div class="item-main">
|
||||
<div class="item-title">
|
||||
<a ng-href="/admin/users/{{u.username}}">
|
||||
<img
|
||||
ng-src="{{u.photo}}"
|
||||
ng-if="u.photo"
|
||||
width="20"
|
||||
height="20"
|
||||
class="rounded-circle mr-1"
|
||||
style="vertical-align: text-bottom"
|
||||
/>
|
||||
{{u.username}}
|
||||
</a>
|
||||
<span
|
||||
class="status-badge"
|
||||
ng-class="'status-' + u.status"
|
||||
>{{u.status | title}}</span>
|
||||
<span
|
||||
class="status-badge status-active"
|
||||
ng-if="u.isAdmin"
|
||||
>Admin</span>
|
||||
</div>
|
||||
<div class="item-meta">
|
||||
<span ng-if="u.emails[0].email">
|
||||
<i class="fas fa-envelope"></i> {{u.emails[0].email}}
|
||||
</span>
|
||||
<span>
|
||||
<i class="fab fa-github"></i>
|
||||
<a ng-href="https://github.com/{{u.username}}" target="_blank">{{u.username}}</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-actions">
|
||||
<div class="dropdown">
|
||||
<button
|
||||
class="btn dropdown-toggle btn-sm"
|
||||
type="button"
|
||||
data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
>
|
||||
Actions
|
||||
</button>
|
||||
<div class="dropdown-menu dropdown-menu-right">
|
||||
<a class="dropdown-item" href="/admin/users/{{u.username}}">
|
||||
<i class="far fa-eye"></i> View Details
|
||||
</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="#"
|
||||
ng-show="u.status == 'active'"
|
||||
ng-click="banUser(u)"
|
||||
>
|
||||
<i class="fas fa-ban"></i> Ban
|
||||
</a>
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="#"
|
||||
ng-show="u.status == 'removed' || u.status == 'banned'"
|
||||
ng-click="activateUser(u)"
|
||||
>
|
||||
<i class="fas fa-check-circle"></i> Activate
|
||||
</a>
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<div class="dropdown">
|
||||
<button
|
||||
class="btn black_border dropdown-toggle btn-sm"
|
||||
type="button"
|
||||
id="dropdownMenuButton"
|
||||
data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
>
|
||||
Actions
|
||||
</button>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
|
||||
<a class="dropdown-item" href="/admin/user/{{user._id}}">
|
||||
<i class="far fa-edit" aria-hidden="true"></i> Edit
|
||||
</a>
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="#"
|
||||
ng-show="user.status == 'ready' || user.status == 'error'"
|
||||
ng-click="banUser(user)"
|
||||
>
|
||||
<i class="fas fa-sync"></i> Ban
|
||||
</a>
|
||||
<a
|
||||
class="dropdown-item"
|
||||
href="#"
|
||||
ng-show="user.status == 'removed'"
|
||||
ng-click="activateUser(user)"
|
||||
>
|
||||
<i class="fas fa-check-circle"></i>
|
||||
Activate
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li
|
||||
class="col-12 d-flex px-0 py-3 border-bottom color-border-secondary"
|
||||
ng-if="filteredUsers.length == 0"
|
||||
>
|
||||
There is no user to display.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="empty-state" ng-if="filteredUsers.length == 0">
|
||||
<i class="fas fa-users"></i>
|
||||
No users match the current filters.
|
||||
</div>
|
||||
|
||||
<!-- Bottom pagination -->
|
||||
<div class="admin-toolbar" ng-if="totalPage > 1" style="justify-content: center; border-bottom: none;">
|
||||
<div class="pagination-compact">
|
||||
<button class="btn btn-sm" ng-click="query.page = Math.max(1, query.page - 1)" ng-disabled="query.page <= 1">
|
||||
<i class="fas fa-chevron-left"></i> Previous
|
||||
</button>
|
||||
<span>Page {{query.page}} of {{totalPage}}</span>
|
||||
<button class="btn btn-sm" ng-click="query.page = Math.min(totalPage, query.page + 1)" ng-disabled="query.page >= totalPage">
|
||||
Next <i class="fas fa-chevron-right"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div class="container-fluid h-100">
|
||||
<div class="row h-100">
|
||||
<div class="container-fluid h-100 anonymize-page">
|
||||
<div class="row h-100 flex-column flex-md-row">
|
||||
<div
|
||||
class="col sidePanel shadow overflow-auto h-100 d-flex align-content-end"
|
||||
class="col-md sidePanel shadow overflow-auto anonymize-form-col"
|
||||
>
|
||||
<div
|
||||
class="p-0 py-2 m-auto"
|
||||
@@ -127,11 +127,14 @@
|
||||
[a-fA-Z0-9]{6,}.
|
||||
</div>
|
||||
</div>
|
||||
<h2>Conference ID</h2>
|
||||
|
||||
<h5 class="anonymize-section-title">
|
||||
<i class="fas fa-chalkboard-teacher"></i> Conference ID
|
||||
</h5>
|
||||
<!-- Conference -->
|
||||
<div class="form-group">
|
||||
<label for="conference"
|
||||
>Conference ID<span class="text-muted">Optional</span></label
|
||||
>Conference ID <span class="text-muted">(Optional)</span></label
|
||||
>
|
||||
<input
|
||||
class="form-control"
|
||||
@@ -159,10 +162,13 @@
|
||||
conference preferences.
|
||||
</small>
|
||||
</div>
|
||||
<h2>Anonymization Options</h2>
|
||||
|
||||
<h5 class="anonymize-section-title">
|
||||
<i class="fas fa-shield-alt"></i> Anonymization Options
|
||||
</h5>
|
||||
<!-- Repo ID -->
|
||||
<div class="form-group">
|
||||
<label for="repoId">Anonymize repository id</label>
|
||||
<label for="repoId">Anonymized repository id</label>
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
@@ -281,7 +287,7 @@
|
||||
aria-expanded="true"
|
||||
aria-controls="collapseOne"
|
||||
>
|
||||
Advance options
|
||||
<i class="fas fa-cog mr-1"></i> Advanced options
|
||||
</button>
|
||||
</h2>
|
||||
</div>
|
||||
@@ -384,31 +390,31 @@
|
||||
ng-if="error"
|
||||
ng-bind="error"
|
||||
></div>
|
||||
<button
|
||||
id="submit"
|
||||
type="submit"
|
||||
class="btn btn-primary"
|
||||
ng-click="anonymizeRepo($event)"
|
||||
ng-show="repoUrl"
|
||||
ng-if="!isUpdate"
|
||||
>
|
||||
Anonymize
|
||||
</button>
|
||||
<button
|
||||
id="submit"
|
||||
type="submit"
|
||||
class="btn btn-primary"
|
||||
ng-click="updateRepo($event)"
|
||||
ng-show="repoUrl"
|
||||
ng-if="isUpdate"
|
||||
>
|
||||
Update
|
||||
</button>
|
||||
<div class="anonymize-submit-bar" ng-show="repoUrl">
|
||||
<button
|
||||
id="submit"
|
||||
type="submit"
|
||||
class="btn btn-primary btn-block"
|
||||
ng-click="anonymizeRepo($event)"
|
||||
ng-if="!isUpdate"
|
||||
>
|
||||
<i class="fas fa-user-secret mr-1"></i> Anonymize
|
||||
</button>
|
||||
<button
|
||||
id="submit"
|
||||
type="submit"
|
||||
class="btn btn-primary btn-block"
|
||||
ng-click="updateRepo($event)"
|
||||
ng-if="isUpdate"
|
||||
>
|
||||
<i class="fas fa-save mr-1"></i> Update
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="col-9 p-2 h-100 overflow-auto markdown-body body"
|
||||
class="col-md-8 p-2 overflow-auto markdown-body body anonymize-preview-col"
|
||||
ng-bind-html="html_readme"
|
||||
ng-if="html_readme"
|
||||
></div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div class="container-fluid h-100">
|
||||
<div class="row h-100">
|
||||
<div class="container-fluid h-100 anonymize-page">
|
||||
<div class="row h-100 flex-column flex-md-row">
|
||||
<div
|
||||
class="col sidePanel shadow overflow-auto h-100 d-flex align-content-end"
|
||||
class="col-md sidePanel shadow overflow-auto anonymize-form-col"
|
||||
>
|
||||
<div
|
||||
class="p-0 py-2 m-auto"
|
||||
@@ -13,15 +13,18 @@
|
||||
name="anonymizeForm"
|
||||
novalidate
|
||||
>
|
||||
<h5 class="card-title">Anonymize a pull request</h5>
|
||||
<h6 class="card-subtitle mb-2 text-muted">
|
||||
<h5 class="card-title mb-2">Anonymize a pull request</h5>
|
||||
<p class="text-muted mb-3" style="font-size: 0.9rem">
|
||||
Fill the information to anonymize! It will only take 5min.
|
||||
</h6>
|
||||
<h2>Source</h2>
|
||||
</p>
|
||||
|
||||
<h5 class="anonymize-section-title">
|
||||
<i class="fab fa-github"></i> Source
|
||||
</h5>
|
||||
<!-- pullRequestUrl -->
|
||||
<div class="form-group">
|
||||
<label for="pullRequestUrl"
|
||||
>Type the url of your pull request</label
|
||||
>URL of your pull request</label
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
@@ -30,6 +33,7 @@
|
||||
id="pullRequestUrl"
|
||||
ng-class="{'is-invalid': anonymize.pullRequestUrl.$invalid}"
|
||||
ng-model="pullRequestUrl"
|
||||
placeholder="https://github.com/owner/repo/pull/123"
|
||||
ng-model-options="{ debounce: {default: 1000, blur: 0, click: 0}, updateOn: 'default blur click' }"
|
||||
ng-change="pullRequestSelected()"
|
||||
/>
|
||||
@@ -71,11 +75,14 @@
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<h2>Conference ID</h2>
|
||||
|
||||
<h5 class="anonymize-section-title">
|
||||
<i class="fas fa-chalkboard-teacher"></i> Conference ID
|
||||
</h5>
|
||||
<!-- Conference -->
|
||||
<div class="form-group">
|
||||
<label for="conference"
|
||||
>Conference ID<span class="text-muted">Optional</span></label
|
||||
>Conference ID <span class="text-muted">(Optional)</span></label
|
||||
>
|
||||
<input
|
||||
class="form-control"
|
||||
@@ -103,10 +110,13 @@
|
||||
conference preferences.
|
||||
</small>
|
||||
</div>
|
||||
<h2>Anonymization Options</h2>
|
||||
|
||||
<h5 class="anonymize-section-title">
|
||||
<i class="fas fa-shield-alt"></i> Anonymization Options
|
||||
</h5>
|
||||
<!-- Pull Request ID -->
|
||||
<div class="form-group">
|
||||
<label for="pullRequestId">Anonymize pull request id</label>
|
||||
<label for="pullRequestId">Anonymized pull request id</label>
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
@@ -218,7 +228,7 @@
|
||||
aria-expanded="true"
|
||||
aria-controls="collapseOne"
|
||||
>
|
||||
Advance options
|
||||
<i class="fas fa-cog mr-1"></i> Advanced options
|
||||
</button>
|
||||
</h2>
|
||||
</div>
|
||||
@@ -230,7 +240,7 @@
|
||||
data-parent="#options"
|
||||
>
|
||||
<div class="card-body">
|
||||
<div class="form-group">
|
||||
<div class="form-group mb-0">
|
||||
<div class="form-check">
|
||||
<input
|
||||
class="form-check-input"
|
||||
@@ -242,7 +252,7 @@
|
||||
<label class="form-check-label" for="link"
|
||||
>Keep links</label
|
||||
>
|
||||
<small id="termsHelp" class="form-text text-muted"
|
||||
<small class="form-text text-muted"
|
||||
>Keep or remove all the links.</small
|
||||
>
|
||||
</div>
|
||||
@@ -257,7 +267,7 @@
|
||||
<label class="form-check-label" for="image"
|
||||
>Display images</label
|
||||
>
|
||||
<small id="termsHelp" class="form-text text-muted"
|
||||
<small class="form-text text-muted"
|
||||
>Images are not anonymized</small
|
||||
>
|
||||
</div>
|
||||
@@ -272,7 +282,7 @@
|
||||
<label class="form-check-label" for="date"
|
||||
>Display dates</label
|
||||
>
|
||||
<small id="termsHelp" class="form-text text-muted"
|
||||
<small class="form-text text-muted"
|
||||
>Display the date of the Pull Request and the date of
|
||||
the comments.</small
|
||||
>
|
||||
@@ -361,32 +371,32 @@
|
||||
ng-if="error"
|
||||
ng-bind="error"
|
||||
></div>
|
||||
<button
|
||||
id="submit"
|
||||
type="submit"
|
||||
class="btn btn-primary"
|
||||
ng-click="anonymizePullRequest($event)"
|
||||
ng-show="pullRequestUrl"
|
||||
ng-if="!isUpdate"
|
||||
>
|
||||
Anonymize
|
||||
</button>
|
||||
<button
|
||||
id="submit"
|
||||
type="submit"
|
||||
class="btn btn-primary"
|
||||
ng-click="updatePullRequest($event)"
|
||||
ng-show="pullRequestUrl"
|
||||
ng-if="isUpdate"
|
||||
>
|
||||
Update
|
||||
</button>
|
||||
<div class="anonymize-submit-bar" ng-show="pullRequestUrl">
|
||||
<button
|
||||
id="submit"
|
||||
type="submit"
|
||||
class="btn btn-primary btn-block"
|
||||
ng-click="anonymizePullRequest($event)"
|
||||
ng-if="!isUpdate"
|
||||
>
|
||||
<i class="fas fa-user-secret mr-1"></i> Anonymize
|
||||
</button>
|
||||
<button
|
||||
id="submit"
|
||||
type="submit"
|
||||
class="btn btn-primary btn-block"
|
||||
ng-click="updatePullRequest($event)"
|
||||
ng-if="isUpdate"
|
||||
>
|
||||
<i class="fas fa-save mr-1"></i> Update
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-9 p-2 h-100 overflow-auto" ng-if="details">
|
||||
<div class="d-flex w-100 justify-content-between align-items-center">
|
||||
<h2 class="pr-title">
|
||||
<div class="col-md-8 p-2 overflow-auto anonymize-preview-col" ng-if="details">
|
||||
<div class="d-flex w-100 justify-content-between align-items-center flex-wrap">
|
||||
<h2 class="pr-title mb-1">
|
||||
<span ng-if="options.title"
|
||||
>{{anonymize(details.pullRequest.title)}}</span
|
||||
>
|
||||
@@ -407,7 +417,8 @@
|
||||
>Pull Request on {{details.pullRequest.baseRepositoryFullName}}</small
|
||||
>
|
||||
<div
|
||||
class="pr-body shadow-sm p-3 mb-5 bg-white rounded"
|
||||
class="pr-body shadow-sm p-3 mb-4 rounded"
|
||||
style="background: var(--sidebar-bg-color)"
|
||||
ng-if="options.body"
|
||||
>
|
||||
<markdown
|
||||
@@ -461,10 +472,11 @@
|
||||
aria-labelledby="pills-diff-tab"
|
||||
>
|
||||
<div
|
||||
class="pr-diff shadow-sm p-3 mb-5 bg-white rounded"
|
||||
class="pr-diff shadow-sm p-3 mb-4 rounded"
|
||||
style="background: var(--sidebar-bg-color)"
|
||||
ng-if="options.diff"
|
||||
>
|
||||
<pre><code ng-bind-html="anonymize(details.pullRequest.diff) | diff"></code></pre>
|
||||
<pre style="overflow-x: auto"><code ng-bind-html="anonymize(details.pullRequest.diff) | diff"></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@@ -479,7 +491,7 @@
|
||||
class="pr-comment list-group-item"
|
||||
ng-repeat="comment in details.pullRequest.comments"
|
||||
>
|
||||
<div class="d-flex w-100 justify-content-between">
|
||||
<div class="d-flex w-100 justify-content-between flex-wrap">
|
||||
<h5 class="mb-1" ng-if="options.username">
|
||||
@{{anonymize(comment.author)}}
|
||||
</h5>
|
||||
|
||||
@@ -227,13 +227,13 @@
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="d-none d-md-flex flex-md-items-center flex-md-justify-end">
|
||||
<a href="/anonymize" class="text-center btn btn-primary ml-3">
|
||||
<div class="d-flex flex-wrap mt-2 mt-md-0" style="gap: 6px">
|
||||
<a href="/anonymize" class="text-center btn btn-primary btn-sm">
|
||||
<i class="fa fa-plus-circle" aria-hidden="true"></i> Anonymize Repo
|
||||
</a>
|
||||
<a
|
||||
href="/pull-request-anonymize"
|
||||
class="text-center btn btn-primary ml-3"
|
||||
class="text-center btn btn-primary btn-sm"
|
||||
>
|
||||
<i class="fa fa-plus-circle" aria-hidden="true"></i> Anonymize PR
|
||||
</a>
|
||||
|
||||
@@ -1,6 +1,18 @@
|
||||
<div class="container-fluid h-100">
|
||||
<div class="row h-100">
|
||||
<div class="leftCol shadow p-1 overflow-auto" ng-show="files.length">
|
||||
<button
|
||||
class="sidebar-toggle"
|
||||
ng-show="files.length"
|
||||
ng-click="sidebarCollapsed = !sidebarCollapsed"
|
||||
>
|
||||
<i class="fas" ng-class="sidebarCollapsed ? 'fa-folder-open' : 'fa-times'"></i>
|
||||
{{sidebarCollapsed ? 'Show Files' : 'Hide Files'}}
|
||||
</button>
|
||||
<div
|
||||
class="leftCol shadow p-1 overflow-auto"
|
||||
ng-show="files.length"
|
||||
ng-class="{'collapsed': sidebarCollapsed}"
|
||||
>
|
||||
<tree class="files" file="files"></tree>
|
||||
<div class="bottom column">
|
||||
<div
|
||||
@@ -20,7 +32,7 @@
|
||||
Loading...
|
||||
</li>
|
||||
</ol>
|
||||
<div class="">
|
||||
<div class="d-flex flex-wrap" style="gap: 4px">
|
||||
<a
|
||||
ng-if="options.isAdmin || options.isOwner"
|
||||
ng-href="/anonymize/{{repoId}}"
|
||||
@@ -32,21 +44,21 @@
|
||||
ng-href="{{url}}"
|
||||
target="__self"
|
||||
class="btn btn-outline-primary btn-sm"
|
||||
>View raw</a
|
||||
>Raw</a
|
||||
>
|
||||
<a
|
||||
ng-show="content != null"
|
||||
ng-href="{{url}}&download=true"
|
||||
target="__self"
|
||||
class="btn btn-outline-primary btn-sm"
|
||||
>Download file</a
|
||||
><i class="fas fa-download"></i><span class="d-none d-md-inline"> Download</span></a
|
||||
>
|
||||
<a
|
||||
ng-if="options.download"
|
||||
ng-href="/api/repo/{{repoId}}/zip"
|
||||
target="__self"
|
||||
class="btn btn-outline-primary btn-sm"
|
||||
>Download Repository</a
|
||||
><i class="fas fa-file-archive"></i><span class="d-none d-md-inline"> ZIP</span></a
|
||||
>
|
||||
<a
|
||||
ng-if="options.hasWebsite"
|
||||
|
||||
+28
-27
@@ -28,6 +28,7 @@
|
||||
ng-class="{'active': path == '/dashboard'}"
|
||||
href="/dashboard"
|
||||
>
|
||||
<i class="fas fa-code-branch d-lg-none mr-1"></i>
|
||||
Repositories
|
||||
</a>
|
||||
</li>
|
||||
@@ -37,6 +38,7 @@
|
||||
ng-class="{'active': path == '/pr-dashboard'}"
|
||||
href="/pr-dashboard"
|
||||
>
|
||||
<i class="fas fa-code-branch d-lg-none mr-1"></i>
|
||||
Pull Requests
|
||||
</a>
|
||||
</li>
|
||||
@@ -45,47 +47,40 @@
|
||||
class="nav-link"
|
||||
ng-class="{'active':path == '/conferences'}"
|
||||
href="/conferences"
|
||||
>Conferences</a
|
||||
>
|
||||
<i class="fas fa-chalkboard-teacher d-lg-none mr-1"></i>
|
||||
Conferences
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item" ng-if="user">
|
||||
<a
|
||||
class="nav-link"
|
||||
ng-class="{'active':path == '/anonymize'}"
|
||||
href="/anonymize"
|
||||
>Anonymize</a
|
||||
>
|
||||
<i class="fas fa-user-secret d-lg-none mr-1"></i>
|
||||
Anonymize
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item" ng-if="user">
|
||||
<a
|
||||
class="nav-link"
|
||||
ng-class="{'active':path == '/pull-request-anonymize'}"
|
||||
href="/pull-request-anonymize"
|
||||
>Anonymize PR</a
|
||||
>
|
||||
<i class="fas fa-user-secret d-lg-none mr-1"></i>
|
||||
Anonymize PR
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item dropdown" ng-if="user">
|
||||
<li class="nav-item" ng-if="user && user.isAdmin">
|
||||
<a
|
||||
class="nav-link dropdown-toggle"
|
||||
href="#"
|
||||
id="navbarDropdownMenuLink"
|
||||
role="button"
|
||||
data-toggle="dropdown"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
ng-if="user.isAdmin"
|
||||
class="nav-link"
|
||||
ng-class="{'active':path.indexOf('/admin') === 0}"
|
||||
href="/admin/"
|
||||
>
|
||||
<i class="fas fa-cog d-lg-none mr-1"></i>
|
||||
Admin
|
||||
</a>
|
||||
<div
|
||||
class="dropdown-menu"
|
||||
aria-labelledby="navbarDropdownMenuLink"
|
||||
>
|
||||
<a class="dropdown-item" href="/admin/">Repositories</a>
|
||||
<a class="dropdown-item" href="/admin/users">Users</a>
|
||||
<a class="dropdown-item" href="/admin/conferences">Conferences</a>
|
||||
<a class="dropdown-item" href="/admin/queues">Queues</a>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="navbar-nav">
|
||||
@@ -103,7 +98,7 @@
|
||||
>FAQ</a
|
||||
>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<li class="nav-item d-none d-lg-block">
|
||||
<a
|
||||
class="nav-link"
|
||||
target="_blank"
|
||||
@@ -114,16 +109,23 @@
|
||||
</li>
|
||||
|
||||
<li class="nav-item" ng-if="!isDarkMode">
|
||||
<a class="nav-link" href="#" ng-click="darkMode(true);">Dark Mode</a>
|
||||
<a class="nav-link" href="#" ng-click="darkMode(true);">
|
||||
<i class="fas fa-moon d-lg-none mr-1"></i>
|
||||
Dark Mode
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item" ng-if="isDarkMode">
|
||||
<a class="nav-link" href="#" ng-click="darkMode(false);">Light Mode</a>
|
||||
<a class="nav-link" href="#" ng-click="darkMode(false);">
|
||||
<i class="fas fa-sun d-lg-none mr-1"></i>
|
||||
Light Mode
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item" ng-if="!user">
|
||||
<a class="nav-link" target="_self" href="/github/login" data-offset="30"
|
||||
>Login
|
||||
><i class="fab fa-github d-lg-none mr-1"></i>
|
||||
Login
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item dropdown" ng-if="user">
|
||||
@@ -144,9 +146,8 @@
|
||||
class="rounded-circle"
|
||||
/>
|
||||
{{user.username}}
|
||||
<!-- <span ng-bind="user.username"></span> -->
|
||||
</a>
|
||||
<div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
|
||||
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdownMenuLink">
|
||||
<a class="dropdown-item" href="/profile">Default settings</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="/api/user/logout" target="__self"
|
||||
|
||||
@@ -155,13 +155,13 @@
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="d-none d-md-flex flex-md-items-center flex-md-justify-end">
|
||||
<a href="/anonymize" class="text-center btn btn-primary ml-3">
|
||||
<div class="d-flex flex-wrap mt-2 mt-md-0" style="gap: 6px">
|
||||
<a href="/anonymize" class="text-center btn btn-primary btn-sm">
|
||||
<i class="fa fa-plus-circle" aria-hidden="true"></i> Anonymize Repo
|
||||
</a>
|
||||
<a
|
||||
href="/pull-request-anonymize"
|
||||
class="text-center btn btn-primary ml-3"
|
||||
class="text-center btn btn-primary btn-sm"
|
||||
>
|
||||
<i class="fa fa-plus-circle" aria-hidden="true"></i> Anonymize PR
|
||||
</a>
|
||||
@@ -170,7 +170,7 @@
|
||||
data-toggle="tooltip"
|
||||
data-placement="bottom"
|
||||
href="/claim"
|
||||
class="text-center btn btn-secondary ml-3"
|
||||
class="text-center btn btn-secondary btn-sm"
|
||||
>
|
||||
Claim
|
||||
</a>
|
||||
|
||||
@@ -5,6 +5,7 @@ angular
|
||||
"$http",
|
||||
"$location",
|
||||
function ($scope, $http, $location) {
|
||||
$scope.Math = Math;
|
||||
$scope.$watch("user.status", () => {
|
||||
if ($scope.user == null) {
|
||||
$location.url("/");
|
||||
@@ -94,6 +95,7 @@ angular
|
||||
"$http",
|
||||
"$location",
|
||||
function ($scope, $http, $location) {
|
||||
$scope.Math = Math;
|
||||
$scope.$watch("user.status", () => {
|
||||
if ($scope.user == null) {
|
||||
$location.url("/");
|
||||
@@ -259,6 +261,7 @@ angular
|
||||
"$http",
|
||||
"$location",
|
||||
function ($scope, $http, $location) {
|
||||
$scope.Math = Math;
|
||||
$scope.$watch("user.status", () => {
|
||||
if ($scope.user == null) {
|
||||
$location.url("/");
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user