Merge pull request #10436 from AllForNothing/nightly

Improve tag-retention and project search function
This commit is contained in:
Will Sun 2020-01-14 13:54:40 +08:00 committed by GitHub
commit a3e84380fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 112 additions and 23 deletions

View File

@ -15,7 +15,7 @@
<option value="2">{{projectTypes[2] | translate}}</option>
</select>
</div>
<hbr-filter [withDivider]="true" filterPlaceholder='{{"PROJECT.FILTER_PLACEHOLDER" | translate}}' (filterEvt)="doSearchProjects($event)"
<hbr-filter [withDivider]="true" filterPlaceholder='{{"PROJECT.FILTER_PLACEHOLDER" | translate}}'
[currentValue]="projectName"></hbr-filter>
<span class="refresh-btn" (click)="refresh()">
<clr-icon shape="refresh"></clr-icon>
@ -25,4 +25,4 @@
<create-project (create)="createProject($event)" [quotaObj]="quotaObj" [isSystemAdmin]="isSystemAdmin"></create-project>
<list-project (addProject)="openModal()"></list-project>
</div>
</div>
</div>

View File

@ -10,6 +10,10 @@ import { HttpClientTestingModule } from '@angular/common/http/testing';
import { ConfigurationService } from '../config/config.service';
import { SessionService } from "../shared/session.service";
import { of } from 'rxjs';
import { delay } from 'rxjs/operators';
import { ProjectService } from '../../lib/services';
import { MessageHandlerService } from '../shared/message-handler/message-handler.service';
import { FilterComponent } from '../../lib/components/filter/filter.component';
describe('ProjectComponent', () => {
let component: ProjectComponent;
let fixture: ComponentFixture<ProjectComponent>;
@ -210,6 +214,19 @@ describe('ProjectComponent', () => {
});
}
};
const mockProjectService = {
listProjects() {
return of({
body: []
}).pipe(delay(0));
}
};
const mockMessageHandlerService = {
refresh() {
},
showSuccess() {
},
};
beforeEach(async(() => {
TestBed.configureTestingModule({
schemas: [
@ -224,11 +241,16 @@ describe('ProjectComponent', () => {
NoopAnimationsModule,
HttpClientTestingModule
],
declarations: [ProjectComponent],
declarations: [
ProjectComponent,
FilterComponent
],
providers: [
TranslateService,
{ provide: SessionService, useValue: mockSessionService },
{ provide: ConfigurationService, useValue: mockConfigurationService },
{ provide: ProjectService, useValue: mockProjectService },
{ provide: MessageHandlerService, useValue: mockMessageHandlerService },
]
})

View File

@ -11,21 +11,27 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component, OnInit, ViewChild } from '@angular/core';
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { CreateProjectComponent } from './create-project/create-project.component';
import { ListProjectComponent } from './list-project/list-project.component';
import { ProjectTypes } from '../shared/shared.const';
import { ConfigurationService } from '../config/config.service';
import { SessionService } from "../shared/session.service";
import { QuotaHardInterface } from "../../lib/services";
import { ProjectService, QuotaHardInterface, Repository, RequestQueryParams } from "../../lib/services";
import { Configuration } from "../../lib/components/config/config";
import { FilterComponent } from '../../lib/components/filter/filter.component';
import { Subscription } from 'rxjs';
import { debounceTime, distinctUntilChanged, finalize, switchMap } from 'rxjs/operators';
import { calculatePage, doFiltering, doSorting } from '../../lib/utils/utils';
import { Project } from './project';
import { MessageHandlerService } from '../shared/message-handler/message-handler.service';
@Component({
selector: 'project',
templateUrl: 'project.component.html',
styleUrls: ['./project.component.scss']
})
export class ProjectComponent implements OnInit {
export class ProjectComponent implements OnInit, OnDestroy {
projectTypes = ProjectTypes;
quotaObj: QuotaHardInterface;
@ViewChild(CreateProjectComponent, {static: false})
@ -48,10 +54,15 @@ export class ProjectComponent implements OnInit {
window.sessionStorage['projectTypeValue'] = +_project;
}
}
@ViewChild(FilterComponent, {static: true})
filterComponent: FilterComponent;
searchSub: Subscription;
constructor(
public configService: ConfigurationService,
private session: SessionService
private session: SessionService,
private proService: ProjectService,
private msgHandler: MessageHandlerService,
) { }
ngOnInit(): void {
@ -62,16 +73,57 @@ export class ProjectComponent implements OnInit {
if (this.isSystemAdmin) {
this.getConfigration();
}
if (!this.searchSub) {
this.searchSub = this.filterComponent.filterTerms.pipe(
debounceTime(500),
distinctUntilChanged(),
switchMap(projectName => {
// reset project list
this.listProject.currentPage = 1;
this.listProject.searchKeyword = projectName;
this.listProject.selectedRow = [];
this.loading = true;
let passInFilteredType: number = undefined;
if (this.listProject.filteredType > 0) {
passInFilteredType = this.listProject.filteredType - 1;
}
return this.proService.listProjects( this.listProject.searchKeyword,
passInFilteredType, this.listProject.currentPage, this.listProject.pageSize)
.pipe(finalize(() => {
this.loading = false;
}));
})).subscribe(response => {
// Get total count
if (response.headers) {
let xHeader: string = response.headers.get("X-Total-Count");
if (xHeader) {
this.listProject.totalCount = parseInt(xHeader, 0);
}
}
this.listProject.projects = response.body as Project[];
}, error => {
this.msgHandler.handleError(error);
});
}
}
ngOnDestroy() {
if (this.searchSub) {
this.searchSub.unsubscribe();
this.searchSub = null;
}
}
getConfigration() {
this.configService.getConfiguration()
.subscribe((configurations: Configuration) => {
this.quotaObj = {
count_per_project: configurations.count_per_project ? configurations.count_per_project.value : -1,
storage_per_project: configurations.storage_per_project ? configurations.storage_per_project.value : -1
};
});
.subscribe((configurations: Configuration) => {
this.quotaObj = {
count_per_project: configurations.count_per_project ? configurations.count_per_project.value : -1,
storage_per_project: configurations.storage_per_project ? configurations.storage_per_project.value : -1
};
});
}
public get isSystemAdmin(): boolean {
let account = this.session.getCurrentUser();
return account != null && account.has_admin_role;
@ -86,11 +138,6 @@ export class ProjectComponent implements OnInit {
}
}
doSearchProjects(projectName: string): void {
this.projectName = projectName;
this.listProject.doSearchProject(this.projectName);
}
doFilterProjects(): void {
this.listProject.doFilterProject(+this.selecteType);
}

View File

@ -37,6 +37,9 @@ const SCHEDULE_TYPE = {
HOURLY: "Hourly",
CUSTOM: "Custom"
};
const RUNNING: string = "Running";
const PENDING: string = "pending";
const TIMEOUT: number = 5000;
@Component({
selector: 'tag-retention',
templateUrl: './tag-retention.component.html',
@ -341,6 +344,14 @@ export class TagRetentionComponent implements OnInit {
}
this.historyList = response.body as Array<any>;
TagRetentionComponent.calculateDuration(this.historyList);
if (this.historyList && this.historyList.length
&& this.historyList.some(item => {
return item.status === RUNNING || item.status === PENDING;
})) {
setTimeout(() => {
this.loadLog();
}, TIMEOUT);
}
}, error => {
this.errorHandler.error(error);
});
@ -362,6 +373,7 @@ export class TagRetentionComponent implements OnInit {
this.tagRetentionService.getProjectInfo(this.projectId).subscribe(
response => {
this.retentionId = response.metadata.retention_id;
this.refreshList();
this.getRetention();
}, error => {
this.loadingRule = false;
@ -435,6 +447,7 @@ export class TagRetentionComponent implements OnInit {
return this.tagRetentionService.getI18nKey(str);
}
clrLoad() {
this.refreshList();
}
}

View File

@ -4,7 +4,7 @@
> .nav-item {
> button {
box-shadow: 0 -3px 0 $mode-link-color2 inset;
color: 0077b8;
color: #0077b8;
}
}
}
@ -115,4 +115,9 @@ clr-dg-action-overflow {
color: $select-option-color;
}
}
}
}
hbr-tag {
.color-green {
color: $light-color-green !important;
}
}

View File

@ -18,5 +18,6 @@ $select-back-color: #acbac3;
$label-form-color: #212129;
$fill-color1: #ccc;
$right-status-fill-color: white;
$light-color-green: #4cd400;
@import "./common.scss";
@import "./common.scss";

View File

@ -20,4 +20,5 @@ $select-back-color: $mode-background-color;
$label-form-color: $mode-background-color3;
$right-status-fill-color: #1d5100;
@import "./common.scss";
$light-color-green: $right-status-fill-color;
@import "./common.scss";

View File

@ -1229,7 +1229,7 @@
"RULE_TEMPLATE_6": "最近#天被拉取过的镜像",
"RULE_TEMPLATE_7": "最近#天被推送过的镜像",
"SCHEDULE": "定时任务",
"SCHEDULE_WARNING": "执行保留策略将会删除受影响的镜像,且不可恢复。请在制定定时任务前仔细检查所有保留规则。",
"SCHEDULE_WARNING": "执行保留策略将会删除受影响的镜像,且不可恢复。请在制定定时任务前仔细检查所有保留规则。",
"EXISTING_RULE": "规则已存在",
"ILLEGAL_RULE": "规则不合法",
"INVALID_RULE": "无效规则",