diff --git a/src/portal/src/app/project/project.component.html b/src/portal/src/app/project/project.component.html
index 0806cd057..91e51d7e2 100644
--- a/src/portal/src/app/project/project.component.html
+++ b/src/portal/src/app/project/project.component.html
@@ -15,7 +15,7 @@
-
@@ -25,4 +25,4 @@
-
\ No newline at end of file
+
diff --git a/src/portal/src/app/project/project.component.spec.ts b/src/portal/src/app/project/project.component.spec.ts
index 03b3aeac0..5972949f6 100644
--- a/src/portal/src/app/project/project.component.spec.ts
+++ b/src/portal/src/app/project/project.component.spec.ts
@@ -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;
@@ -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 },
]
})
diff --git a/src/portal/src/app/project/project.component.ts b/src/portal/src/app/project/project.component.ts
index b8ed02ef1..a5daa00a4 100644
--- a/src/portal/src/app/project/project.component.ts
+++ b/src/portal/src/app/project/project.component.ts
@@ -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);
}
diff --git a/src/portal/src/app/project/tag-feature-integration/tag-retention/tag-retention.component.ts b/src/portal/src/app/project/tag-feature-integration/tag-retention/tag-retention.component.ts
index 74ce80b65..1c04c38d5 100644
--- a/src/portal/src/app/project/tag-feature-integration/tag-retention/tag-retention.component.ts
+++ b/src/portal/src/app/project/tag-feature-integration/tag-retention/tag-retention.component.ts
@@ -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;
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();
}
}
diff --git a/src/portal/src/css/common.scss b/src/portal/src/css/common.scss
index 24f620b5b..8154d244c 100644
--- a/src/portal/src/css/common.scss
+++ b/src/portal/src/css/common.scss
@@ -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;
}
}
-}
\ No newline at end of file
+}
+hbr-tag {
+ .color-green {
+ color: $light-color-green !important;
+ }
+}
diff --git a/src/portal/src/css/dark-theme.scss b/src/portal/src/css/dark-theme.scss
index 7a50d8101..c3f4e82e1 100644
--- a/src/portal/src/css/dark-theme.scss
+++ b/src/portal/src/css/dark-theme.scss
@@ -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";
\ No newline at end of file
+@import "./common.scss";
diff --git a/src/portal/src/css/light-theme.scss b/src/portal/src/css/light-theme.scss
index 380cc24b3..fa6e0e42b 100644
--- a/src/portal/src/css/light-theme.scss
+++ b/src/portal/src/css/light-theme.scss
@@ -20,4 +20,5 @@ $select-back-color: $mode-background-color;
$label-form-color: $mode-background-color3;
$right-status-fill-color: #1d5100;
-@import "./common.scss";
\ No newline at end of file
+$light-color-green: $right-status-fill-color;
+@import "./common.scss";
diff --git a/src/portal/src/i18n/lang/zh-cn-lang.json b/src/portal/src/i18n/lang/zh-cn-lang.json
index 266614b30..0487f1ee0 100644
--- a/src/portal/src/i18n/lang/zh-cn-lang.json
+++ b/src/portal/src/i18n/lang/zh-cn-lang.json
@@ -1229,7 +1229,7 @@
"RULE_TEMPLATE_6": "最近#天被拉取过的镜像",
"RULE_TEMPLATE_7": "最近#天被推送过的镜像",
"SCHEDULE": "定时任务",
- "SCHEDULE_WARNING": "执行保留策略会将会删除受影响的镜像,且不可恢复。请在制定定时任务前仔细检查所有保留规则。",
+ "SCHEDULE_WARNING": "执行保留策略将会删除受影响的镜像,且不可恢复。请在制定定时任务前仔细检查所有保留规则。",
"EXISTING_RULE": "规则已存在",
"ILLEGAL_RULE": "规则不合法",
"INVALID_RULE": "无效规则",