diff --git a/src/portal/src/app/base/left-side-nav/replication/replication/list-replication-rule/list-replication-rule.component.html b/src/portal/src/app/base/left-side-nav/replication/replication/list-replication-rule/list-replication-rule.component.html index 3131746fd..6509a5f1f 100644 --- a/src/portal/src/app/base/left-side-nav/replication/replication/list-replication-rule/list-replication-rule.component.html +++ b/src/portal/src/app/base/left-side-nav/replication/replication/list-replication-rule/list-replication-rule.component.html @@ -90,31 +90,69 @@ - {{ 'REPLICATION.NAME' | translate }} - {{ - 'REPLICATION.STATUS' | translate - }} - {{ - 'REPLICATION.SRC_REGISTRY' | translate - }} - {{ - 'REPLICATION.REPLICATION_MODE' | translate - }} - {{ - 'REPLICATION.DESTINATION_NAMESPACE' | translate - }} - {{ - 'REPLICATION.DES_REPO_FLATTENING' | translate - }} - {{ - 'REPLICATION.REPLICATION_TRIGGER' | translate - }} - {{ - 'REPLICATION.BANDWIDTH' | translate - }} - {{ - 'REPLICATION.DESCRIPTION' | translate - }} + + + {{ 'REPLICATION.NAME' | translate }} + + + + + {{ 'REPLICATION.STATUS' | translate }} + + + + + {{ 'REPLICATION.SRC_REGISTRY' | translate }} + + + + + {{ 'REPLICATION.REPLICATION_MODE' | translate }} + + + + + {{ 'REPLICATION.DESTINATION_NAMESPACE' | translate }} + + + + + {{ 'REPLICATION.DES_REPO_FLATTENING' | translate }} + + + + + {{ 'REPLICATION.REPLICATION_TRIGGER' | translate }} + + + + {{ 'REPLICATION.BANDWIDTH' | translate }} + + + + + {{ 'REPLICATION.DESCRIPTION' | translate }} + + {{ 'REPLICATION.PLACEHOLDER' | translate }} diff --git a/src/portal/src/app/base/left-side-nav/replication/replication/list-replication-rule/list-replication-rule.component.scss b/src/portal/src/app/base/left-side-nav/replication/replication/list-replication-rule/list-replication-rule.component.scss index 2210f1188..1ce2267fb 100644 --- a/src/portal/src/app/base/left-side-nav/replication/replication/list-replication-rule/list-replication-rule.component.scss +++ b/src/portal/src/app/base/left-side-nav/replication/replication/list-replication-rule/list-replication-rule.component.scss @@ -7,15 +7,15 @@ } .min-width { - width: 236px; + min-width: 236px; } .col-width { - width: 140px; + min-width: 140px; } .status-width { - width: 130px; + min-width: 130px; } .icon-style { diff --git a/src/portal/src/app/base/left-side-nav/replication/replication/list-replication-rule/list-replication-rule.component.ts b/src/portal/src/app/base/left-side-nav/replication/replication/list-replication-rule/list-replication-rule.component.ts index e5df9852c..b7410ae3f 100644 --- a/src/portal/src/app/base/left-side-nav/replication/replication/list-replication-rule/list-replication-rule.component.ts +++ b/src/portal/src/app/base/left-side-nav/replication/replication/list-replication-rule/list-replication-rule.component.ts @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. import { + AfterViewInit, Component, EventEmitter, Input, @@ -31,10 +32,12 @@ import { import { ErrorHandler } from '../../../../../shared/units/error-handler'; import { clone, + getHiddenArrayFromLocalStorage, getPageSizeFromLocalStorage, getQueryString, getSortingString, PageSizeMapKeys, + setHiddenArrayToLocalStorage, setPageSizeToLocalStorage, } from '../../../../../shared/units/utils'; import { @@ -64,7 +67,7 @@ import { JobType } from '../../../job-service-dashboard/job-service-dashboard.in templateUrl: './list-replication-rule.component.html', styleUrls: ['./list-replication-rule.component.scss'], }) -export class ListReplicationRuleComponent implements OnInit { +export class ListReplicationRuleComponent implements OnInit, AfterViewInit { @Input() selectedId: number | string; @Input() withReplicationJob: boolean; @Input() hasCreateReplicationPermission: boolean; @@ -94,14 +97,21 @@ export class ListReplicationRuleComponent implements OnInit { loading: boolean = true; paused: boolean = false; - + hiddenArray: boolean[] = getHiddenArrayFromLocalStorage( + PageSizeMapKeys.LIST_REPLICATION_RULE_COMPONENT, + [false, false, false, false, false, false, false, true, true] + ); + copiedHiddenArray: boolean[] = []; + private _hasViewInit: boolean = false; constructor( private replicationService: ReplicationService, private translateService: TranslateService, private errorHandlerEntity: ErrorHandler, private operationService: OperationService, private scheduleService: ScheduleService - ) {} + ) { + this.copiedHiddenArray = clone(this.hiddenArray); + } ngOnInit() { this.scheduleService @@ -111,6 +121,10 @@ export class ListReplicationRuleComponent implements OnInit { }); } + ngAfterViewInit() { + this._hasViewInit = true; + } + getTriggerTypeI18n(t: ReplicationTrigger) { if (t) { if (this.paused && t?.type === TRIGGER.SCHEDULED) { @@ -383,4 +397,14 @@ export class ListReplicationRuleComponent implements OnInit { } return 'REPLICATION.UNLIMITED'; } + + columnHiddenChange(index: number) { + if (this._hasViewInit) { + this.copiedHiddenArray[index] = !this.copiedHiddenArray[index]; + setHiddenArrayToLocalStorage( + PageSizeMapKeys.LIST_REPLICATION_RULE_COMPONENT, + this.copiedHiddenArray + ); + } + } } diff --git a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.html b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.html index 942e1ccf8..5fb7cbc3b 100644 --- a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.html +++ b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.html @@ -136,34 +136,82 @@ {{ 'REPOSITORY.ARTIFACTS_COUNT' | translate }} + > + {{ 'REPOSITORY.ARTIFACTS_COUNT' | translate }} + + + + + {{ 'REPOSITORY.PULL_COMMAND' | translate }} + + + + + {{ 'REPOSITORY.PLATFORM' | translate }} + + + + + {{ 'REPOSITORY.TAGS' | translate }} + + + + + {{ 'ACCESSORY.CO_SIGNED' | translate }} + + + + + {{ 'REPOSITORY.SIZE' | translate }} + + + + + {{ 'REPOSITORY.VULNERABILITY' | translate }} + + + + + {{ 'ARTIFACT.ANNOTATION' | translate }} + + + + + {{ 'REPOSITORY.LABELS' | translate }} + + + + + {{ 'REPOSITORY.PUSH_TIME' | translate }} + + + + + {{ 'REPOSITORY.PULL_TIME' | translate }} + - {{ - 'REPOSITORY.PULL_COMMAND' | translate - }} - {{ - 'REPOSITORY.PLATFORM' | translate - }} - {{ 'REPOSITORY.TAGS' | translate }} - {{ - 'ACCESSORY.CO_SIGNED' | translate - }} - {{ - 'REPOSITORY.SIZE' | translate - }} - {{ - 'REPOSITORY.VULNERABILITY' | translate - }} - {{ - 'ARTIFACT.ANNOTATION' | translate - }} - {{ 'REPOSITORY.LABELS' | translate }} - {{ - 'REPOSITORY.PUSH_TIME' | translate - }} - {{ - 'REPOSITORY.PULL_TIME' | translate - }} {{ 'ARTIFACT.PLACEHOLDER' | translate }} diff --git a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.ts b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.ts index 9a9608df1..1fedfbd7f 100644 --- a/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.ts +++ b/src/portal/src/app/base/project/repository/artifact/artifact-list-page/artifact-list/artifact-list-tab/artifact-list-tab.component.ts @@ -11,7 +11,13 @@ // 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, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { + AfterViewInit, + Component, + OnDestroy, + OnInit, + ViewChild, +} from '@angular/core'; import { forkJoin, Observable, of, Subscription } from 'rxjs'; import { catchError, finalize, map } from 'rxjs/operators'; import { TranslateService } from '@ngx-translate/core'; @@ -30,9 +36,11 @@ import { DEFAULT_SUPPORTED_MIME_TYPES, doSorting, formatSize, + getHiddenArrayFromLocalStorage, getPageSizeFromLocalStorage, getSortingString, PageSizeMapKeys, + setHiddenArrayToLocalStorage, setPageSizeToLocalStorage, VULNERABILITY_SCAN_STATUS, } from '../../../../../../../shared/units/utils'; @@ -96,7 +104,9 @@ const FALSE: string = 'false'; templateUrl: './artifact-list-tab.component.html', styleUrls: ['./artifact-list-tab.component.scss'], }) -export class ArtifactListTabComponent implements OnInit, OnDestroy { +export class ArtifactListTabComponent + implements OnInit, OnDestroy, AfterViewInit +{ projectId: number; projectName: string; repoName: string; @@ -160,6 +170,25 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy { onScanArtifactsLength: number = 0; stopBtnState: ClrLoadingState = ClrLoadingState.DEFAULT; updateArtifactSub: Subscription; + + hiddenArray: boolean[] = getHiddenArrayFromLocalStorage( + PageSizeMapKeys.ARTIFACT_LIST_TAB_COMPONENT, + [ + false, + false, + false, + false, + false, + false, + false, + true, + false, + false, + false, + ] + ); + copiedHiddenArray: boolean[] = []; + private _hasViewInit: boolean = false; constructor( private errorHandlerService: ErrorHandler, private artifactService: ArtifactService, @@ -171,7 +200,9 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy { private router: Router, private appConfigService: AppConfigService, private artifactListPageService: ArtifactListPageService - ) {} + ) { + this.copiedHiddenArray = clone(this.hiddenArray); + } initRouterData() { this.projectId = this.activatedRoute.snapshot?.parent?.parent?.params['id']; @@ -212,6 +243,11 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy { ); } } + + ngAfterViewInit() { + this._hasViewInit = true; + } + ngOnDestroy() { if (this.updateArtifactSub) { this.updateArtifactSub.unsubscribe(); @@ -1014,4 +1050,14 @@ export class ArtifactListTabComponent implements OnInit, OnDestroy { isEllipsisActive(ele: HTMLSpanElement): boolean { return ele?.offsetWidth < ele?.scrollWidth; } + + columnHiddenChange(index: number) { + if (this._hasViewInit) { + this.copiedHiddenArray[index] = !this.copiedHiddenArray[index]; + setHiddenArrayToLocalStorage( + PageSizeMapKeys.ARTIFACT_LIST_TAB_COMPONENT, + this.copiedHiddenArray + ); + } + } } diff --git a/src/portal/src/app/shared/units/utils.spec.ts b/src/portal/src/app/shared/units/utils.spec.ts index d4a204879..9a87e1d0b 100644 --- a/src/portal/src/app/shared/units/utils.spec.ts +++ b/src/portal/src/app/shared/units/utils.spec.ts @@ -2,6 +2,7 @@ import { DEFAULT_PAGE_SIZE, delUrlParam, durationStr, + getHiddenArrayFromLocalStorage, getPageSizeFromLocalStorage, getQueryString, getSizeNumber, @@ -9,6 +10,7 @@ import { getSortingString, isSameArrayValue, isSameObject, + setHiddenArrayToLocalStorage, setPageSizeToLocalStorage, } from './utils'; import { ClrDatagridStateInterface } from '@clr/angular'; @@ -127,4 +129,31 @@ describe('functions in utils.ts should work', () => { expect(durationStr(61111)).toEqual('1min 1sec'); expect(durationStr(3661111)).toEqual('1hrs 1min 1sec'); }); + + it('functions getHiddenArrayFromLocalStorage() and setHiddenArrayToLocalStorage() should work', () => { + let store = {}; + spyOn(localStorage, 'getItem').and.callFake(key => { + return store[key]; + }); + spyOn(localStorage, 'setItem').and.callFake((key, value) => { + return (store[key] = value + ''); + }); + spyOn(localStorage, 'clear').and.callFake(() => { + store = {}; + }); + expect(getHiddenArrayFromLocalStorage(null, [])).toEqual([]); + expect(getHiddenArrayFromLocalStorage('test', [true])).toEqual([true]); + expect(getHiddenArrayFromLocalStorage('test1', [])).toEqual([]); + setHiddenArrayToLocalStorage('test1', [false, false, false]); + expect(getHiddenArrayFromLocalStorage('test1', [false])).toEqual([ + false, + false, + false, + ]); + setHiddenArrayToLocalStorage('test1', [true, true]); + expect(getHiddenArrayFromLocalStorage('test1', [false])).toEqual([ + true, + true, + ]); + }); }); diff --git a/src/portal/src/app/shared/units/utils.ts b/src/portal/src/app/shared/units/utils.ts index 702cb9be3..516f8a837 100644 --- a/src/portal/src/app/shared/units/utils.ts +++ b/src/portal/src/app/shared/units/utils.ts @@ -888,6 +888,11 @@ export function delUrlParam(url: string, key: string): string { const PAGE_SIZE_MAP_KEY: string = 'pageSizeMap'; +interface DataGridMetadata { + pageSize?: number; + columnHiddenArray?: boolean[]; +} + /** * Get the page size from the browser's localStorage * @param key @@ -901,10 +906,12 @@ export function getPageSizeFromLocalStorage( initialSize = DEFAULT_PAGE_SIZE; } if (localStorage && key && localStorage.getItem(PAGE_SIZE_MAP_KEY)) { - const pageSizeMap: { - [k: string]: number; + const metadataMap: { + [k: string]: DataGridMetadata; } = JSON.parse(localStorage.getItem(PAGE_SIZE_MAP_KEY)); - return pageSizeMap[key] ? pageSizeMap[key] : initialSize; + return metadataMap[key]?.pageSize + ? metadataMap[key]?.pageSize + : initialSize; } return initialSize; } @@ -920,11 +927,62 @@ export function setPageSizeToLocalStorage(key: string, pageSize: number) { // if first set localStorage.setItem(PAGE_SIZE_MAP_KEY, '{}'); } - const pageSizeMap: { - [k: string]: number; + const metadataMap: { + [k: string]: DataGridMetadata; } = JSON.parse(localStorage.getItem(PAGE_SIZE_MAP_KEY)); - pageSizeMap[key] = pageSize; - localStorage.setItem(PAGE_SIZE_MAP_KEY, JSON.stringify(pageSizeMap)); + if (!isObject(metadataMap[key])) { + metadataMap[key] = {}; + } + metadataMap[key].pageSize = pageSize; + localStorage.setItem(PAGE_SIZE_MAP_KEY, JSON.stringify(metadataMap)); + } +} + +/** + * Get the hidden array from the browser's localStorage + * @param key + * @param initialArray + */ +export function getHiddenArrayFromLocalStorage( + key: string, + initialArray: boolean[] +) { + if (!initialArray?.length) { + initialArray = []; + } + if (localStorage && key && localStorage.getItem(PAGE_SIZE_MAP_KEY)) { + const metadataMap: { + [k: string]: DataGridMetadata; + } = JSON.parse(localStorage.getItem(PAGE_SIZE_MAP_KEY)); + return metadataMap[key]?.columnHiddenArray + ? metadataMap[key]?.columnHiddenArray + : initialArray; + } + return initialArray; +} + +/** + * Set the hidden array to the browser's localStorage + * @param key + * @param hiddenArray + */ +export function setHiddenArrayToLocalStorage( + key: string, + hiddenArray: boolean[] +) { + if (localStorage && key && hiddenArray?.length) { + if (!localStorage.getItem(PAGE_SIZE_MAP_KEY)) { + // if first set + localStorage.setItem(PAGE_SIZE_MAP_KEY, '{}'); + } + const metadataMap: { + [k: string]: DataGridMetadata; + } = JSON.parse(localStorage.getItem(PAGE_SIZE_MAP_KEY)); + if (!isObject(metadataMap[key])) { + metadataMap[key] = {}; + } + metadataMap[key].columnHiddenArray = hiddenArray; + localStorage.setItem(PAGE_SIZE_MAP_KEY, JSON.stringify(metadataMap)); } }