diff --git a/.travis.yml b/.travis.yml index 9b3429fe8..7ba2076f8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,7 +20,8 @@ matrix: - go: 1.12.5 env: - OFFLINE=true - - node_js: 10.16.2 + - language: node_js + node_js: 10.16.2 env: - UI_UT=true env: diff --git a/make/photon/portal/Dockerfile b/make/photon/portal/Dockerfile index 9f71410f7..004d0113a 100644 --- a/make/photon/portal/Dockerfile +++ b/make/photon/portal/Dockerfile @@ -6,6 +6,7 @@ COPY ./LICENSE /portal_src WORKDIR /build_dir + RUN cp -r /portal_src/* /build_dir \ && ls -la \ && apt-get update \ @@ -14,7 +15,7 @@ RUN cp -r /portal_src/* /build_dir \ && npm install \ && npm run build_lib \ && npm run link_lib \ - && npm run release + && node --max_old_space_size=8192 'node_modules/@angular/cli/bin/ng' build --prod FROM photon:2.0 diff --git a/src/portal/angular.json b/src/portal/angular.json index 157657038..b7bf203d3 100644 --- a/src/portal/angular.json +++ b/src/portal/angular.json @@ -26,6 +26,7 @@ "node_modules/@clr/ui/clr-ui.min.css", "node_modules/swagger-ui/dist/swagger-ui.css", "node_modules/prismjs/themes/prism-solarizedlight.css", + "src/global.scss", "src/styles.css" ], "scripts": [ diff --git a/src/portal/lib/ng-package.json b/src/portal/lib/ng-package.json index 89852ea86..921319790 100644 --- a/src/portal/lib/ng-package.json +++ b/src/portal/lib/ng-package.json @@ -4,11 +4,6 @@ "deleteDestPath": false, "lib": { "entryFile": "index.ts", - "externals": { - "@ngx-translate/core": "ngx-translate-core", - "@ngx-translate/core/index": "ngx-translate-core", - "ngx-markdown": "ngx-markdown" - }, "umdModuleIds": { "@clr/angular" : "angular", "ngx-markdown" : "ngxMarkdown", diff --git a/src/portal/lib/ng-package.prod.json b/src/portal/lib/ng-package.prod.json index 85a87a50d..4bf1dc101 100644 --- a/src/portal/lib/ng-package.prod.json +++ b/src/portal/lib/ng-package.prod.json @@ -3,11 +3,6 @@ "dest": "./dist", "lib": { "entryFile": "index.ts", - "externals": { - "@ngx-translate/core": "ngx-translate-core", - "@ngx-translate/core/index": "ngx-translate-core", - "ngx-markdown": "ngx-markdown" - }, "umdModuleIds": { "@clr/angular" : "angular", "ngx-markdown" : "ngxMarkdown", diff --git a/src/portal/lib/package-lock.json b/src/portal/lib/package-lock.json new file mode 100644 index 000000000..e4655fb88 --- /dev/null +++ b/src/portal/lib/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "@harbor/ui", + "version": "1.10.0", + "lockfileVersion": 1 +} diff --git a/src/portal/lib/package.json b/src/portal/lib/package.json index 9c49c4207..db2c23758 100644 --- a/src/portal/lib/package.json +++ b/src/portal/lib/package.json @@ -1,7 +1,7 @@ { "name": "@harbor/ui", - "version": "1.9.0", - "description": "Harbor shared UI components based on Clarity and Angular7", + "version": "1.10.0", + "description": "Harbor shared UI components based on Clarity and Angular8", "author": "CNCF", "module": "index.js", "main": "bundles/harborui.umd.min.js", @@ -19,26 +19,26 @@ }, "homepage": "https://github.com/vmware/harbor#readme", "peerDependencies": { - "@angular/animations": "^7.1.3", - "@angular/common": "^7.1.3", - "@angular/compiler": "^7.1.3", - "@angular/core": "^7.1.3", - "@angular/forms": "^7.1.3", - "@angular/http": "^7.1.3", - "@angular/platform-browser": "^7.1.3", - "@angular/platform-browser-dynamic": "^7.1.3", - "@angular/router": "^7.1.3", + "@angular/animations": "^8.2.0", + "@angular/common": "^8.2.0", + "@angular/compiler": "^8.2.0", + "@angular/core": "^8.2.0", + "@angular/forms": "^8.2.0", + "@angular/http": "^8.2.0", + "@angular/platform-browser": "^8.2.0", + "@angular/platform-browser-dynamic": "^8.2.0", + "@angular/router": "^8.2.0", "@ngx-translate/core": "^10.0.2", "@ngx-translate/http-loader": "^3.0.1", "@webcomponents/custom-elements": "^1.1.3", - "@clr/angular": "^1.0.0", - "@clr/ui": "^1.0.0", - "@clr/icons": "^1.0.0", + "@clr/angular": "^2.1.0", + "@clr/icons": "^2.1.0", + "@clr/ui": "^2.1.0", "core-js": "^2.5.4", "intl": "^1.2.5", "mutationobserver-shim": "^0.3.2", "ngx-cookie": "^1.0.0", - "ngx-markdown": "^6.2.0", + "ngx-markdown": "^8.1.0", "rxjs": "^6.3.3", "ts-helpers": "^1.1.1", "web-animations-js": "^2.2.1", diff --git a/src/portal/lib/src/config/config.ts b/src/portal/lib/src/config/config.ts index 9505b11c5..7d11b5d0a 100644 --- a/src/portal/lib/src/config/config.ts +++ b/src/portal/lib/src/config/config.ts @@ -100,6 +100,7 @@ export class Configuration { oidc_scope?: StringValueItem; count_per_project: NumberValueItem; storage_per_project: NumberValueItem; + cfg_expiration: NumberValueItem; public constructor() { this.auth_mode = new StringValueItem("db_auth", true); this.project_creation_restriction = new StringValueItem("everyone", true); diff --git a/src/portal/lib/src/config/gc/gc.component.spec.ts b/src/portal/lib/src/config/gc/gc.component.spec.ts index c9b442682..1f4941b8c 100644 --- a/src/portal/lib/src/config/gc/gc.component.spec.ts +++ b/src/portal/lib/src/config/gc/gc.component.spec.ts @@ -9,6 +9,7 @@ import { GcViewModelFactory } from './gc.viewmodel.factory'; import { CronScheduleComponent } from '../../cron-schedule/cron-schedule.component'; import { CronTooltipComponent } from "../../cron-schedule/cron-tooltip/cron-tooltip.component"; import { of } from 'rxjs'; +import { GcJobData } from './gcLog'; describe('GcComponent', () => { let component: GcComponent; @@ -18,13 +19,17 @@ describe('GcComponent', () => { systemInfoEndpoint: "/api/system/gc" }; let mockSchedule = []; - let mockJobs = [ + let mockJobs: GcJobData[] = [ { id: 22222, schedule: null, job_status: 'string', - creation_time: new Date(), - update_time: new Date(), + creation_time: new Date().toDateString(), + update_time: new Date().toDateString(), + job_name: 'string', + job_kind: 'string', + job_uuid: 'string', + delete: false } ]; let spySchedule: jasmine.Spy; diff --git a/src/portal/lib/src/config/gc/gc.component.ts b/src/portal/lib/src/config/gc/gc.component.ts index 44d805d92..ccd4196aa 100644 --- a/src/portal/lib/src/config/gc/gc.component.ts +++ b/src/portal/lib/src/config/gc/gc.component.ts @@ -32,7 +32,7 @@ export class GcComponent implements OnInit { getText = 'CONFIG.GC'; getLabelCurrent = 'GC.CURRENT_SCHEDULE'; @Output() loadingGcStatus = new EventEmitter(); - @ViewChild(CronScheduleComponent) + @ViewChild(CronScheduleComponent, {static: false}) CronScheduleComponent: CronScheduleComponent; constructor( private gcRepoService: GcRepoService, diff --git a/src/portal/lib/src/config/project-quotas/edit-project-quotas/edit-project-quotas.component.html b/src/portal/lib/src/config/project-quotas/edit-project-quotas/edit-project-quotas.component.html index c9bd48440..89ab0c585 100644 --- a/src/portal/lib/src/config/project-quotas/edit-project-quotas/edit-project-quotas.component.html +++ b/src/portal/lib/src/config/project-quotas/edit-project-quotas/edit-project-quotas.component.html @@ -4,79 +4,73 @@ -
-
- -
- -
-
- -
+ + + + + + + + + + + + {{ 'DESTINATION.NAME_IS_REQUIRED' | translate }} + + + + + + + + +
+ +
+
+ +
-
- -
- - -
- -
- - -
- -
- - +
+ + {{ 'DESTINATION.URL_IS_REQUIRED' | translate }} +
- -
- - +
+ + + + + + +
+ +
+
+ + + + +
- -
- - - - - -
- -
- - +
+ + +
-
- - -
-
+ + + + + +
+ + +
\ No newline at end of file diff --git a/src/portal/lib/src/create-edit-endpoint/create-edit-endpoint.component.ts b/src/portal/lib/src/create-edit-endpoint/create-edit-endpoint.component.ts index 28d7624e4..b02b6feef 100644 --- a/src/portal/lib/src/create-edit-endpoint/create-edit-endpoint.component.ts +++ b/src/portal/lib/src/create-edit-endpoint/create-edit-endpoint.component.ts @@ -63,13 +63,13 @@ export class CreateEditEndpointComponent selectedType: string; initVal: Endpoint; targetForm: NgForm; - @ViewChild("targetForm") currentForm: NgForm; + @ViewChild("targetForm", {static: false}) currentForm: NgForm; targetEndpoint; testOngoing: boolean; onGoing: boolean; endpointId: number | string; - @ViewChild(InlineAlertComponent) inlineAlert: InlineAlertComponent; + @ViewChild(InlineAlertComponent, {static: false}) inlineAlert: InlineAlertComponent; @Output() reload = new EventEmitter(); diff --git a/src/portal/lib/src/create-edit-label/create-edit-label.component.html b/src/portal/lib/src/create-edit-label/create-edit-label.component.html index ab1f83b9d..92f040130 100644 --- a/src/portal/lib/src/create-edit-label/create-edit-label.component.html +++ b/src/portal/lib/src/create-edit-label/create-edit-label.component.html @@ -3,13 +3,13 @@
- +
diff --git a/src/portal/lib/src/project-policy-config/project-policy-config.component.scss b/src/portal/lib/src/project-policy-config/project-policy-config.component.scss index ddda99c37..53759f80c 100644 --- a/src/portal/lib/src/project-policy-config/project-policy-config.component.scss +++ b/src/portal/lib/src/project-policy-config/project-policy-config.component.scss @@ -5,6 +5,7 @@ .select { width: 120px; } + .margin-top-4 { margin-top: 4px; } @@ -17,6 +18,7 @@ width: 270px; color: #0079bb; overflow-y: auto; + li { height: 24px; line-height: 24px; @@ -43,16 +45,16 @@ .padding-top-8 { padding-top: 8px; } - -.padding-left-80 { - padding-left: 80px; +.position-relative { + position: relative; } - .add-modal { position: absolute; padding: 0 8px; background-color: rgb(238, 238, 238); - + .flex-direction-column { + flex-direction: column; + } input { width: 100%; border: 1px solid; @@ -63,8 +65,34 @@ } } -.hand{ +.hand { cursor: pointer; margin: 0; } +.config-subtext { + font-size: 0.55rem; + line-height: 1.2rem; + color: rgb(86, 86, 86); + font-weight: 300; +} + +.mt-05 { + margin-bottom: 0.5rem; +} + +.col-flex-grow-0 { + flex-grow: 0; +} + +.expire-data { + min-width: 12.5rem; + margin-top: -1rem; +} + +.bottom-line { + display: flex; + flex-direction: column-reverse; + font-size: 13px; + color: #000; +} diff --git a/src/portal/lib/src/project-policy-config/project-policy-config.component.ts b/src/portal/lib/src/project-policy-config/project-policy-config.component.ts index a6ab59495..1727ad04e 100644 --- a/src/portal/lib/src/project-policy-config/project-policy-config.component.ts +++ b/src/portal/lib/src/project-policy-config/project-policy-config.component.ts @@ -61,9 +61,9 @@ export class ProjectPolicyConfigComponent implements OnInit { @Input() hasSignedIn: boolean; @Input() hasProjectAdminRole: boolean; - @ViewChild('cfgConfirmationDialog') confirmationDlg: ConfirmationDialogComponent; - @ViewChild('dateInput') dateInput: ElementRef; - @ViewChild('dateSystemInput') dateSystemInput: ElementRef; + @ViewChild('cfgConfirmationDialog', {static: false}) confirmationDlg: ConfirmationDialogComponent; + @ViewChild('dateInput', {static: false}) dateInput: ElementRef; + @ViewChild('dateSystemInput', {static: false}) dateSystemInput: ElementRef; systemInfo: SystemInfo; orgProjectPolicy = new ProjectPolicy(); diff --git a/src/portal/lib/src/push-image/push-image.component.spec.ts b/src/portal/lib/src/push-image/push-image.component.spec.ts index a9178514b..4605fcb0d 100644 --- a/src/portal/lib/src/push-image/push-image.component.spec.ts +++ b/src/portal/lib/src/push-image/push-image.component.spec.ts @@ -39,7 +39,7 @@ describe('PushImageButtonComponent (inline template)', () => { expect(component).toBeTruthy(); }); - it('should open the drop-down panel', fakeAsync(() => { + it('should open the drop-down panel', () => { fixture.detectChanges(); fixture.whenStable().then(() => { fixture.detectChanges(); @@ -57,6 +57,6 @@ describe('PushImageButtonComponent (inline template)', () => { expect(copyInputs[1].value.trim()).toEqual(`docker push ${component.registryUrl}/${component.projectName}/IMAGE[:TAG]`); }); }); - })); + }); }); diff --git a/src/portal/lib/src/push-image/push-image.component.ts b/src/portal/lib/src/push-image/push-image.component.ts index 0fd21a60a..3c35ae2a8 100644 --- a/src/portal/lib/src/push-image/push-image.component.ts +++ b/src/portal/lib/src/push-image/push-image.component.ts @@ -13,9 +13,9 @@ export class PushImageButtonComponent { @Input() registryUrl: string = "unknown"; @Input() projectName: string = "unknown"; - @ViewChild("tagCopy") tagCopyInput: CopyInputComponent; - @ViewChild("pushCopy") pushCopyInput: CopyInputComponent; - @ViewChild("copyAlert") copyAlert: InlineAlertComponent; + @ViewChild("tagCopy", {static: false}) tagCopyInput: CopyInputComponent; + @ViewChild("pushCopy", {static: false}) pushCopyInput: CopyInputComponent; + @ViewChild("copyAlert", {static: false}) copyAlert: InlineAlertComponent; public get tagCommand(): string { return `docker tag SOURCE_IMAGE[:TAG] ${this.registryUrl}/${ diff --git a/src/portal/lib/src/push-image/push-image.scss b/src/portal/lib/src/push-image/push-image.scss index d5707a3d3..74835d8ae 100644 --- a/src/portal/lib/src/push-image/push-image.scss +++ b/src/portal/lib/src/push-image/push-image.scss @@ -32,6 +32,7 @@ .command-input { font-size: 14px; font-weight: 500; + border: 0; } :host>>>.dropdown-menu { diff --git a/src/portal/lib/src/replication/replication.component.ts b/src/portal/lib/src/replication/replication.component.ts index 1bdbfe200..8079ac3bb 100644 --- a/src/portal/lib/src/replication/replication.component.ts +++ b/src/portal/lib/src/replication/replication.component.ts @@ -120,16 +120,16 @@ export class ReplicationComponent implements OnInit, OnDestroy { jobs: ReplicationJobItem[]; - @ViewChild(ListReplicationRuleComponent) + @ViewChild(ListReplicationRuleComponent, {static: false}) listReplicationRule: ListReplicationRuleComponent; - @ViewChild(CreateEditRuleComponent) + @ViewChild(CreateEditRuleComponent, {static: false}) createEditPolicyComponent: CreateEditRuleComponent; - @ViewChild("replicationConfirmDialog") + @ViewChild("replicationConfirmDialog", {static: false}) replicationConfirmDialog: ConfirmationDialogComponent; - @ViewChild("StopConfirmDialog") + @ViewChild("StopConfirmDialog", {static: false}) StopConfirmDialog: ConfirmationDialogComponent; creationTimeComparator: Comparator = new CustomComparator< diff --git a/src/portal/lib/src/repository-gridview/repository-gridview.component.ts b/src/portal/lib/src/repository-gridview/repository-gridview.component.ts index fe533195b..62bd594ba 100644 --- a/src/portal/lib/src/repository-gridview/repository-gridview.component.ts +++ b/src/portal/lib/src/repository-gridview/repository-gridview.component.ts @@ -80,10 +80,10 @@ export class RepositoryGridviewComponent implements OnChanges, OnInit { totalCount = 0; currentState: State; - @ViewChild("confirmationDialog") + @ViewChild("confirmationDialog", {static: false}) confirmationDialog: ConfirmationDialogComponent; - @ViewChild("gridView") gridView: GridViewComponent; + @ViewChild("gridView", {static: false}) gridView: GridViewComponent; hasCreateRepositoryPermission: boolean; hasDeleteRepositoryPermission: boolean; constructor(@Inject(SERVICE_CONFIG) private configInfo: IServiceConfig, diff --git a/src/portal/lib/src/repository/repository.component.html b/src/portal/lib/src/repository/repository.component.html index a5216ed33..a8698657e 100644 --- a/src/portal/lib/src/repository/repository.component.html +++ b/src/portal/lib/src/repository/repository.component.html @@ -33,7 +33,7 @@ {{ 'REPOSITORY.MARKDOWN' | translate }} -
+

{{'REPOSITORY.NO_INFO' | translate }}

@@ -42,7 +42,8 @@
- +
diff --git a/src/portal/lib/src/repository/repository.component.ts b/src/portal/lib/src/repository/repository.component.ts index 74204ec1e..1ae176e48 100644 --- a/src/portal/lib/src/repository/repository.component.ts +++ b/src/portal/lib/src/repository/repository.component.ts @@ -56,7 +56,7 @@ export class RepositoryComponent implements OnInit { timerHandler: any; - @ViewChild('confirmationDialog') + @ViewChild('confirmationDialog', {static: false}) confirmationDlg: ConfirmationDialogComponent; constructor( diff --git a/src/portal/lib/src/tag/tag-detail.component.html b/src/portal/lib/src/tag/tag-detail.component.html index 83c053a2f..bee923073 100644 --- a/src/portal/lib/src/tag/tag-detail.component.html +++ b/src/portal/lib/src/tag/tag-detail.component.html @@ -89,8 +89,8 @@ - - + + {{ 'REPOSITORY.BUILD_HISTORY' | translate }} diff --git a/src/portal/lib/src/tag/tag.component.html b/src/portal/lib/src/tag/tag.component.html index 9df2ddad1..445d6d9ef 100644 --- a/src/portal/lib/src/tag/tag.component.html +++ b/src/portal/lib/src/tag/tag.component.html @@ -3,7 +3,7 @@