mirror of
https://github.com/goharbor/harbor.git
synced 2025-03-02 10:41:59 +01:00
Remove helm chart UI (#18099)
1.Remove all helm chart v2 related code Signed-off-by: AllForNothing <sshijun@vmware.com>
This commit is contained in:
parent
9d30955607
commit
ff9dcd5483
@ -118,13 +118,6 @@ export class SignInComponent implements AfterViewChecked, OnInit {
|
||||
|
||||
// App title
|
||||
public get appTitle(): string {
|
||||
if (
|
||||
this.appConfigService.getConfig() &&
|
||||
this.appConfigService.getConfig().with_admiral
|
||||
) {
|
||||
return 'APP_TITLE.VIC';
|
||||
}
|
||||
|
||||
return 'APP_TITLE.VMW_HARBOR';
|
||||
}
|
||||
|
||||
|
@ -50,10 +50,6 @@ export class AppComponent {
|
||||
this.initLanguage();
|
||||
// Override page title
|
||||
let key: string = 'APP_TITLE.HARBOR';
|
||||
if (this.appConfigService.isIntegrationMode()) {
|
||||
key = 'APP_TITLE.REG';
|
||||
}
|
||||
|
||||
translate.get(key).subscribe((res: string) => {
|
||||
const customSkinData: CustomStyle =
|
||||
this.skinableConfig.getSkinConfig();
|
||||
|
@ -161,17 +161,6 @@ const routes: Routes = [
|
||||
projectResolver: ProjectRoutingResolver,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'projects/:id/helm-charts',
|
||||
canActivate: [MemberGuard],
|
||||
resolve: {
|
||||
projectResolver: ProjectRoutingResolver,
|
||||
},
|
||||
loadChildren: () =>
|
||||
import(
|
||||
'./project/helm-chart/helm-chart-detail/helm-chart-detail.module'
|
||||
).then(m => m.HelmChartListModule),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
@ -129,7 +129,6 @@
|
||||
{{ 'SIDE_NAV.DISTRIBUTIONS.NAME' | translate }}
|
||||
</a>
|
||||
<a
|
||||
*ngIf="!withAdmiral"
|
||||
clrVerticalNavLink
|
||||
routerLink="/harbor/labels"
|
||||
routerLinkActive="active">
|
||||
|
@ -242,9 +242,6 @@ export class HarborShellComponent implements OnInit, OnDestroy {
|
||||
this.session.getCurrentUser().has_admin_role
|
||||
);
|
||||
}
|
||||
public get withAdmiral(): boolean {
|
||||
return this.appConfigService.getConfig().with_admiral;
|
||||
}
|
||||
// Open modal dialog
|
||||
openModal(event: ModalEvent): void {
|
||||
switch (event.modalName) {
|
||||
|
@ -24,7 +24,7 @@
|
||||
type="button"
|
||||
routerLink="security"
|
||||
routerLinkActive="active">
|
||||
{{ 'HELM_CHART.SECURITY' | translate }}
|
||||
{{ 'CONFIG.SECURITY' | translate }}
|
||||
</button>
|
||||
</li>
|
||||
<li role="presentation" class="nav-item">
|
||||
|
@ -53,9 +53,6 @@
|
||||
<clr-dg-column>{{ 'PROJECT.ROLE' | translate }}</clr-dg-column>
|
||||
<clr-dg-column>{{ 'PROJECT.TYPE' | translate }}</clr-dg-column>
|
||||
<clr-dg-column>{{ 'PROJECT.REPO_COUNT' | translate }}</clr-dg-column>
|
||||
<clr-dg-column *ngIf="withChartMuseum">{{
|
||||
'PROJECT.CHART_COUNT' | translate
|
||||
}}</clr-dg-column>
|
||||
<clr-dg-column [clrDgSortBy]="'creation_time'">{{
|
||||
'PROJECT.CREATION_TIME' | translate
|
||||
}}</clr-dg-column>
|
||||
@ -83,7 +80,6 @@
|
||||
projectTypeMap[p.registry_id ? 1 : 0] | translate
|
||||
}}</clr-dg-cell>
|
||||
<clr-dg-cell>{{ p.repo_count }}</clr-dg-cell>
|
||||
<clr-dg-cell *ngIf="withChartMuseum">{{ p.chart_count }}</clr-dg-cell>
|
||||
<clr-dg-cell>{{
|
||||
p.creation_time | harborDatetime: 'short'
|
||||
}}</clr-dg-cell>
|
||||
|
@ -132,11 +132,6 @@ export class ListProjectComponent implements OnDestroy {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
get withChartMuseum(): boolean {
|
||||
return this.appConfigService.getConfig().with_chartmuseum;
|
||||
}
|
||||
|
||||
public get isSystemAdmin(): boolean {
|
||||
let account = this.session.getCurrentUser();
|
||||
return account != null && account.has_admin_role;
|
||||
|
@ -101,12 +101,10 @@ export class CreateEditEndpointComponent
|
||||
this.endpointService.getAdapters().subscribe(
|
||||
adapters => {
|
||||
this.adapterList = adapters || [];
|
||||
if (!this.appConfigService.getConfig().with_chartmuseum) {
|
||||
// disable helm-hub
|
||||
for (let i = 0; i < this.adapterList.length; i++) {
|
||||
if (this.adapterList[i] === HELM_HUB) {
|
||||
this.adapterList.splice(i, 1);
|
||||
}
|
||||
// disable helm-hub
|
||||
for (let i = 0; i < this.adapterList.length; i++) {
|
||||
if (this.adapterList[i] === HELM_HUB) {
|
||||
this.adapterList.splice(i, 1);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -246,12 +246,7 @@
|
||||
?.values
|
||||
"
|
||||
value="{{ value }}">
|
||||
{{ value
|
||||
}}{{
|
||||
value === 'chart'
|
||||
? ' (chartmuseum)'
|
||||
: ''
|
||||
}}
|
||||
{{ value }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
@ -610,7 +605,6 @@
|
||||
| translate
|
||||
}}
|
||||
</div>
|
||||
<div>{{ 'REPLICATION.NOTE' | translate }}</div>
|
||||
</clr-tooltip-content>
|
||||
</clr-tooltip>
|
||||
</div>
|
||||
|
@ -111,7 +111,6 @@ export class ReplicationComponent implements OnInit, OnDestroy {
|
||||
@Input() projectId: number | string;
|
||||
@Input() projectName: string;
|
||||
@Input() isSystemAdmin: boolean;
|
||||
@Input() withAdmiral: boolean;
|
||||
@Input() withReplicationJob: boolean;
|
||||
@Input() hasCreateReplicationPermission: boolean;
|
||||
@Input() hasUpdateReplicationPermission: boolean;
|
||||
|
@ -3,7 +3,6 @@
|
||||
<hbr-replication
|
||||
[withReplicationJob]="true"
|
||||
[isSystemAdmin]="isSystemAdmin"
|
||||
[withAdmiral]="withAdmiral"
|
||||
(goToRegistry)="goRegistry()"
|
||||
[hasCreateReplicationPermission]="true"
|
||||
[hasUpdateReplicationPermission]="true"
|
||||
|
@ -80,8 +80,4 @@ export class TotalReplicationPageComponent implements OnInit, OnDestroy {
|
||||
let account = this.session.getCurrentUser();
|
||||
return account != null && account.has_admin_role;
|
||||
}
|
||||
|
||||
get withAdmiral(): boolean {
|
||||
return this.appConfigService.getConfig().with_admiral;
|
||||
}
|
||||
}
|
||||
|
@ -28,8 +28,6 @@ export enum PermissionsKinds {
|
||||
|
||||
export enum Resource {
|
||||
REPO = 'repository',
|
||||
HELM_CHART = 'helm-chart',
|
||||
HELM_CHART_VERSION = 'helm-chart-version',
|
||||
ARTIFACT = 'artifact',
|
||||
}
|
||||
|
||||
@ -116,31 +114,6 @@ export const INITIAL_ACCESSES: FrontAccess[] = [
|
||||
action: 'stop',
|
||||
checked: true,
|
||||
},
|
||||
{
|
||||
resource: 'helm-chart',
|
||||
action: 'read',
|
||||
checked: true,
|
||||
},
|
||||
{
|
||||
resource: 'helm-chart-version',
|
||||
action: 'create',
|
||||
checked: true,
|
||||
},
|
||||
{
|
||||
resource: 'helm-chart-version',
|
||||
action: 'delete',
|
||||
checked: true,
|
||||
},
|
||||
{
|
||||
resource: 'helm-chart-version-label',
|
||||
action: 'create',
|
||||
checked: true,
|
||||
},
|
||||
{
|
||||
resource: 'helm-chart-version-label',
|
||||
action: 'delete',
|
||||
checked: true,
|
||||
},
|
||||
];
|
||||
|
||||
export const ACTION_RESOURCE_I18N_MAP = {
|
||||
@ -151,11 +124,8 @@ export const ACTION_RESOURCE_I18N_MAP = {
|
||||
delete: 'SYSTEM_ROBOT.DELETE',
|
||||
repository: 'SYSTEM_ROBOT.REPOSITORY',
|
||||
artifact: 'SYSTEM_ROBOT.ARTIFACT',
|
||||
'helm-chart': 'SYSTEM_ROBOT.HELM',
|
||||
'helm-chart-version': 'SYSTEM_ROBOT.HELM_VERSION',
|
||||
tag: 'REPLICATION.TAG',
|
||||
'artifact-label': 'SYSTEM_ROBOT.ARTIFACT_LABEL',
|
||||
'helm-chart-version-label': 'SYSTEM_ROBOT.HELM_LABEL',
|
||||
scan: 'SYSTEM_ROBOT.SCAN',
|
||||
'scanner-pull': 'SYSTEM_ROBOT.SCANNER_PULL',
|
||||
stop: 'SYSTEM_ROBOT.STOP',
|
||||
|
@ -1,18 +0,0 @@
|
||||
<div>
|
||||
<div class="breadcrumb">
|
||||
<span class="back-icon"><</span>
|
||||
<a (click)="gotoProjectList()">{{ 'SIDE_NAV.PROJECTS' | translate }}</a>
|
||||
<span class="back-icon"><</span>
|
||||
<a (click)="gotoChartList()">{{ projectName }}</a>
|
||||
<span class="back-icon"><</span>
|
||||
<a (click)="gotoChartVersion()">{{
|
||||
'HELM_CHART.CHARTVERSIONS' | translate
|
||||
}}</a>
|
||||
</div>
|
||||
<hbr-chart-detail
|
||||
[projectId]="projectId"
|
||||
[project]="project"
|
||||
[chartName]="chartName"
|
||||
[chartVersion]="chartVersion"
|
||||
[roleName]="roleName"></hbr-chart-detail>
|
||||
</div>
|
@ -1,16 +0,0 @@
|
||||
.breadcrumb a {
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
color: #007cbb;
|
||||
font-size: 16px;
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.breadcrumb {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.back-icon {
|
||||
color: #007cbb;
|
||||
font-size: 16px;
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { SessionService } from '../../../../shared/services/session.service';
|
||||
import { of } from 'rxjs';
|
||||
import { HelmChartDetailComponent } from './chart-detail.component';
|
||||
import { SharedTestingModule } from '../../../../shared/shared.module';
|
||||
|
||||
describe('ChartDetailComponent', () => {
|
||||
let component: HelmChartDetailComponent;
|
||||
let fixture: ComponentFixture<HelmChartDetailComponent>;
|
||||
let fakeRouter = null;
|
||||
let fakeSessionService = {
|
||||
getCurrentUser: function () {
|
||||
return { has_admin_role: true };
|
||||
},
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [HelmChartDetailComponent],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
imports: [SharedTestingModule],
|
||||
providers: [
|
||||
{
|
||||
provide: ActivatedRoute,
|
||||
useValue: {
|
||||
paramMap: of({ get: key => 'value' }),
|
||||
snapshot: {
|
||||
parent: {
|
||||
data: {
|
||||
projectResolver: {
|
||||
role_name: 'admin',
|
||||
},
|
||||
},
|
||||
params: { id: 1 },
|
||||
},
|
||||
params: {
|
||||
chart: 'chart',
|
||||
version: 1.0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{ provide: Router, useValue: fakeRouter },
|
||||
{ provide: SessionService, useValue: fakeSessionService },
|
||||
],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(HelmChartDetailComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -1,59 +0,0 @@
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Project } from '../../project';
|
||||
import { SessionService } from '../../../../shared/services/session.service';
|
||||
import { SessionUser } from '../../../../shared/entities/session-user';
|
||||
|
||||
@Component({
|
||||
selector: 'project-chart-detail',
|
||||
templateUrl: './chart-detail.component.html',
|
||||
styleUrls: ['./chart-detail.component.scss'],
|
||||
})
|
||||
export class HelmChartDetailComponent implements OnInit {
|
||||
projectId: number | string;
|
||||
project: Project;
|
||||
projectName: string;
|
||||
chartName: string;
|
||||
chartVersion: string;
|
||||
currentUser: SessionUser;
|
||||
hasProjectAdminRole: boolean;
|
||||
roleName: string;
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private session: SessionService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
// Get projectId from router-guard params snapshot.
|
||||
this.projectId = +this.route.snapshot.parent.params['id'];
|
||||
this.chartName = this.route.snapshot.params['chart'];
|
||||
this.chartVersion = this.route.snapshot.params['version'];
|
||||
// Get current user from registered resolver.
|
||||
this.currentUser = this.session.getCurrentUser();
|
||||
let resolverData = this.route.snapshot.parent.data;
|
||||
if (resolverData) {
|
||||
this.project = <Project>resolverData['projectResolver'];
|
||||
this.roleName = this.project.role_name;
|
||||
this.projectName = this.project.name;
|
||||
this.hasProjectAdminRole = this.project.has_project_admin_role;
|
||||
}
|
||||
}
|
||||
|
||||
gotoProjectList() {
|
||||
this.router.navigateByUrl('/harbor/projects');
|
||||
}
|
||||
|
||||
gotoChartList() {
|
||||
this.router.navigateByUrl(
|
||||
`/harbor/projects/${this.projectId}/helm-charts`
|
||||
);
|
||||
}
|
||||
|
||||
gotoChartVersion() {
|
||||
this.router.navigateByUrl(
|
||||
`/harbor/projects/${this.projectId}/helm-charts/${this.chartName}/versions`
|
||||
);
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
<div class="row flex-items-xs-center dep-container">
|
||||
<div class="col-md-12">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="left">{{ 'HELM_CHART.NAME' | translate }}</th>
|
||||
<th class="left">{{ 'HELM_CHART.VERSION' | translate }}</th>
|
||||
<th class="left">{{ 'HELM_CHART.REPO' | translate }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let dep of dependencies">
|
||||
<td class="left">{{ dep.name }}</td>
|
||||
<td class="left">{{ dep.version }}</td>
|
||||
<td class="left">
|
||||
<a href="{{ dep.repository }}">{{ dep.repository }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
@ -1,3 +0,0 @@
|
||||
.dep-container {
|
||||
margin-top: 30px;
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ChartDetailDependencyComponent } from './chart-detail-dependency.component';
|
||||
import { SharedTestingModule } from '../../../../../shared/shared.module';
|
||||
|
||||
describe('ChartDetailDependencyComponent', () => {
|
||||
let component: ChartDetailDependencyComponent;
|
||||
let fixture: ComponentFixture<ChartDetailDependencyComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [SharedTestingModule],
|
||||
declarations: [ChartDetailDependencyComponent],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ChartDetailDependencyComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -1,15 +0,0 @@
|
||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
||||
|
||||
import { HelmChartDependency } from '../helm-chart.interface.service';
|
||||
|
||||
@Component({
|
||||
selector: 'hbr-chart-detail-dependency',
|
||||
templateUrl: './chart-detail-dependency.component.html',
|
||||
styleUrls: ['./chart-detail-dependency.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ChartDetailDependencyComponent {
|
||||
@Input() dependencies: HelmChartDependency;
|
||||
|
||||
constructor() {}
|
||||
}
|
@ -1,224 +0,0 @@
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<p>{{ summary.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row content-wrapper">
|
||||
<div class="col-md-8 md-container pl-1">
|
||||
<div
|
||||
*ngIf="readme"
|
||||
class="md-div"
|
||||
[innerHTML]="readme | markdown"></div>
|
||||
<div *ngIf="!readme">{{ 'HELM_CHART.NO_README' | translate }}</div>
|
||||
</div>
|
||||
<div class="col-md-4 summary-container mt-1">
|
||||
<div class="col-md-12 content-group">
|
||||
<div>
|
||||
<label>{{ 'HELM_CHART.OVERVIEW' | translate }}</label>
|
||||
</div>
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="left">
|
||||
{{ 'HELM_CHART.HOME' | translate }}
|
||||
</td>
|
||||
<td class="left text-wrapper">
|
||||
<a href="{{ summary.home }}">{{ summary.home }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr *ngFor="let src of summary.sources; let i = index">
|
||||
<td class="left" *ngIf="i === 0">
|
||||
{{ 'HELM_CHART.SRC_REPO' | translate }}
|
||||
</td>
|
||||
<td class="left" *ngIf="i !== 0"></td>
|
||||
<td class="left text-wrapper">
|
||||
<a href="{{ src }}">{{ src }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="left">
|
||||
{{ 'HELM_CHART.CREATED' | translate }}
|
||||
</td>
|
||||
<td class="left">
|
||||
{{ summary.created | harborDatetime }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr
|
||||
*ngFor="
|
||||
let maintainer of summary.maintainers;
|
||||
let i = index
|
||||
">
|
||||
<td class="left" *ngIf="i === 0">
|
||||
{{ 'HELM_CHART.MAINTAINERS' | translate }}
|
||||
</td>
|
||||
<td class="left" *ngIf="i !== 0"></td>
|
||||
<td class="left">
|
||||
<a href="mailto:{{ maintainer.email }}">{{
|
||||
maintainer.name
|
||||
}}</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="left">
|
||||
{{ 'HELM_CHART.APP_VERSION' | translate }}
|
||||
</td>
|
||||
<td class="left">{{ summary.appVersion }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-md-12 content-group">
|
||||
<div>
|
||||
<label>{{ 'HELM_CHART.COMMAND' | translate }}</label>
|
||||
</div>
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="left cmd-title">
|
||||
{{ 'HELM_CHART.ADD_REPO' | translate }}
|
||||
</td>
|
||||
<td class="left cmd-content">
|
||||
<input
|
||||
class="cmd-content clr-input"
|
||||
type="text"
|
||||
[(ngModel)]="addCMD"
|
||||
#addCMDInput
|
||||
readonly />
|
||||
</td>
|
||||
<td class="left">
|
||||
<span>
|
||||
<clr-icon
|
||||
shape="copy"
|
||||
size="24"
|
||||
[class.is-success]="isCopied('add')"
|
||||
[ngxClipboard]="addCMDInput"
|
||||
(cbOnSuccess)="
|
||||
onCopySuccess($event, 'add')
|
||||
"></clr-icon>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="left cmd-title">
|
||||
{{ 'HELM_CHART.INSTALL_CHART' | translate }}
|
||||
</td>
|
||||
<td class="left">
|
||||
<input
|
||||
class="cmd-content clr-input"
|
||||
type="text"
|
||||
[(ngModel)]="installCMD"
|
||||
#installCMDInput
|
||||
readonly />
|
||||
</td>
|
||||
<td class="left">
|
||||
<span>
|
||||
<clr-icon
|
||||
shape="copy"
|
||||
size="24"
|
||||
[class.is-success]="isCopied('install')"
|
||||
[ngxClipboard]="installCMDInput"
|
||||
(cbOnSuccess)="
|
||||
onCopySuccess($event, 'install')
|
||||
"></clr-icon>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr *ngIf="prov_ready">
|
||||
<td class="left cmd-title">
|
||||
{{ 'HELM_CHART.VERIFY_CHART' | translate }}
|
||||
</td>
|
||||
<td class="left">
|
||||
<input
|
||||
class="cmd-content clr-input"
|
||||
type="text"
|
||||
[(ngModel)]="verifyCMD"
|
||||
#verifyCMDInput
|
||||
readonly />
|
||||
</td>
|
||||
<td class="left">
|
||||
<span>
|
||||
<clr-icon
|
||||
shape="copy"
|
||||
size="24"
|
||||
[class.is-success]="isCopied('verify')"
|
||||
[ngxClipboard]="verifyCMDInput"
|
||||
(cbOnSuccess)="
|
||||
onCopySuccess($event, 'verify')
|
||||
"></clr-icon>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="col-md-12 content-group">
|
||||
<div>
|
||||
<label>{{ 'HELM_CHART.SECURITY' | translate }}</label>
|
||||
</div>
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="left">
|
||||
{{ 'HELM_CHART.PROV_FILE' | translate }}
|
||||
</td>
|
||||
<div
|
||||
*ngIf="
|
||||
prov_ready;
|
||||
then signedContent;
|
||||
else unsignedContent
|
||||
"></div>
|
||||
<ng-template #signedContent>
|
||||
<td class="left">
|
||||
<span class="content-icon">
|
||||
<clr-icon
|
||||
shape="shield-check"
|
||||
class="is-success"></clr-icon> </span
|
||||
> <a
|
||||
href="javascript:void(0)"
|
||||
(click)="downloadChart()"
|
||||
>{{ 'HELM_CHART.READY' | translate }}</a
|
||||
>
|
||||
</td>
|
||||
</ng-template>
|
||||
<ng-template #unsignedContent>
|
||||
<td class="left">
|
||||
<span class="content-icon">
|
||||
<clr-icon
|
||||
shape="shield-x"
|
||||
class="is-error"></clr-icon> </span
|
||||
> {{ 'HELM_CHART.NOT_READY' | translate }}
|
||||
</td>
|
||||
</ng-template>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="col-md-12 content-group">
|
||||
<div>
|
||||
<label>{{ 'HELM_CHART.LABELS' | translate }}</label>
|
||||
</div>
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="left">
|
||||
{{ 'HELM_CHART.LABELS' | translate }}
|
||||
</td>
|
||||
<td class="left">{{ labels?.length }}</td>
|
||||
</tr>
|
||||
<tr *ngIf="labels?.length > 0">
|
||||
<td></td>
|
||||
<td class="left">
|
||||
<hbr-label-piece
|
||||
*ngFor="let label of labels"
|
||||
[label]="label"
|
||||
[labelWidth]="90">
|
||||
</hbr-label-piece>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,45 +0,0 @@
|
||||
.content-wrapper {
|
||||
margin-top: 20px;
|
||||
padding: 0 0 0 15px;
|
||||
|
||||
.md-container {
|
||||
border: solid 1px;
|
||||
}
|
||||
|
||||
.summary-container {
|
||||
padding: 0;
|
||||
|
||||
table {
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.content-group {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.content-icon {
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.text-wrapper {
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
|
||||
.cmd-title {
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.cmd-content {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin align-text-mixin($values...) {
|
||||
@each $var in $values {
|
||||
&[align="$var"] {
|
||||
text-align: $var;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { ChartDetailSummaryComponent } from './chart-detail-summary.component';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA, SecurityContext } from '@angular/core';
|
||||
import { MarkdownModule, MarkedOptions } from 'ngx-markdown';
|
||||
import { HelmChartService } from '../helm-chart.service';
|
||||
import { ErrorHandler } from '../../../../../shared/units/error-handler';
|
||||
import { MessageHandlerService } from '../../../../../shared/services/message-handler.service';
|
||||
import { SharedTestingModule } from '../../../../../shared/shared.module';
|
||||
|
||||
describe('ChartDetailSummaryComponent', () => {
|
||||
let component: ChartDetailSummaryComponent;
|
||||
let fixture: ComponentFixture<ChartDetailSummaryComponent>;
|
||||
const mockHelmChartService = {
|
||||
downloadChart: function () {},
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
SharedTestingModule,
|
||||
MarkdownModule.forRoot({ sanitize: SecurityContext.HTML }),
|
||||
],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
declarations: [ChartDetailSummaryComponent],
|
||||
providers: [
|
||||
TranslateService,
|
||||
{ provide: MarkedOptions, useValue: {} },
|
||||
{ provide: ErrorHandler, useValue: MessageHandlerService },
|
||||
{ provide: HelmChartService, useValue: mockHelmChartService },
|
||||
],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ChartDetailSummaryComponent);
|
||||
component = fixture.componentInstance;
|
||||
component.summary = {
|
||||
name: 'string',
|
||||
home: 'string',
|
||||
sources: [],
|
||||
version: 'string',
|
||||
description: 'string',
|
||||
keywords: [],
|
||||
maintainers: [],
|
||||
engine: 'string',
|
||||
icon: 'string',
|
||||
appVersion: 'string',
|
||||
urls: [],
|
||||
created: new Date().toDateString(),
|
||||
digest: 'string',
|
||||
};
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -1,87 +0,0 @@
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
Input,
|
||||
OnInit,
|
||||
} from '@angular/core';
|
||||
import {
|
||||
HelmChartMetaData,
|
||||
HelmChartSecurity,
|
||||
} from '../helm-chart.interface.service';
|
||||
import { HelmChartService } from '../helm-chart.service';
|
||||
import { Label } from '../../../../../shared/services';
|
||||
import { ErrorHandler } from '../../../../../shared/units/error-handler';
|
||||
import { downloadFile } from '../../../../../shared/units/utils';
|
||||
|
||||
@Component({
|
||||
selector: 'hbr-chart-detail-summary',
|
||||
templateUrl: './chart-detail-summary.component.html',
|
||||
styleUrls: ['./chart-detail-summary.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ChartDetailSummaryComponent implements OnInit {
|
||||
@Input() summary: HelmChartMetaData;
|
||||
@Input() security: HelmChartSecurity;
|
||||
@Input() repoURL: string;
|
||||
@Input() projectName: string;
|
||||
@Input() chartName: string;
|
||||
@Input() chartVersion: string;
|
||||
@Input() readme: string;
|
||||
@Input() labels: Label[];
|
||||
|
||||
copiedCMD = '';
|
||||
addCMD: string;
|
||||
installCMD: string;
|
||||
verifyCMD: string;
|
||||
|
||||
constructor(
|
||||
private errorHandler: ErrorHandler,
|
||||
private helmChartService: HelmChartService
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.addCMD = `helm repo add --ca-file <ca file> --cert-file <cert file> --key-file <key file> \
|
||||
--username <username> --password <password> <repo name> ${this.repoURL}/chartrepo/${this.projectName}`;
|
||||
this.installCMD = `helm install --ca-file <ca file> --cert-file <cert file> --key-file <key file> \
|
||||
--username=<username> --password=<password> --version ${this.chartVersion} <repo name>/${this.chartName}`;
|
||||
this.verifyCMD = `helm verify --keyring <key path> ${this.chartName}-${this.chartVersion}.tgz`;
|
||||
}
|
||||
|
||||
isCopied(cmd: string) {
|
||||
return this.copiedCMD === cmd;
|
||||
}
|
||||
|
||||
onCopySuccess(e: Event, cmd: string) {
|
||||
this.copiedCMD = cmd;
|
||||
}
|
||||
|
||||
public get prov_ready() {
|
||||
return (
|
||||
this.security &&
|
||||
this.security.signature &&
|
||||
this.security.signature.signed
|
||||
);
|
||||
}
|
||||
|
||||
downloadChart() {
|
||||
if (
|
||||
!this.summary ||
|
||||
!this.summary.urls ||
|
||||
this.summary.urls.length < 1
|
||||
) {
|
||||
return;
|
||||
}
|
||||
let filename = `${this.summary.urls[0]}.prov`;
|
||||
|
||||
this.helmChartService
|
||||
.downloadChart(this.projectName, filename)
|
||||
.subscribe(
|
||||
res => {
|
||||
downloadFile(res);
|
||||
},
|
||||
error => {
|
||||
this.errorHandler.error(error);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
<div class="row flex-items-xs-between values-header">
|
||||
<div *ngIf="valueMode" class="title-container">
|
||||
<label>{{ 'HELM_CHART.SHOW_KV' | translate }}</label>
|
||||
</div>
|
||||
<div *ngIf="!valueMode" class="title-container">
|
||||
<label>{{ 'HELM_CHART.SHOW_YAML' | translate }}</label>
|
||||
</div>
|
||||
<div class="switch-container">
|
||||
<span
|
||||
class="card-btn"
|
||||
(click)="showYamlFile(false)"
|
||||
(mouseenter)="mouseEnter('value')"
|
||||
(mouseleave)="mouseLeave('value')">
|
||||
<clr-icon
|
||||
size="24"
|
||||
shape="view-list"
|
||||
title="list values"
|
||||
[ngClass]="{
|
||||
'is-highlight': isValueMode || isHovering('value')
|
||||
}"></clr-icon>
|
||||
</span>
|
||||
<span
|
||||
class="list-btn"
|
||||
(click)="showYamlFile(true)"
|
||||
(mouseenter)="mouseEnter('yaml')"
|
||||
(mouseleave)="mouseLeave('yaml')">
|
||||
<clr-icon
|
||||
size="24"
|
||||
shape="file"
|
||||
title="yaml file"
|
||||
[ngClass]="{
|
||||
'is-highlight': !isValueMode || isHovering('yaml')
|
||||
}"></clr-icon>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row value-container">
|
||||
<div class="col-xs-8" *ngIf="valueMode">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr *ngFor="let key of objKeys(values)">
|
||||
<td class="left">{{ key }}</td>
|
||||
<td class="left">{{ values[key] }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-xs-8" *ngIf="!valueMode">
|
||||
<div
|
||||
class="yaml-container"
|
||||
[innerHTML]="yaml | language: 'yaml' | markdown"></div>
|
||||
</div>
|
||||
</div>
|
@ -1,24 +0,0 @@
|
||||
.value-container {
|
||||
::ng-deep pre {
|
||||
min-height: fit-content;
|
||||
max-height: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.values-header {
|
||||
margin-top: 12px;
|
||||
|
||||
.title-container {
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.switch-container {
|
||||
margin-right: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
/* stylelint-disable */
|
||||
pre {
|
||||
max-height: max-content;
|
||||
padding-left: 21px;
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { TranslateModule, TranslateService } from '@ngx-translate/core';
|
||||
import { ChartDetailValueComponent } from './chart-detail-value.component';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA, SecurityContext } from '@angular/core';
|
||||
import { ClarityModule } from '@clr/angular';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { MarkdownModule, MarkedOptions } from 'ngx-markdown';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
|
||||
describe('ChartDetailValueComponent', () => {
|
||||
let component: ChartDetailValueComponent;
|
||||
let fixture: ComponentFixture<ChartDetailValueComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [
|
||||
TranslateModule.forRoot(),
|
||||
ClarityModule,
|
||||
FormsModule,
|
||||
BrowserModule,
|
||||
MarkdownModule.forRoot({ sanitize: SecurityContext.HTML }),
|
||||
],
|
||||
declarations: [ChartDetailValueComponent],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
providers: [
|
||||
TranslateService,
|
||||
{ provide: MarkedOptions, useValue: {} },
|
||||
],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ChartDetailValueComponent);
|
||||
component = fixture.componentInstance;
|
||||
component.yaml = 'rfrf';
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -1,53 +0,0 @@
|
||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'hbr-chart-detail-value',
|
||||
templateUrl: './chart-detail-value.component.html',
|
||||
styleUrls: ['./chart-detail-value.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ChartDetailValueComponent {
|
||||
@Input() values;
|
||||
@Input() yaml;
|
||||
|
||||
// Default set to yaml file
|
||||
valueMode = false;
|
||||
valueHover = false;
|
||||
yamlHover = true;
|
||||
|
||||
objKeys = Object.keys;
|
||||
|
||||
constructor() {}
|
||||
|
||||
public get isValueMode() {
|
||||
return this.valueMode;
|
||||
}
|
||||
|
||||
isHovering(view: string) {
|
||||
if (view === 'value') {
|
||||
return this.valueHover;
|
||||
} else {
|
||||
return this.yamlHover;
|
||||
}
|
||||
}
|
||||
|
||||
showYamlFile(showYaml: boolean) {
|
||||
this.valueMode = !showYaml;
|
||||
}
|
||||
|
||||
mouseEnter(mode: string) {
|
||||
if (mode === 'value') {
|
||||
this.valueHover = true;
|
||||
} else {
|
||||
this.yamlHover = true;
|
||||
}
|
||||
}
|
||||
|
||||
mouseLeave(mode: string) {
|
||||
if (mode === 'value') {
|
||||
this.valueHover = false;
|
||||
} else {
|
||||
this.yamlHover = false;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
<div>
|
||||
<div class="flex-container">
|
||||
<div class="title-container">
|
||||
<div class="chart-name">
|
||||
{{ chartNameWithVersion | translate }}
|
||||
</div>
|
||||
<div>
|
||||
{{ roleName | translate }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<button class="btn btn-secondary" (click)="downloadChart()">
|
||||
{{ 'HELM_CHART.DOWNLOAD' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<span *ngIf="loading" class="spinner spinner-lg detail-loading">
|
||||
Loading...
|
||||
</span>
|
||||
<div *ngIf="!loading && isChartExist">
|
||||
<clr-tabs>
|
||||
<clr-tab>
|
||||
<button clrTabLink id="summary-link">
|
||||
{{ 'HELM_CHART.SUMMARY' | translate }}
|
||||
</button>
|
||||
<clr-tab-content id="summary-content" *clrIfActive>
|
||||
<hbr-chart-detail-summary
|
||||
[summary]="chartDetail.metadata"
|
||||
[chartName]="chartName"
|
||||
[repoURL]="repoURL"
|
||||
[projectName]="project.name"
|
||||
[chartVersion]="chartVersion"
|
||||
[security]="chartDetail.security"
|
||||
[readme]="chartDetail.files['README.md']"
|
||||
[labels]="
|
||||
chartDetail.labels
|
||||
"></hbr-chart-detail-summary>
|
||||
</clr-tab-content>
|
||||
</clr-tab>
|
||||
<clr-tab>
|
||||
<button clrTabLink id="depend-link">
|
||||
{{ 'HELM_CHART.DEPENDENCIES' | translate }}
|
||||
</button>
|
||||
<clr-tab-content id="depend-content">
|
||||
<hbr-chart-detail-dependency
|
||||
[dependencies]="
|
||||
chartDetail.dependencies
|
||||
"></hbr-chart-detail-dependency>
|
||||
</clr-tab-content>
|
||||
</clr-tab>
|
||||
<clr-tab>
|
||||
<button clrTabLink id="value-link">
|
||||
{{ 'HELM_CHART.VALUES' | translate }}
|
||||
</button>
|
||||
<clr-tab-content id="value-content">
|
||||
<hbr-chart-detail-value
|
||||
[values]="chartDetail.values"
|
||||
[yaml]="
|
||||
chartDetail.files['values.yaml']
|
||||
"></hbr-chart-detail-value>
|
||||
</clr-tab-content>
|
||||
</clr-tab>
|
||||
</clr-tabs>
|
||||
</div>
|
||||
<div *ngIf="!loading && !isChartExist">
|
||||
<h6>{{ 'HELM_CHART.NO_DETAIL' | translate }}</h6>
|
||||
</div>
|
||||
</div>
|
@ -1,28 +0,0 @@
|
||||
@import "../../../../../shared/mixin";
|
||||
|
||||
.title-container {
|
||||
display: flex;
|
||||
|
||||
.chart-name {
|
||||
border-right: 1px solid gray;
|
||||
font-size: 27px;
|
||||
font-weight: normal;
|
||||
padding-right: 9px;
|
||||
margin-right: 9px;
|
||||
}
|
||||
}
|
||||
|
||||
.detail-loading {
|
||||
@include absolute-center;
|
||||
}
|
||||
|
||||
.flex-container {
|
||||
display: flex;
|
||||
-webkit-display:flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.title-container {
|
||||
display: flex;
|
||||
align-items:center;
|
||||
}
|
||||
}
|
@ -1,143 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { TranslateModule, TranslateService } from '@ngx-translate/core';
|
||||
import { ChartDetailComponent } from './chart-detail.component';
|
||||
import { ClarityModule } from '@clr/angular';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||
import { HelmChartService } from '../helm-chart.service';
|
||||
import { of } from 'rxjs';
|
||||
import { ErrorHandler } from '../../../../../shared/units/error-handler';
|
||||
import { SystemInfoService } from '../../../../../shared/services';
|
||||
|
||||
describe('ChartDetailComponent', () => {
|
||||
let component: ChartDetailComponent;
|
||||
let fixture: ComponentFixture<ChartDetailComponent>;
|
||||
const mockErrorHandler = {
|
||||
error: function () {},
|
||||
};
|
||||
const mockSystemInfoService = {
|
||||
getSystemInfo: function () {
|
||||
return of({
|
||||
with_notary: false,
|
||||
with_admiral: false,
|
||||
admiral_endpoint: '',
|
||||
auth_mode: 'oidc_auth',
|
||||
registry_url: 'nightly-oidc.harbor.io',
|
||||
external_url: 'https://nightly-oidc.harbor.io',
|
||||
project_creation_restriction: 'everyone',
|
||||
self_registration: false,
|
||||
has_ca_root: false,
|
||||
harbor_version: 'dev',
|
||||
registry_storage_provider_name: 'filesystem',
|
||||
read_only: false,
|
||||
with_chartmuseum: true,
|
||||
notification_enable: true,
|
||||
});
|
||||
},
|
||||
};
|
||||
const mockHelmChartService = {
|
||||
getChartDetail: function () {
|
||||
return of({
|
||||
metadata: {
|
||||
name: 'harbor',
|
||||
home: 'https://github.com/vmware/harbor',
|
||||
sources: [
|
||||
'https://github.com/vmware/harbor/tree/master/contrib/helm/harbor',
|
||||
],
|
||||
version: '0.2.0',
|
||||
description: 'Ane',
|
||||
keywords: ['vmware', 'docker', 'registry', 'harbor'],
|
||||
maintainers: [
|
||||
{
|
||||
name: 'Jessde Hu',
|
||||
email: 'huh@qq.com',
|
||||
},
|
||||
{
|
||||
name: 'paulczar',
|
||||
email: 'username@qq.com',
|
||||
},
|
||||
],
|
||||
engine: '',
|
||||
icon: 'ht',
|
||||
appVersion: '1.5.0',
|
||||
urls: [''],
|
||||
created: '201940492141Z',
|
||||
digest: '',
|
||||
},
|
||||
dependencies: [
|
||||
{
|
||||
name: 'redis',
|
||||
version: '3.2.5',
|
||||
repository: '',
|
||||
},
|
||||
],
|
||||
values: {
|
||||
'adminserver.image.pullPolicy': 'IfNotPresent',
|
||||
},
|
||||
files: {
|
||||
'README.md': '',
|
||||
'values.yaml': '',
|
||||
},
|
||||
security: {
|
||||
signature: {
|
||||
signed: false,
|
||||
prov_file: '',
|
||||
},
|
||||
},
|
||||
labels: [],
|
||||
});
|
||||
},
|
||||
downloadChart: function () {},
|
||||
};
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [TranslateModule.forRoot(), ClarityModule, FormsModule],
|
||||
declarations: [ChartDetailComponent],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
providers: [
|
||||
TranslateService,
|
||||
{ provide: ErrorHandler, useValue: mockErrorHandler },
|
||||
{ provide: SystemInfoService, useValue: mockSystemInfoService },
|
||||
{ provide: HelmChartService, useValue: mockHelmChartService },
|
||||
],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ChartDetailComponent);
|
||||
component = fixture.componentInstance;
|
||||
component.chartName = 'chart';
|
||||
component.chartVersion = 'chart-version';
|
||||
component.project = {
|
||||
project_id: 1,
|
||||
owner_id: 1,
|
||||
name: 'library',
|
||||
creation_time: new Date(),
|
||||
creation_time_str: '123',
|
||||
update_time: new Date(),
|
||||
deleted: 1,
|
||||
owner_name: '',
|
||||
togglable: true,
|
||||
current_user_role_id: 1,
|
||||
has_project_admin_role: true,
|
||||
is_member: true,
|
||||
role_name: 'maintainer',
|
||||
repo_count: 0,
|
||||
chart_count: 1,
|
||||
registry_id: 0,
|
||||
metadata: {
|
||||
public: 'true',
|
||||
enable_content_trust: 'string',
|
||||
prevent_vul: 'string',
|
||||
severity: 'string',
|
||||
auto_scan: true,
|
||||
retention_id: 1,
|
||||
},
|
||||
};
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -1,109 +0,0 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
|
||||
import { Project } from '../../../project';
|
||||
import { HelmChartService } from '../helm-chart.service';
|
||||
import { HelmChartDetail } from '../helm-chart.interface.service';
|
||||
import { finalize } from 'rxjs/operators';
|
||||
import { SystemInfo, SystemInfoService } from '../../../../../shared/services';
|
||||
import { ErrorHandler } from '../../../../../shared/units/error-handler';
|
||||
import { downloadFile } from '../../../../../shared/units/utils';
|
||||
|
||||
@Component({
|
||||
selector: 'hbr-chart-detail',
|
||||
templateUrl: './chart-detail.component.html',
|
||||
styleUrls: ['./chart-detail.component.scss'],
|
||||
})
|
||||
export class ChartDetailComponent implements OnInit {
|
||||
@Input() projectId: number;
|
||||
@Input() project: Project;
|
||||
@Input() chartName: string;
|
||||
@Input() chartVersion: string;
|
||||
@Input() roleName: string;
|
||||
@Input() hasSignedIn: boolean;
|
||||
@Input() hasProjectAdminRole: boolean;
|
||||
|
||||
loading = true;
|
||||
isMember = false;
|
||||
chartDetail: HelmChartDetail;
|
||||
systemInfo: SystemInfo;
|
||||
|
||||
repoURL = '';
|
||||
|
||||
constructor(
|
||||
private errorHandler: ErrorHandler,
|
||||
private systemInfoService: SystemInfoService,
|
||||
private helmChartService: HelmChartService
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.systemInfoService.getSystemInfo().subscribe(
|
||||
systemInfo => {
|
||||
this.systemInfo = systemInfo;
|
||||
if (this.systemInfo.external_url) {
|
||||
this.repoURL = `${this.systemInfo.external_url}`;
|
||||
} else {
|
||||
let scheme = 'http://';
|
||||
if (this.systemInfo.has_ca_root) {
|
||||
scheme = 'https://';
|
||||
}
|
||||
this.repoURL = `${scheme}${this.systemInfo.registry_url}`;
|
||||
}
|
||||
},
|
||||
error => this.errorHandler.error(error)
|
||||
);
|
||||
this.refresh();
|
||||
}
|
||||
public get chartNameWithVersion() {
|
||||
return `${this.chartName}:${this.chartVersion}`;
|
||||
}
|
||||
|
||||
public get isChartExist() {
|
||||
return !!this.chartDetail;
|
||||
}
|
||||
|
||||
refresh() {
|
||||
this.loading = true;
|
||||
this.helmChartService
|
||||
.getChartDetail(
|
||||
this.project.name,
|
||||
this.chartName,
|
||||
this.chartVersion
|
||||
)
|
||||
.pipe(
|
||||
finalize(() => {
|
||||
this.loading = false;
|
||||
})
|
||||
)
|
||||
.subscribe(
|
||||
chartDetail => {
|
||||
this.chartDetail = chartDetail;
|
||||
},
|
||||
err => {
|
||||
this.errorHandler.error(err);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
downloadChart() {
|
||||
if (
|
||||
!this.chartDetail ||
|
||||
!this.chartDetail.metadata ||
|
||||
!this.chartDetail.metadata.urls ||
|
||||
this.chartDetail.metadata.urls.length < 1
|
||||
) {
|
||||
return;
|
||||
}
|
||||
let filename = this.chartDetail.metadata.urls[0];
|
||||
|
||||
this.helmChartService
|
||||
.downloadChart(this.project.name, filename)
|
||||
.subscribe(
|
||||
res => {
|
||||
downloadFile(res);
|
||||
},
|
||||
error => {
|
||||
this.errorHandler.error(error);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
// Copyright Project Harbor Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// 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 { NgModule } from '@angular/core';
|
||||
import { LabelFilterComponent } from './label-filter/label-filter.component';
|
||||
import { LabelMarkerComponent } from './label-marker/label-marker.component';
|
||||
import { ListChartVersionsComponent } from './list-chart-versions/list-chart-versions.component';
|
||||
import { ChartVersionComponent } from './list-chart-versions/helm-chart-versions-detail/helm-chart-version.component';
|
||||
import { ChartDetailDependencyComponent } from './chart-detail/chart-detail-dependency.component';
|
||||
import { ChartDetailSummaryComponent } from './chart-detail/chart-detail-summary.component';
|
||||
import { ChartDetailValueComponent } from './chart-detail/chart-detail-value.component';
|
||||
import { ChartDetailComponent } from './chart-detail/chart-detail.component';
|
||||
import { HelmChartDetailComponent } from './chart-detail.component';
|
||||
import { SharedModule } from '../../../../shared/shared.module';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: ':chart/versions',
|
||||
component: ListChartVersionsComponent,
|
||||
},
|
||||
{
|
||||
path: ':chart/versions/:version',
|
||||
component: HelmChartDetailComponent,
|
||||
},
|
||||
];
|
||||
@NgModule({
|
||||
imports: [SharedModule, RouterModule.forChild(routes)],
|
||||
declarations: [
|
||||
LabelFilterComponent,
|
||||
LabelMarkerComponent,
|
||||
ListChartVersionsComponent,
|
||||
ChartVersionComponent,
|
||||
ChartDetailDependencyComponent,
|
||||
ChartDetailSummaryComponent,
|
||||
ChartDetailValueComponent,
|
||||
ChartDetailComponent,
|
||||
HelmChartDetailComponent,
|
||||
],
|
||||
})
|
||||
export class HelmChartListModule {}
|
@ -1,89 +0,0 @@
|
||||
import { Label } from '../../../../shared/services';
|
||||
|
||||
export interface HelmChartSearchResultItem {
|
||||
Name: string;
|
||||
Score: number;
|
||||
Chart: HelmChartVersion;
|
||||
}
|
||||
export interface HelmChartItem {
|
||||
name: string;
|
||||
total_versions: number;
|
||||
latest_version: string;
|
||||
created: string;
|
||||
updated: string;
|
||||
icon: string;
|
||||
home: string;
|
||||
deprecated?: boolean;
|
||||
status?: string;
|
||||
pulls?: number;
|
||||
maintainer?: string;
|
||||
}
|
||||
|
||||
export interface HelmChartVersion {
|
||||
name: string;
|
||||
home: string;
|
||||
sources: string[];
|
||||
version: string;
|
||||
description: string;
|
||||
keywords: string[];
|
||||
maintainers: HelmChartMaintainer[];
|
||||
engine: string;
|
||||
icon: string;
|
||||
appVersion: string;
|
||||
apiVersion: string;
|
||||
urls: string[];
|
||||
created: string;
|
||||
digest: string;
|
||||
labels: Label[];
|
||||
deprecated?: boolean;
|
||||
}
|
||||
|
||||
export interface HelmChartDetail {
|
||||
metadata: HelmChartMetaData;
|
||||
dependencies: HelmChartDependency[];
|
||||
values: any;
|
||||
files: HelmchartFile;
|
||||
security: HelmChartSecurity;
|
||||
labels: Label[];
|
||||
}
|
||||
|
||||
export interface HelmChartMetaData {
|
||||
name: string;
|
||||
home: string;
|
||||
sources: string[];
|
||||
version: string;
|
||||
description: string;
|
||||
keywords: string[];
|
||||
maintainers: HelmChartMaintainer[];
|
||||
engine: string;
|
||||
icon: string;
|
||||
appVersion: string;
|
||||
urls: string[];
|
||||
created?: string;
|
||||
digest: string;
|
||||
}
|
||||
|
||||
export interface HelmChartMaintainer {
|
||||
name: string;
|
||||
email: string;
|
||||
}
|
||||
|
||||
export interface HelmChartDependency {
|
||||
name: string;
|
||||
version: string;
|
||||
repository: string;
|
||||
}
|
||||
|
||||
export interface HelmchartFile {
|
||||
'README.MD': string;
|
||||
'values.yaml': string;
|
||||
}
|
||||
|
||||
export interface HelmChartSecurity {
|
||||
signature: HelmChartSignature;
|
||||
}
|
||||
|
||||
export interface HelmChartSignature {
|
||||
signed: boolean;
|
||||
prov_file: string;
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
import { inject, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { HelmChartService } from './helm-chart.service';
|
||||
|
||||
describe('HelmChartService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [HelmChartService],
|
||||
});
|
||||
});
|
||||
|
||||
it('should be created', inject(
|
||||
[HelmChartService],
|
||||
(service: HelmChartService) => {
|
||||
expect(service).toBeTruthy();
|
||||
}
|
||||
));
|
||||
});
|
@ -1,266 +0,0 @@
|
||||
import { Observable, throwError as observableThrowError } from 'rxjs';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
|
||||
import { catchError, map } from 'rxjs/operators';
|
||||
import {
|
||||
HelmChartDetail,
|
||||
HelmChartItem,
|
||||
HelmChartVersion,
|
||||
} from './helm-chart.interface.service';
|
||||
import { RequestQueryParams } from '../../../../shared/services';
|
||||
import {
|
||||
HTTP_GET_OPTIONS,
|
||||
HTTP_JSON_OPTIONS,
|
||||
V1_BASE_HREF,
|
||||
} from '../../../../shared/units/utils';
|
||||
|
||||
/**
|
||||
* Define service methods for handling the helmchart related things.
|
||||
* Loose couple with project module.
|
||||
*
|
||||
**
|
||||
* @abstract
|
||||
* class HelmChartService
|
||||
*/
|
||||
export abstract class HelmChartService {
|
||||
/**
|
||||
* Get all helm charts info
|
||||
* ** deprecated param projectName Id of the project
|
||||
* ** deprecated param queryParams options params for query data
|
||||
*/
|
||||
abstract getHelmCharts(
|
||||
projectName: string,
|
||||
queryParams?: RequestQueryParams
|
||||
): Observable<HelmChartItem[]>;
|
||||
|
||||
/**
|
||||
* Delete an helmchart
|
||||
* ** deprecated param projectId Id of the project
|
||||
* ** deprecated param chartId ID of helmChart in this specific project
|
||||
*/
|
||||
abstract deleteHelmChart(
|
||||
projectId: number | string,
|
||||
chartName: string
|
||||
): Observable<any>;
|
||||
|
||||
/**
|
||||
* Get all the versions of helmchart
|
||||
* ** deprecated param projectName Id of the project
|
||||
* ** deprecated param chartName ID of the helm chart
|
||||
* ** deprecated param queryParams option params for query
|
||||
*/
|
||||
abstract getChartVersions(
|
||||
projectName: string,
|
||||
chartName: string
|
||||
): Observable<HelmChartVersion[]>;
|
||||
|
||||
/**
|
||||
* Delete a version of helmchart
|
||||
* ** deprecated param projectName ID of the project
|
||||
* ** deprecated param chartName ID of the chart you want to delete
|
||||
* ** deprecated param version name of the version
|
||||
*/
|
||||
abstract deleteChartVersion(
|
||||
projectName: string,
|
||||
chartName: string,
|
||||
version: string
|
||||
): Observable<any>;
|
||||
|
||||
/**
|
||||
* Get the all details of an helmchart
|
||||
* ** deprecated param projectName ID of the project
|
||||
* ** deprecated param chartname ID of the chart
|
||||
* ** deprecated param version name of the chart's version
|
||||
* ** deprecated param queryParams options
|
||||
*/
|
||||
abstract getChartDetail(
|
||||
projectName: string,
|
||||
chartname: string,
|
||||
version: string
|
||||
): Observable<HelmChartDetail>;
|
||||
|
||||
/**
|
||||
* Download an specific verison
|
||||
* ** deprecated param projectName ID of the project
|
||||
* ** deprecated param filename ID of the helm chart
|
||||
* ** deprecated param version Name of version
|
||||
* ** deprecated param queryParams options
|
||||
*/
|
||||
abstract downloadChart(
|
||||
projectName: string,
|
||||
filename: string
|
||||
): Observable<any>;
|
||||
|
||||
/**
|
||||
* Upload chart and prov files to chartmuseam
|
||||
* ** deprecated param projectName Name of the project
|
||||
* ** deprecated param chart chart file
|
||||
* ** deprecated param prov prov file
|
||||
*/
|
||||
abstract uploadChart(
|
||||
projectName: string,
|
||||
chart: File,
|
||||
prov: File
|
||||
): Observable<any>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement default service for helm chart.
|
||||
*/
|
||||
@Injectable()
|
||||
export class HelmChartDefaultService extends HelmChartService {
|
||||
constructor(private http: HttpClient) {
|
||||
super();
|
||||
}
|
||||
|
||||
private handleErrorObservable(error: HttpErrorResponse) {
|
||||
return observableThrowError(error);
|
||||
}
|
||||
|
||||
public getHelmCharts(projectName: string): Observable<HelmChartItem[]> {
|
||||
if (!projectName) {
|
||||
return observableThrowError(
|
||||
'Bad argument, No project id to get helm charts'
|
||||
);
|
||||
}
|
||||
|
||||
return this.http
|
||||
.get<HelmChartItem[]>(
|
||||
`${V1_BASE_HREF + '/chartrepo'}/${projectName}/charts`,
|
||||
HTTP_GET_OPTIONS
|
||||
)
|
||||
.pipe(
|
||||
map(response => response || []),
|
||||
catchError(error => this.handleErrorObservable(error))
|
||||
);
|
||||
}
|
||||
|
||||
public deleteHelmChart(
|
||||
projectId: number | string,
|
||||
chartName: string
|
||||
): Observable<any> {
|
||||
if (!chartName) {
|
||||
observableThrowError('Bad argument');
|
||||
}
|
||||
|
||||
return this.http
|
||||
.delete(
|
||||
`${
|
||||
V1_BASE_HREF + '/chartrepo'
|
||||
}/${projectId}/charts/${chartName}`
|
||||
)
|
||||
.pipe(
|
||||
map(response => {
|
||||
return response || [];
|
||||
})
|
||||
)
|
||||
.pipe(catchError(this.handleErrorObservable));
|
||||
}
|
||||
|
||||
public getChartVersions(
|
||||
projectName: string,
|
||||
chartName: string
|
||||
): Observable<HelmChartVersion[]> {
|
||||
return this.http
|
||||
.get<HelmChartVersion[]>(
|
||||
`${
|
||||
V1_BASE_HREF + '/chartrepo'
|
||||
}/${projectName}/charts/${chartName}`,
|
||||
HTTP_GET_OPTIONS
|
||||
)
|
||||
.pipe(
|
||||
map(response => response || []),
|
||||
catchError(this.handleErrorObservable)
|
||||
);
|
||||
}
|
||||
|
||||
public deleteChartVersion(
|
||||
projectName: string,
|
||||
chartName: string,
|
||||
version: string
|
||||
): any {
|
||||
return this.http
|
||||
.delete(
|
||||
`${
|
||||
V1_BASE_HREF + '/chartrepo'
|
||||
}/${projectName}/charts/${chartName}/${version}`,
|
||||
HTTP_JSON_OPTIONS
|
||||
)
|
||||
.pipe(
|
||||
map(response => {
|
||||
return response || [];
|
||||
})
|
||||
)
|
||||
.pipe(catchError(this.handleErrorObservable));
|
||||
}
|
||||
|
||||
public getChartDetail(
|
||||
projectName: string,
|
||||
chartName: string,
|
||||
version: string
|
||||
): Observable<HelmChartDetail> {
|
||||
return this.http
|
||||
.get<HelmChartDetail>(
|
||||
`${
|
||||
V1_BASE_HREF + '/chartrepo'
|
||||
}/${projectName}/charts/${chartName}/${version}`
|
||||
)
|
||||
.pipe(catchError(this.handleErrorObservable));
|
||||
}
|
||||
|
||||
public downloadChart(
|
||||
projectName: string,
|
||||
filename: string
|
||||
): Observable<any> {
|
||||
let url: string;
|
||||
let chartFileRegexPattern = new RegExp('^http.*/chartrepo/(.*)');
|
||||
if (chartFileRegexPattern.test(filename)) {
|
||||
let match = filename.match('^http.*/chartrepo/(.*)');
|
||||
url = `${DOWNLOAD_CHART_ENDPOINT}/${match[1]}`;
|
||||
} else {
|
||||
url = `${DOWNLOAD_CHART_ENDPOINT}/${projectName}/${filename}`;
|
||||
}
|
||||
return this.http
|
||||
.get(url, {
|
||||
responseType: 'blob',
|
||||
})
|
||||
.pipe(
|
||||
map(response => {
|
||||
let parts = filename.split('/');
|
||||
return {
|
||||
filename: parts[parts.length - 1],
|
||||
data: response,
|
||||
};
|
||||
})
|
||||
)
|
||||
.pipe(catchError(this.handleErrorObservable));
|
||||
}
|
||||
|
||||
public uploadChart(
|
||||
projectName: string,
|
||||
chart?: File,
|
||||
prov?: File
|
||||
): Observable<any> {
|
||||
let formData = new FormData();
|
||||
let uploadURL = `${V1_BASE_HREF + '/chartrepo'}/${projectName}/charts`;
|
||||
if (chart) {
|
||||
formData.append('chart', chart);
|
||||
}
|
||||
if (prov) {
|
||||
formData.append('prov', prov);
|
||||
if (!chart) {
|
||||
uploadURL = `${
|
||||
V1_BASE_HREF + '/chartrepo'
|
||||
}/${projectName}/prov`;
|
||||
}
|
||||
}
|
||||
return this.http
|
||||
.post(uploadURL, formData, {
|
||||
responseType: 'json',
|
||||
})
|
||||
.pipe(map(response => response || []))
|
||||
.pipe(catchError(this.handleErrorObservable));
|
||||
}
|
||||
}
|
||||
|
||||
export const DOWNLOAD_CHART_ENDPOINT: string = '/chartrepo';
|
@ -1,32 +0,0 @@
|
||||
<div>
|
||||
<div class="form-group filter-div">
|
||||
<input
|
||||
#filterInput
|
||||
class="clr-input"
|
||||
type="text"
|
||||
placeholder="{{ 'LABEL.FILTER_LABEL_PLACEHOLDER' | translate }}"
|
||||
[(ngModel)]="labelFilter" />
|
||||
</div>
|
||||
<div class="label-items-container">
|
||||
<div class="dropdown-item" *ngFor="let label of filteredLabels">
|
||||
<div class="cur-pointer" (click)="selectLabel(label)">
|
||||
<span class="check-label-span">
|
||||
<clr-icon
|
||||
*ngIf="isSelected(label)"
|
||||
shape="check"></clr-icon>
|
||||
</span>
|
||||
<span class="cur-pointer">
|
||||
<hbr-label-piece
|
||||
[label]="label"
|
||||
[labelWidth]="90"></hbr-label-piece>
|
||||
</span>
|
||||
<span
|
||||
*ngIf="isSelected(label)"
|
||||
class="x-label-span"
|
||||
(click)="$event.stopPropagation(); unselectLabel(label)">
|
||||
<clr-icon shape="times-circle"></clr-icon>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,37 +0,0 @@
|
||||
@mixin icon-span {
|
||||
width: 12px;
|
||||
min-height: 12px;
|
||||
}
|
||||
|
||||
.filter-div {
|
||||
margin-left: 9px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.cur-pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.label-items-container {
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
|
||||
.dropdown-item {
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
|
||||
.x-label-span {
|
||||
@include icon-span;
|
||||
|
||||
float: right;
|
||||
}
|
||||
|
||||
.check-label-span {
|
||||
@include icon-span;
|
||||
|
||||
float: left;
|
||||
margin-right: 9px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { LabelFilterComponent } from './label-filter.component';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||
import { SharedTestingModule } from '../../../../../shared/shared.module';
|
||||
|
||||
describe('LabelFilterComponent', () => {
|
||||
let component: LabelFilterComponent;
|
||||
let fixture: ComponentFixture<LabelFilterComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
imports: [SharedTestingModule],
|
||||
declarations: [LabelFilterComponent],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(LabelFilterComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -1,84 +0,0 @@
|
||||
import {
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnInit,
|
||||
ViewChild,
|
||||
} from '@angular/core';
|
||||
import { ClrDatagridFilterInterface } from '@clr/angular';
|
||||
import { fromEvent } from 'rxjs';
|
||||
import { debounceTime } from 'rxjs/operators';
|
||||
import { HelmChartVersion } from '../helm-chart.interface.service';
|
||||
import { Label } from '../../../../../shared/services';
|
||||
import { Artifact } from '../../../../../../../ng-swagger-gen/models/artifact';
|
||||
import { ResourceType } from '../../../../../shared/entities/shared.const';
|
||||
|
||||
@Component({
|
||||
selector: 'hbr-chart-version-label-filter',
|
||||
templateUrl: './label-filter.component.html',
|
||||
styleUrls: ['./label-filter.component.scss'],
|
||||
})
|
||||
export class LabelFilterComponent
|
||||
implements ClrDatagridFilterInterface<any>, OnInit
|
||||
{
|
||||
@Input() labels: Label[] = [];
|
||||
@Input() resourceType: ResourceType;
|
||||
|
||||
@ViewChild('filterInput', { static: true }) filterInputRef: ElementRef;
|
||||
|
||||
selectedLabels: Map<number, boolean> = new Map<number, boolean>();
|
||||
|
||||
changes: EventEmitter<any> = new EventEmitter<any>(false);
|
||||
|
||||
labelFilter = '';
|
||||
|
||||
ngOnInit(): void {
|
||||
fromEvent(this.filterInputRef.nativeElement, 'keyup')
|
||||
.pipe(debounceTime(500))
|
||||
.subscribe(() => {
|
||||
let hnd = setInterval(() => this.cdr.markForCheck(), 100);
|
||||
setTimeout(() => clearInterval(hnd), 2000);
|
||||
});
|
||||
}
|
||||
constructor(private cdr: ChangeDetectorRef) {}
|
||||
|
||||
get filteredLabels() {
|
||||
return this.labels.filter(label =>
|
||||
label.name.includes(this.labelFilter)
|
||||
);
|
||||
}
|
||||
|
||||
isActive(): boolean {
|
||||
return this.selectedLabels.size > 0;
|
||||
}
|
||||
|
||||
accepts(cv: any): boolean {
|
||||
if (this.resourceType === ResourceType.CHART_VERSION) {
|
||||
return (cv as HelmChartVersion).labels.some(label =>
|
||||
this.selectedLabels.get(label.id)
|
||||
);
|
||||
} else if (this.resourceType === ResourceType.REPOSITORY_TAG) {
|
||||
return (cv as Artifact).labels.some(label =>
|
||||
this.selectedLabels.get(label.id)
|
||||
);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
selectLabel(label: Label) {
|
||||
this.selectedLabels.set(label.id, true);
|
||||
this.changes.emit();
|
||||
}
|
||||
|
||||
unselectLabel(label: Label) {
|
||||
this.selectedLabels.delete(label.id);
|
||||
this.changes.emit(true);
|
||||
}
|
||||
|
||||
isSelected(label: Label) {
|
||||
return this.selectedLabels.has(label.id);
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
<div>
|
||||
<label class="dropdown-header">{{ addLabelHeaders | translate }}</label>
|
||||
<div class="form-group filter-div">
|
||||
<input
|
||||
class="clr-input"
|
||||
#filterInput
|
||||
type="text"
|
||||
placeholder="Filter labels"
|
||||
[(ngModel)]="labelFilter" />
|
||||
</div>
|
||||
<div class="label-items-container">
|
||||
<div class="dropdown-item" *ngFor="let label of sortedLabels">
|
||||
<div (click)="markLabel(label)">
|
||||
<div *ngIf="!isMarkOngoing(label)" class="mark-label-div">
|
||||
<clr-icon *ngIf="isMarked(label)" shape="check"></clr-icon>
|
||||
</div>
|
||||
<div *ngIf="isMarkOngoing(label)" class="spinner spinner-sm">
|
||||
Loading...
|
||||
</div>
|
||||
<div class="label-div">
|
||||
<hbr-label-piece
|
||||
[label]="label"
|
||||
[labelWidth]="130"></hbr-label-piece>
|
||||
</div>
|
||||
<div class="unmark-label-div" (click)="unmarkLabel(label)">
|
||||
<clr-icon
|
||||
*ngIf="isMarked(label)"
|
||||
shape="times-circle"></clr-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,53 +0,0 @@
|
||||
@mixin icon-span {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
|
||||
clr-icon {
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin flex-item {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.filter-div {
|
||||
margin-left: 9px;
|
||||
margin-right: 9px;
|
||||
margin-bottom: 9px;
|
||||
}
|
||||
|
||||
.label-items-container {
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
|
||||
.dropdown-item {
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
|
||||
.mark-label-div {
|
||||
@include icon-span;
|
||||
@include flex-item;
|
||||
|
||||
float: left;
|
||||
margin-right: 9px;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
@include flex-item;
|
||||
}
|
||||
|
||||
.label-div {
|
||||
@include flex-item;
|
||||
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.unmark-label-div {
|
||||
@include icon-span;
|
||||
@include flex-item;
|
||||
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { TranslateModule, TranslateService } from '@ngx-translate/core';
|
||||
import { LabelMarkerComponent } from './label-marker.component';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||
import { ClarityModule } from '@clr/angular';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { of } from 'rxjs';
|
||||
import { LabelService } from '../../../../../shared/services';
|
||||
import { ErrorHandler } from '../../../../../shared/units/error-handler';
|
||||
|
||||
describe('LabelMarkerComponent', () => {
|
||||
const mockErrorHandler = null;
|
||||
|
||||
const mockLabelService = {
|
||||
getChartVersionLabels: () => {
|
||||
return of({
|
||||
name: '111',
|
||||
description: 'string',
|
||||
color: 'string',
|
||||
scope: 'string',
|
||||
project_id: 1,
|
||||
});
|
||||
},
|
||||
markChartLabel: () => {},
|
||||
unmarkChartLabel: () => {},
|
||||
};
|
||||
let component: LabelMarkerComponent;
|
||||
let fixture: ComponentFixture<LabelMarkerComponent>;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
imports: [ClarityModule, TranslateModule.forRoot(), FormsModule],
|
||||
declarations: [LabelMarkerComponent],
|
||||
providers: [
|
||||
TranslateService,
|
||||
{ provide: LabelService, useValue: mockLabelService },
|
||||
{ provide: ErrorHandler, useValue: mockErrorHandler },
|
||||
],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(LabelMarkerComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -1,171 +0,0 @@
|
||||
import {
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
ElementRef,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnInit,
|
||||
Output,
|
||||
ViewChild,
|
||||
} from '@angular/core';
|
||||
import { fromEvent, Subject } from 'rxjs';
|
||||
import { debounceTime, finalize } from 'rxjs/operators';
|
||||
import { HelmChartVersion } from '../helm-chart.interface.service';
|
||||
import { Label, LabelService } from '../../../../../shared/services';
|
||||
import { ErrorHandler } from '../../../../../shared/units/error-handler';
|
||||
import { ResourceType } from '../../../../../shared/entities/shared.const';
|
||||
|
||||
@Component({
|
||||
selector: 'hbr-resource-label-marker',
|
||||
templateUrl: './label-marker.component.html',
|
||||
styleUrls: ['./label-marker.component.scss'],
|
||||
})
|
||||
export class LabelMarkerComponent implements OnInit {
|
||||
@Input() labels: Label[] = [];
|
||||
@Input() projectName: string;
|
||||
@Input() resource: HelmChartVersion;
|
||||
@Input() resourceType: ResourceType;
|
||||
@Input() addLabelHeaders: string;
|
||||
@Output() changeEvt = new EventEmitter<any>();
|
||||
|
||||
labelFilter = '';
|
||||
markedMap: Map<number, boolean> = new Map<number, boolean>();
|
||||
markingMap: Map<number, boolean> = new Map<number, boolean>();
|
||||
sortedLabels: Label[] = [];
|
||||
|
||||
loading = false;
|
||||
|
||||
labelChangeDebouncer: Subject<any> = new Subject();
|
||||
|
||||
@ViewChild('filterInput', { static: true }) filterInputRef: ElementRef;
|
||||
|
||||
ngOnInit(): void {
|
||||
this.sortedLabels = this.labels;
|
||||
this.refresh();
|
||||
fromEvent(this.filterInputRef.nativeElement, 'keyup')
|
||||
.pipe(debounceTime(500))
|
||||
.subscribe(() => this.refresh());
|
||||
|
||||
this.labelChangeDebouncer
|
||||
.pipe(debounceTime(1000))
|
||||
.subscribe(() => this.changeEvt.emit());
|
||||
}
|
||||
|
||||
constructor(
|
||||
private labelService: LabelService,
|
||||
private errorHandler: ErrorHandler,
|
||||
private cdr: ChangeDetectorRef
|
||||
) {}
|
||||
|
||||
refresh() {
|
||||
this.loading = true;
|
||||
if (this.resourceType === ResourceType.CHART_VERSION) {
|
||||
this.labelService
|
||||
.getChartVersionLabels(
|
||||
this.projectName,
|
||||
this.resource.name,
|
||||
(this.resource as HelmChartVersion).version
|
||||
)
|
||||
.pipe(
|
||||
finalize(() => {
|
||||
this.loading = false;
|
||||
let hnd = setInterval(
|
||||
() => this.cdr.markForCheck(),
|
||||
100
|
||||
);
|
||||
setTimeout(() => clearInterval(hnd), 2000);
|
||||
})
|
||||
)
|
||||
.subscribe(chartVersionLabels => {
|
||||
for (let label of chartVersionLabels) {
|
||||
this.markedMap.set(label.id, true);
|
||||
}
|
||||
this.sortedLabels = this.getSortedLabels();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
markLabel(label: Label) {
|
||||
if (this.markedMap.get(label.id) || this.isMarkOngoing(label)) {
|
||||
return;
|
||||
}
|
||||
this.markingMap.set(label.id, true);
|
||||
this.labelService
|
||||
.markChartLabel(
|
||||
this.projectName,
|
||||
this.resource.name,
|
||||
(this.resource as HelmChartVersion).version,
|
||||
label
|
||||
)
|
||||
.pipe(
|
||||
finalize(() => {
|
||||
this.markingMap.set(label.id, false);
|
||||
let hnd = setInterval(() => this.cdr.markForCheck(), 100);
|
||||
setTimeout(() => clearInterval(hnd), 5000);
|
||||
})
|
||||
)
|
||||
.subscribe(
|
||||
() => {
|
||||
this.markedMap.set(label.id, true);
|
||||
this.refresh();
|
||||
this.labelChangeDebouncer.next(null);
|
||||
let hnd = setInterval(() => this.cdr.markForCheck(), 100);
|
||||
setTimeout(() => clearInterval(hnd), 5000);
|
||||
},
|
||||
err => this.errorHandler.error(err)
|
||||
);
|
||||
}
|
||||
|
||||
unmarkLabel(label: Label) {
|
||||
if (!this.isMarked(label) || this.isMarkOngoing(label)) {
|
||||
return;
|
||||
}
|
||||
this.markingMap.set(label.id, true);
|
||||
this.labelService
|
||||
.unmarkChartLabel(
|
||||
this.projectName,
|
||||
this.resource.name,
|
||||
(this.resource as HelmChartVersion).version,
|
||||
label
|
||||
)
|
||||
.pipe(
|
||||
finalize(() => {
|
||||
this.markingMap.set(label.id, false);
|
||||
let hnd = setInterval(() => this.cdr.markForCheck(), 100);
|
||||
setTimeout(() => clearInterval(hnd), 5000);
|
||||
})
|
||||
)
|
||||
.subscribe(
|
||||
() => {
|
||||
this.markedMap.set(label.id, false);
|
||||
this.refresh();
|
||||
this.labelChangeDebouncer.next(null);
|
||||
let hnd = setInterval(() => this.cdr.markForCheck(), 100);
|
||||
setTimeout(() => clearInterval(hnd), 5000);
|
||||
},
|
||||
err => this.errorHandler.error(err)
|
||||
);
|
||||
}
|
||||
|
||||
isMarked(label: Label) {
|
||||
return this.markedMap.get(label.id) ? true : false;
|
||||
}
|
||||
|
||||
isMarkOngoing(label: Label) {
|
||||
return this.markingMap.get(label.id) ? true : false;
|
||||
}
|
||||
|
||||
getSortedLabels(): Label[] {
|
||||
return this.labels
|
||||
.filter(l => l.name.includes(this.labelFilter))
|
||||
.sort((a, b) => {
|
||||
if (this.isMarked(a) && !this.isMarked(b)) {
|
||||
return -1;
|
||||
} else if (!this.isMarked(a) && this.isMarked(b)) {
|
||||
return 1;
|
||||
} else {
|
||||
return a.name < b.name ? -1 : a.name > b.name ? 1 : 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -1,276 +0,0 @@
|
||||
<div class="version-position">
|
||||
<div class="row flex-items-xs-between">
|
||||
<div class="col-xs-4">
|
||||
<div class="title-container">
|
||||
<div class="chart-name-span">
|
||||
{{ chartName | translate }}
|
||||
</div>
|
||||
<div>
|
||||
{{ roleName | translate }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row version-tool">
|
||||
<div class="toolbar">
|
||||
<div class="row flex-items-xs-right option-right rightPos">
|
||||
<div class="flex-xs-middle">
|
||||
<hbr-filter
|
||||
[withDivider]="true"
|
||||
filterPlaceholder="{{
|
||||
'HELM_CHART.FILTER_FOR_CHARTS' | translate
|
||||
}}"
|
||||
[currentValue]="lastFilteredVersionName"
|
||||
(filterEvt)="updateFilterValue($event)"></hbr-filter>
|
||||
<span
|
||||
class="card-btn"
|
||||
(click)="showCard(true)"
|
||||
(mouseenter)="mouseEnter('card')"
|
||||
(mouseleave)="mouseLeave('card')">
|
||||
<clr-icon
|
||||
[ngClass]="{
|
||||
'is-highlight': isCardView || isHovering('card')
|
||||
}"
|
||||
shape="view-cards"></clr-icon>
|
||||
</span>
|
||||
<span
|
||||
class="list-btn"
|
||||
(click)="showCard(false)"
|
||||
(mouseenter)="mouseEnter('list')"
|
||||
(mouseleave)="mouseLeave('list')">
|
||||
<clr-icon
|
||||
[ngClass]="{
|
||||
'is-highlight':
|
||||
!isCardView || isHovering('list')
|
||||
}"
|
||||
shape="view-list"></clr-icon>
|
||||
</span>
|
||||
<span class="filter-divider"></span>
|
||||
<span class="refresh-btn" (click)="refresh()">
|
||||
<clr-icon shape="refresh"></clr-icon>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div
|
||||
*ngIf="!isCardView"
|
||||
class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
|
||||
<clr-datagrid
|
||||
(clrDgRefresh)="refresh($event)"
|
||||
[clrDgLoading]="loading"
|
||||
[(clrDgSelected)]="selectedRows">
|
||||
<clr-dg-action-bar>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-secondary"
|
||||
[disabled]="
|
||||
!(selectedRows.length === 1) ||
|
||||
!hasDownloadHelmChartVersionPermission
|
||||
"
|
||||
(click)="versionDownload()">
|
||||
<clr-icon shape="download" size="16"></clr-icon> {{
|
||||
'HELM_CHART.DOWNLOAD' | translate
|
||||
}}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-secondary"
|
||||
[disabled]="
|
||||
selectedRows.length <= 0 ||
|
||||
!hasDeleteHelmChartVersionPermission
|
||||
"
|
||||
(click)="openVersionDeleteModal()">
|
||||
<clr-icon shape="times" size="16"></clr-icon> {{
|
||||
'BUTTON.DELETE' | translate
|
||||
}}
|
||||
</button>
|
||||
<clr-dropdown>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-secondary"
|
||||
clrDropdownTrigger
|
||||
[disabled]="
|
||||
!(selectedRows.length === 1) ||
|
||||
!hasAddRemoveHelmChartVersionPermission
|
||||
">
|
||||
<clr-icon shape="plus" size="16"></clr-icon
|
||||
>{{ 'REPOSITORY.ADD_LABELS' | translate }}
|
||||
</button>
|
||||
<clr-dropdown-menu clrPosition="bottom-left" *clrIfOpen>
|
||||
<hbr-resource-label-marker
|
||||
[labels]="labels"
|
||||
[projectName]="projectName"
|
||||
[resource]="selectedRows[0]"
|
||||
[resourceType]="resourceType"
|
||||
[addLabelHeaders]="addLabelHeaders"
|
||||
(changeEvt)="onLabelChange(selectedRows[0])">
|
||||
</hbr-resource-label-marker>
|
||||
</clr-dropdown-menu>
|
||||
</clr-dropdown>
|
||||
</clr-dg-action-bar>
|
||||
<clr-dg-column>{{
|
||||
'HELM_CHART.VERSION' | translate
|
||||
}}</clr-dg-column>
|
||||
<clr-dg-column>{{
|
||||
'HELM_CHART.STATUS' | translate
|
||||
}}</clr-dg-column>
|
||||
<clr-dg-column>{{
|
||||
'HELM_CHART.ENGINE' | translate
|
||||
}}</clr-dg-column>
|
||||
|
||||
<clr-dg-column>{{
|
||||
'HELM_CHART.MAINTAINERS' | translate
|
||||
}}</clr-dg-column>
|
||||
<clr-dg-column>{{
|
||||
'HELM_CHART.CREATED' | translate
|
||||
}}</clr-dg-column>
|
||||
<clr-dg-column>
|
||||
{{ 'REPOSITORY.LABELS' | translate }}
|
||||
<clr-dg-filter [clrDgFilter]="labelFilter">
|
||||
<hbr-chart-version-label-filter
|
||||
#labelFilter
|
||||
class="label-filter"
|
||||
[labels]="labels"
|
||||
[resourceType]="resourceType">
|
||||
</hbr-chart-version-label-filter>
|
||||
</clr-dg-filter>
|
||||
</clr-dg-column>
|
||||
<clr-dg-placeholder>{{
|
||||
'HELM_CHART.NO_VERSION_PLACEHOLDER' | translate
|
||||
}}</clr-dg-placeholder>
|
||||
<clr-dg-row
|
||||
*clrDgItems="let v of chartVersions"
|
||||
[clrDgItem]="v">
|
||||
<clr-dg-cell>
|
||||
<span class="list-img">
|
||||
<img
|
||||
[src]="v.icon ? v.icon : chartDefaultIcon"
|
||||
(error)="getDefaultIcon(v)" />
|
||||
</span>
|
||||
<a
|
||||
href="javascript:void(0)"
|
||||
(click)="onVersionClick(v)"
|
||||
>{{ v.version }}</a
|
||||
>
|
||||
</clr-dg-cell>
|
||||
<clr-dg-cell>{{
|
||||
getStatusString(v) | translate
|
||||
}}</clr-dg-cell>
|
||||
<clr-dg-cell>{{ v.engine }}</clr-dg-cell>
|
||||
<clr-dg-cell>{{
|
||||
getMaintainerString(v.maintainers)
|
||||
}}</clr-dg-cell>
|
||||
<clr-dg-cell>{{ v.created | harborDatetime }}</clr-dg-cell>
|
||||
<clr-dg-cell>
|
||||
<div>
|
||||
<hbr-label-piece
|
||||
*ngIf="v.labels?.length"
|
||||
[label]="v.labels[0]"
|
||||
[labelWidth]="130">
|
||||
</hbr-label-piece>
|
||||
<hbr-resource-label-signpost
|
||||
*ngIf="v.labels?.length > 1"
|
||||
[labels]="
|
||||
v.labels
|
||||
"></hbr-resource-label-signpost>
|
||||
</div>
|
||||
</clr-dg-cell>
|
||||
</clr-dg-row>
|
||||
<clr-dg-footer>
|
||||
<clr-dg-pagination
|
||||
#pagination
|
||||
[clrDgPageSize]="pageSize"
|
||||
[clrDgTotalItems]="totalCount">
|
||||
<clr-dg-page-size [clrPageSizeOptions]="[15, 25, 50]">{{
|
||||
'PAGINATION.PAGE_SIZE' | translate
|
||||
}}</clr-dg-page-size>
|
||||
<span *ngIf="totalCount">
|
||||
{{ pagination.firstItem + 1 }} -
|
||||
{{ pagination.lastItem + 1 }}
|
||||
{{ 'HELM_CHART.OF' | translate }}
|
||||
</span>
|
||||
{{ totalCount }} {{ 'HELM_CHART.ITEMS' | translate }}
|
||||
</clr-dg-pagination>
|
||||
</clr-dg-footer>
|
||||
</clr-datagrid>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="isCardView" class="row card-container">
|
||||
<div
|
||||
*ngFor="let item of chartVersions"
|
||||
class="col-lg-3 col-md-4 col-sm-6">
|
||||
<a
|
||||
let
|
||||
i="index;"
|
||||
class="card clickable"
|
||||
(click)="onVersionClick(item)">
|
||||
<div class="card-header">
|
||||
<div class="card-media-block">
|
||||
<img
|
||||
[src]="item.icon ? item.icon : chartDefaultIcon"
|
||||
(error)="getDefaultIcon(item)" />
|
||||
<div class="card-media-description">
|
||||
<span class="card-media-title">{{
|
||||
item.name
|
||||
}}</span>
|
||||
<a class="card-media-text">{{ item.home }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-block">
|
||||
<div class="form-group">
|
||||
<label class="card-label">{{
|
||||
'HELM_CHART.STATUS' | translate
|
||||
}}</label>
|
||||
<div>{{ getStatusString(item) | translate }}</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="card-label">{{
|
||||
'HELM_CHART.ENGINE' | translate
|
||||
}}</label>
|
||||
<div>{{ item.engine }}</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="card-label">{{
|
||||
'HELM_CHART.MAINTAINERS' | translate
|
||||
}}</label>
|
||||
<div>{{ getMaintainerString(item.maintainers) }}</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="card-label">{{
|
||||
'HELM_CHART.VERSION' | translate
|
||||
}}</label>
|
||||
<div>{{ item.version }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<clr-dropdown [clrCloseMenuOnItemClick]="false">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-link"
|
||||
(click)="versionDownload($event, item)">
|
||||
{{ 'HELM_CHART.DOWNLOAD' | translate }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-link"
|
||||
[disabled]="!hasDeleteHelmChartVersionPermission"
|
||||
(click)="deleteVersionCard($event, item)">
|
||||
{{ 'BUTTON.DELETE' | translate }}
|
||||
</button>
|
||||
</clr-dropdown>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div *ngIf="loading" class="center-x">
|
||||
<span class="vertical-helper"></span>
|
||||
<span class="spinner"></span>
|
||||
</div>
|
||||
</div>
|
||||
<confirmation-dialog
|
||||
#confirmationDialog
|
||||
(confirmAction)="confirmDeletion($event)"></confirmation-dialog>
|
||||
</div>
|
@ -1,131 +0,0 @@
|
||||
@import "../../../../../../shared/mixin";
|
||||
|
||||
.title-container {
|
||||
display: flex;
|
||||
|
||||
.chart-name-span {
|
||||
border-right: 1px solid gray;
|
||||
font-size: 27px;
|
||||
font-weight: normal;
|
||||
padding-right: 9px;
|
||||
margin-right: 9px;
|
||||
}
|
||||
}
|
||||
|
||||
.version-tool {
|
||||
position: relative;
|
||||
|
||||
.toolbar {
|
||||
overflow: hidden;
|
||||
/* stylelint-disable */
|
||||
.rightPos {
|
||||
@include grid-right-top-pos;
|
||||
|
||||
.filter-divider {
|
||||
display: inline-block;
|
||||
height: 16px;
|
||||
width: 1px;
|
||||
padding-top: 12px;
|
||||
padding-bottom: 12px;
|
||||
position: relative;
|
||||
top: 9px;
|
||||
margin-right: 6px;
|
||||
margin-left: 6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clr-dg-action-bar {
|
||||
clr-dropdown {
|
||||
.btn {
|
||||
@include dropdown-as-action-button;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hbr-resource-label-signpost {
|
||||
display: inline-block;
|
||||
max-height: 24px;
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
.card-container {
|
||||
margin-top: 40px;
|
||||
|
||||
.card-header {
|
||||
.card-media-block {
|
||||
img {
|
||||
height: 45px;
|
||||
width: 45px;
|
||||
}
|
||||
|
||||
.card-media-description {
|
||||
width:80%;
|
||||
height: 45px;
|
||||
|
||||
.card-media-title {
|
||||
overflow: hidden;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.card-media-text {
|
||||
font-size:0.8em;
|
||||
color:#007cbb;
|
||||
@include text-overflow;
|
||||
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card-block {
|
||||
font-size:0.9em;
|
||||
margin-top: 24px;
|
||||
min-height: 100px;
|
||||
|
||||
.form-group {
|
||||
display: flex;
|
||||
|
||||
label {
|
||||
width: 100px;
|
||||
color:#aaa;
|
||||
}
|
||||
}
|
||||
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.card-footer {
|
||||
padding-top: 6px;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.list-img {
|
||||
img {
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
margin-right: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.vertical-helper {
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.center-x {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
top: 6.5rem;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.version-position {
|
||||
position: relative;
|
||||
}
|
@ -1,110 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ChartVersionComponent } from './helm-chart-version.component';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||
import { HelmChartService } from '../../helm-chart.service';
|
||||
import { LabelFilterComponent } from '../../label-filter/label-filter.component';
|
||||
import { of } from 'rxjs';
|
||||
import {
|
||||
LabelService,
|
||||
SystemInfoService,
|
||||
UserPermissionService,
|
||||
} from '../../../../../../shared/services';
|
||||
import { ErrorHandler } from '../../../../../../shared/units/error-handler';
|
||||
import { OperationService } from '../../../../../../shared/components/operation/operation.service';
|
||||
import { delay } from 'rxjs/operators';
|
||||
import { SharedTestingModule } from '../../../../../../shared/shared.module';
|
||||
|
||||
describe('ChartVersionComponent', () => {
|
||||
let component: ChartVersionComponent;
|
||||
let fixture: ComponentFixture<ChartVersionComponent>;
|
||||
const mockSystemInfoService = {
|
||||
getSystemInfo: () => {
|
||||
return of({
|
||||
with_notary: false,
|
||||
with_admiral: false,
|
||||
admiral_endpoint: '',
|
||||
auth_mode: 'oidc_auth',
|
||||
registry_url: 'nightly-oidc.harbor.io',
|
||||
external_url: 'https://nightly-oidc.harbor.io',
|
||||
project_creation_restriction: 'everyone',
|
||||
self_registration: false,
|
||||
has_ca_root: false,
|
||||
harbor_version: 'dev',
|
||||
registry_storage_provider_name: 'filesystem',
|
||||
read_only: false,
|
||||
with_chartmuseum: true,
|
||||
notification_enable: true,
|
||||
});
|
||||
},
|
||||
};
|
||||
const mockLabelService = {
|
||||
getLabels: () => {
|
||||
return of([]);
|
||||
},
|
||||
getProjectLabels: () => {
|
||||
return of([]);
|
||||
},
|
||||
};
|
||||
const mockErrorHandler = null;
|
||||
const mockOperationService = {
|
||||
publishInfo: () => {
|
||||
return of([]);
|
||||
},
|
||||
};
|
||||
const mockUserPermissionService = {
|
||||
getPermission() {
|
||||
return of(true);
|
||||
},
|
||||
};
|
||||
const mockHelmChartService = {
|
||||
getChartVersions() {
|
||||
return of([
|
||||
{
|
||||
name: 'string',
|
||||
home: 'string',
|
||||
sources: [],
|
||||
version: 'string',
|
||||
description: 'string',
|
||||
keywords: [],
|
||||
maintainers: [],
|
||||
engine: 'string',
|
||||
icon: 'string',
|
||||
appVersion: 'string',
|
||||
apiVersion: 'string',
|
||||
urls: [],
|
||||
created: 'string',
|
||||
digest: 'string',
|
||||
labels: [],
|
||||
},
|
||||
]).pipe(delay(0));
|
||||
},
|
||||
};
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
imports: [SharedTestingModule],
|
||||
declarations: [ChartVersionComponent, LabelFilterComponent],
|
||||
providers: [
|
||||
{ provide: SystemInfoService, useValue: mockSystemInfoService },
|
||||
{ provide: LabelService, useValue: mockLabelService },
|
||||
{
|
||||
provide: UserPermissionService,
|
||||
useValue: mockUserPermissionService,
|
||||
},
|
||||
{ provide: ErrorHandler, useValue: mockErrorHandler },
|
||||
{ provide: HelmChartService, useValue: mockHelmChartService },
|
||||
{ provide: OperationService, useValue: mockOperationService },
|
||||
],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ChartVersionComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -1,504 +0,0 @@
|
||||
import {
|
||||
Component,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnInit,
|
||||
Output,
|
||||
ViewChild,
|
||||
} from '@angular/core';
|
||||
import { forkJoin, Observable, throwError as observableThrowError } from 'rxjs';
|
||||
import { catchError, finalize, map } from 'rxjs/operators';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import {
|
||||
HelmChartMaintainer,
|
||||
HelmChartVersion,
|
||||
} from '../../helm-chart.interface.service';
|
||||
import { HelmChartService } from '../../helm-chart.service';
|
||||
import {
|
||||
LabelService as OldLabelService,
|
||||
State,
|
||||
SystemInfo,
|
||||
SystemInfoService,
|
||||
UserPermissionService,
|
||||
USERSTATICPERMISSION,
|
||||
} from '../../../../../../shared/services';
|
||||
import {
|
||||
downloadFile,
|
||||
getPageSizeFromLocalStorage,
|
||||
PageSizeMapKeys,
|
||||
setPageSizeToLocalStorage,
|
||||
} from '../../../../../../shared/units/utils';
|
||||
import { ErrorHandler } from '../../../../../../shared/units/error-handler';
|
||||
import { OperationService } from '../../../../../../shared/components/operation/operation.service';
|
||||
import {
|
||||
operateChanges,
|
||||
OperateInfo,
|
||||
OperationState,
|
||||
} from '../../../../../../shared/components/operation/operate';
|
||||
import {
|
||||
ConfirmationButtons,
|
||||
ConfirmationState,
|
||||
ConfirmationTargets,
|
||||
DefaultHelmIcon,
|
||||
ResourceType,
|
||||
} from '../../../../../../shared/entities/shared.const';
|
||||
import { errorHandler } from '../../../../../../shared/units/shared.utils';
|
||||
import { ConfirmationDialogComponent } from '../../../../../../shared/components/confirmation-dialog';
|
||||
import { ConfirmationMessage } from '../../../../../global-confirmation-dialog/confirmation-message';
|
||||
import { ConfirmationAcknowledgement } from '../../../../../global-confirmation-dialog/confirmation-state-message';
|
||||
import { Label } from '../../../../../../../../ng-swagger-gen/models/label';
|
||||
import { LabelService } from '../../../../../../../../ng-swagger-gen/services/label.service';
|
||||
import { ClrDatagridStateInterface } from '@clr/angular';
|
||||
|
||||
const PAGE_SIZE: number = 100;
|
||||
@Component({
|
||||
selector: 'hbr-helm-chart-version',
|
||||
templateUrl: './helm-chart-version.component.html',
|
||||
styleUrls: ['./helm-chart-version.component.scss'],
|
||||
})
|
||||
export class ChartVersionComponent implements OnInit {
|
||||
signedCon: { [key: string]: any | string[] } = {};
|
||||
@Input() projectId: number;
|
||||
@Input() projectName: string;
|
||||
@Input() chartName: string;
|
||||
@Input() roleName: string;
|
||||
@Input() hasSignedIn: boolean;
|
||||
@Input() chartDefaultIcon: string = DefaultHelmIcon;
|
||||
@Output() versionClickEvt = new EventEmitter<string>();
|
||||
@Output() backEvt = new EventEmitter<any>();
|
||||
|
||||
lastFilteredVersionName: string;
|
||||
chartVersions: HelmChartVersion[] = [];
|
||||
systemInfo: SystemInfo;
|
||||
selectedRows: HelmChartVersion[] = [];
|
||||
labels: Label[] = [];
|
||||
loading = true;
|
||||
resourceType = ResourceType.CHART_VERSION;
|
||||
|
||||
isCardView: boolean;
|
||||
cardHover = false;
|
||||
listHover = false;
|
||||
|
||||
pageSize: number = getPageSizeFromLocalStorage(
|
||||
PageSizeMapKeys.CHART_VERSION_COMPONENT
|
||||
);
|
||||
currentPage = 1;
|
||||
totalCount = 0;
|
||||
currentState: State;
|
||||
|
||||
chartFile: File;
|
||||
provFile: File;
|
||||
|
||||
addLabelHeaders = 'HELM_CHART.ADD_LABEL_TO_CHART_VERSION';
|
||||
|
||||
@ViewChild('confirmationDialog')
|
||||
confirmationDialog: ConfirmationDialogComponent;
|
||||
hasAddRemoveHelmChartVersionPermission: boolean;
|
||||
hasDownloadHelmChartVersionPermission: boolean;
|
||||
hasDeleteHelmChartVersionPermission: boolean;
|
||||
constructor(
|
||||
private errorHandlerEntity: ErrorHandler,
|
||||
private systemInfoService: SystemInfoService,
|
||||
private helmChartService: HelmChartService,
|
||||
private labelService: LabelService,
|
||||
private resrouceLabelService: OldLabelService,
|
||||
public userPermissionService: UserPermissionService,
|
||||
private operationService: OperationService,
|
||||
private translateService: TranslateService
|
||||
) {}
|
||||
|
||||
public get registryUrl(): string {
|
||||
return this.systemInfo ? this.systemInfo.registry_url : '';
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
// Get system info for tag views
|
||||
this.systemInfoService.getSystemInfo().subscribe(
|
||||
systemInfo => (this.systemInfo = systemInfo),
|
||||
error => this.errorHandlerEntity.error(error)
|
||||
);
|
||||
this.refresh();
|
||||
this.getLabels();
|
||||
this.lastFilteredVersionName = '';
|
||||
this.getHelmChartVersionPermission(this.projectId);
|
||||
}
|
||||
|
||||
updateFilterValue(value: string) {
|
||||
this.lastFilteredVersionName = value;
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
getLabels() {
|
||||
// get all project labels
|
||||
this.labelService
|
||||
.ListLabelsResponse({
|
||||
pageSize: PAGE_SIZE,
|
||||
page: 1,
|
||||
scope: 'p',
|
||||
projectId: this.projectId,
|
||||
})
|
||||
.subscribe(res => {
|
||||
if (res.headers) {
|
||||
const xHeader: string = res.headers.get('X-Total-Count');
|
||||
const totalCount = parseInt(xHeader, 0);
|
||||
let arr = res.body || [];
|
||||
if (totalCount <= PAGE_SIZE) {
|
||||
// already gotten all project labels
|
||||
if (arr && arr.length) {
|
||||
this.labels = this.labels.concat(arr);
|
||||
}
|
||||
} else {
|
||||
// get all the project labels in specified times
|
||||
const times: number = Math.ceil(totalCount / PAGE_SIZE);
|
||||
const observableList: Observable<Label[]>[] = [];
|
||||
for (let i = 2; i <= times; i++) {
|
||||
observableList.push(
|
||||
this.labelService.ListLabels({
|
||||
page: i,
|
||||
pageSize: PAGE_SIZE,
|
||||
scope: 'p',
|
||||
projectId: this.projectId,
|
||||
})
|
||||
);
|
||||
}
|
||||
forkJoin(observableList).subscribe(response => {
|
||||
if (response && response.length) {
|
||||
response.forEach(item => {
|
||||
arr = arr.concat(item);
|
||||
});
|
||||
this.labels = this.labels.concat(arr);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
// get all global labels
|
||||
this.labelService
|
||||
.ListLabelsResponse({
|
||||
pageSize: PAGE_SIZE,
|
||||
page: 1,
|
||||
scope: 'g',
|
||||
})
|
||||
.subscribe(res => {
|
||||
if (res.headers) {
|
||||
const xHeader: string = res.headers.get('X-Total-Count');
|
||||
const totalCount = parseInt(xHeader, 0);
|
||||
let arr = res.body || [];
|
||||
if (totalCount <= PAGE_SIZE) {
|
||||
// already gotten all global labels
|
||||
if (arr && arr.length) {
|
||||
this.labels = this.labels.concat(arr);
|
||||
}
|
||||
} else {
|
||||
// get all the global labels in specified times
|
||||
const times: number = Math.ceil(totalCount / PAGE_SIZE);
|
||||
const observableList: Observable<Label[]>[] = [];
|
||||
for (let i = 2; i <= times; i++) {
|
||||
observableList.push(
|
||||
this.labelService.ListLabels({
|
||||
page: i,
|
||||
pageSize: PAGE_SIZE,
|
||||
scope: 'g',
|
||||
})
|
||||
);
|
||||
}
|
||||
forkJoin(observableList).subscribe(response => {
|
||||
if (response && response.length) {
|
||||
response.forEach(item => {
|
||||
arr = arr.concat(item);
|
||||
});
|
||||
this.labels = this.labels.concat(arr);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
refresh(state?: ClrDatagridStateInterface) {
|
||||
if (state?.page?.size) {
|
||||
setPageSizeToLocalStorage(
|
||||
PageSizeMapKeys.CHART_VERSION_COMPONENT,
|
||||
state.page.size
|
||||
);
|
||||
}
|
||||
this.loading = true;
|
||||
this.helmChartService
|
||||
.getChartVersions(this.projectName, this.chartName)
|
||||
.pipe(
|
||||
finalize(() => {
|
||||
this.selectedRows = [];
|
||||
this.loading = false;
|
||||
})
|
||||
)
|
||||
.subscribe(
|
||||
versions => {
|
||||
this.chartVersions = versions.filter(x =>
|
||||
x?.version?.includes(this.lastFilteredVersionName)
|
||||
);
|
||||
this.totalCount = versions.length;
|
||||
},
|
||||
err => {
|
||||
this.errorHandlerEntity.error(err);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
getMaintainerString(maintainers: HelmChartMaintainer[]) {
|
||||
if (!maintainers || maintainers.length < 1) {
|
||||
return '';
|
||||
}
|
||||
|
||||
let maintainer_string = maintainers[0].name;
|
||||
if (maintainers.length > 1) {
|
||||
maintainer_string = `${maintainer_string} (${
|
||||
maintainers.length - 1
|
||||
} others)`;
|
||||
}
|
||||
return maintainer_string;
|
||||
}
|
||||
|
||||
onVersionClick(version: HelmChartVersion) {
|
||||
this.versionClickEvt.emit(version.version);
|
||||
}
|
||||
|
||||
deleteVersion(version: HelmChartVersion): Observable<any> {
|
||||
// init operation info
|
||||
let operateMsg = new OperateInfo();
|
||||
operateMsg.name = 'OPERATION.DELETE_CHART_VERSION';
|
||||
operateMsg.data.id = version.digest;
|
||||
operateMsg.state = OperationState.progressing;
|
||||
operateMsg.data.name = `${version.name}:${version.version}`;
|
||||
this.operationService.publishInfo(operateMsg);
|
||||
|
||||
return this.helmChartService
|
||||
.deleteChartVersion(
|
||||
this.projectName,
|
||||
this.chartName,
|
||||
version.version
|
||||
)
|
||||
.pipe(
|
||||
map(() => operateChanges(operateMsg, OperationState.success)),
|
||||
catchError(error => {
|
||||
const message = errorHandler(error);
|
||||
this.translateService
|
||||
.get(message)
|
||||
.subscribe(res =>
|
||||
operateChanges(
|
||||
operateMsg,
|
||||
OperationState.failure,
|
||||
res
|
||||
)
|
||||
);
|
||||
return observableThrowError(error);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
deleteVersions(versions: HelmChartVersion[]) {
|
||||
if (versions && versions.length < 1) {
|
||||
return;
|
||||
}
|
||||
let successCount: number;
|
||||
let totalCount = this.chartVersions.length;
|
||||
let versionObs = versions.map(v => this.deleteVersion(v));
|
||||
forkJoin(versionObs)
|
||||
.pipe(
|
||||
finalize(() => {
|
||||
if (totalCount !== successCount) {
|
||||
this.refresh();
|
||||
}
|
||||
})
|
||||
)
|
||||
.subscribe(
|
||||
res => {
|
||||
successCount = res.filter(
|
||||
r => r.state === OperationState.success
|
||||
).length;
|
||||
if (totalCount === successCount) {
|
||||
this.backEvt.emit();
|
||||
}
|
||||
},
|
||||
error => {
|
||||
this.errorHandlerEntity.error(error);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
versionDownload(evt?: Event, item?: HelmChartVersion) {
|
||||
if (evt) {
|
||||
evt.stopPropagation();
|
||||
}
|
||||
let selectedVersion: HelmChartVersion;
|
||||
|
||||
if (item) {
|
||||
selectedVersion = item;
|
||||
} else {
|
||||
// return if selected version less then 1
|
||||
if (this.selectedRows.length < 1) {
|
||||
return;
|
||||
}
|
||||
selectedVersion = this.selectedRows[0];
|
||||
}
|
||||
if (!selectedVersion) {
|
||||
return;
|
||||
}
|
||||
|
||||
let filename = selectedVersion.urls[0];
|
||||
this.helmChartService
|
||||
.downloadChart(this.projectName, filename)
|
||||
.subscribe(
|
||||
res => {
|
||||
downloadFile(res);
|
||||
},
|
||||
error => {
|
||||
this.errorHandlerEntity.error(error);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
showCard(cardView: boolean) {
|
||||
if (this.isCardView === cardView) {
|
||||
return;
|
||||
}
|
||||
this.isCardView = cardView;
|
||||
}
|
||||
|
||||
mouseEnter(itemName: string) {
|
||||
if (itemName === 'card') {
|
||||
this.cardHover = true;
|
||||
} else {
|
||||
this.listHover = true;
|
||||
}
|
||||
}
|
||||
|
||||
mouseLeave(itemName: string) {
|
||||
if (itemName === 'card') {
|
||||
this.cardHover = false;
|
||||
} else {
|
||||
this.listHover = false;
|
||||
}
|
||||
}
|
||||
|
||||
isHovering(itemName: string) {
|
||||
if (itemName === 'card') {
|
||||
return this.cardHover;
|
||||
} else {
|
||||
return this.listHover;
|
||||
}
|
||||
}
|
||||
|
||||
onChartFileChangeEvent(event) {
|
||||
if (event.target.files && event.target.files.length > 0) {
|
||||
this.chartFile = event.target.files[0];
|
||||
}
|
||||
}
|
||||
onProvFileChangeEvent(event) {
|
||||
if (event.target.files && event.target.files.length > 0) {
|
||||
this.provFile = event.target.files[0];
|
||||
}
|
||||
}
|
||||
|
||||
deleteVersionCard(env: Event, version: HelmChartVersion) {
|
||||
env.stopPropagation();
|
||||
this.openVersionDeleteModal([version]);
|
||||
}
|
||||
|
||||
openVersionDeleteModal(versions?: HelmChartVersion[]) {
|
||||
if (!versions) {
|
||||
versions = this.selectedRows;
|
||||
}
|
||||
let versionNames = versions.map(v => v.version).join(',');
|
||||
let message = new ConfirmationMessage(
|
||||
'HELM_CHART.DELETE_CHART_VERSION_TITLE',
|
||||
'HELM_CHART.DELETE_CHART_VERSION',
|
||||
versionNames,
|
||||
versions,
|
||||
ConfirmationTargets.HELM_CHART_VERSION,
|
||||
ConfirmationButtons.DELETE_CANCEL
|
||||
);
|
||||
this.confirmationDialog.open(message);
|
||||
}
|
||||
|
||||
confirmDeletion(message: ConfirmationAcknowledgement) {
|
||||
if (
|
||||
message &&
|
||||
message.source === ConfirmationTargets.HELM_CHART_VERSION &&
|
||||
message.state === ConfirmationState.CONFIRMED
|
||||
) {
|
||||
let versions = message.data;
|
||||
this.deleteVersions(versions);
|
||||
}
|
||||
}
|
||||
|
||||
getImgLink(v: HelmChartVersion) {
|
||||
if (v.icon) {
|
||||
return v.icon;
|
||||
} else {
|
||||
return DefaultHelmIcon;
|
||||
}
|
||||
}
|
||||
|
||||
getDefaultIcon(v: HelmChartVersion) {
|
||||
v.icon = this.chartDefaultIcon;
|
||||
}
|
||||
|
||||
getStatusString(chartVersion: HelmChartVersion) {
|
||||
if (chartVersion.deprecated) {
|
||||
return 'HELM_CHART.DEPRECATED';
|
||||
} else {
|
||||
return 'HELM_CHART.ACTIVE';
|
||||
}
|
||||
}
|
||||
|
||||
onLabelChange(version: HelmChartVersion) {
|
||||
this.resrouceLabelService
|
||||
.getChartVersionLabels(
|
||||
this.projectName,
|
||||
this.chartName,
|
||||
version.version
|
||||
)
|
||||
.subscribe(labels => {
|
||||
let versionIdx = this.chartVersions.findIndex(
|
||||
v => v.name === version.name
|
||||
);
|
||||
this.chartVersions[versionIdx].labels = labels;
|
||||
});
|
||||
}
|
||||
|
||||
getHelmChartVersionPermission(projectId: number): void {
|
||||
let hasAddRemoveHelmChartVersionPermission =
|
||||
this.userPermissionService.getPermission(
|
||||
projectId,
|
||||
USERSTATICPERMISSION.HELM_CHART_VERSION_LABEL.KEY,
|
||||
USERSTATICPERMISSION.HELM_CHART_VERSION_LABEL.VALUE.CREATE
|
||||
);
|
||||
let hasDownloadHelmChartVersionPermission =
|
||||
this.userPermissionService.getPermission(
|
||||
projectId,
|
||||
USERSTATICPERMISSION.HELM_CHART_VERSION.KEY,
|
||||
USERSTATICPERMISSION.HELM_CHART_VERSION.VALUE.READ
|
||||
);
|
||||
let hasDeleteHelmChartVersionPermission =
|
||||
this.userPermissionService.getPermission(
|
||||
projectId,
|
||||
USERSTATICPERMISSION.HELM_CHART_VERSION.KEY,
|
||||
USERSTATICPERMISSION.HELM_CHART_VERSION.VALUE.DELETE
|
||||
);
|
||||
forkJoin(
|
||||
hasAddRemoveHelmChartVersionPermission,
|
||||
hasDownloadHelmChartVersionPermission,
|
||||
hasDeleteHelmChartVersionPermission
|
||||
).subscribe(
|
||||
permissions => {
|
||||
this.hasAddRemoveHelmChartVersionPermission =
|
||||
permissions[0] as boolean;
|
||||
this.hasDownloadHelmChartVersionPermission =
|
||||
permissions[1] as boolean;
|
||||
this.hasDeleteHelmChartVersionPermission =
|
||||
permissions[2] as boolean;
|
||||
},
|
||||
error => this.errorHandlerEntity.error(error)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
<div>
|
||||
<div class="breadcrumb">
|
||||
<span class="back-icon"><</span>
|
||||
<a href="javascript:void(0)" (click)="gotoProjectList()">{{
|
||||
'SIDE_NAV.PROJECTS' | translate
|
||||
}}</a>
|
||||
<span class="back-icon"><</span>
|
||||
<a href="javascript:void(0)" (click)="gotoChartList()">{{
|
||||
projectName
|
||||
}}</a>
|
||||
</div>
|
||||
<hbr-helm-chart-version
|
||||
[projectId]="projectId"
|
||||
[projectName]="projectName"
|
||||
[chartName]="chartName"
|
||||
[roleName]="roleName"
|
||||
[hasSignedIn]="hasSignedIn"
|
||||
(versionClickEvt)="onVersionClick($event)"
|
||||
(backEvt)="gotoChartList()">
|
||||
</hbr-helm-chart-version>
|
||||
</div>
|
@ -1,16 +0,0 @@
|
||||
.breadcrumb a {
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
color: #007cbb;
|
||||
font-size: 16px;
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.breadcrumb {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.back-icon {
|
||||
color: #007cbb;
|
||||
font-size: 16px;
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ClarityModule } from '@clr/angular';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||
import { TranslateModule, TranslateService } from '@ngx-translate/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { SessionService } from '../../../../../shared/services/session.service';
|
||||
import { ListChartVersionsComponent } from './list-chart-versions.component';
|
||||
|
||||
describe('ListChartVersionsComponent', () => {
|
||||
let component: ListChartVersionsComponent;
|
||||
let fixture: ComponentFixture<ListChartVersionsComponent>;
|
||||
let fakeSessionService = {
|
||||
getCurrentUser: function () {
|
||||
return 'admin';
|
||||
},
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ListChartVersionsComponent],
|
||||
imports: [ClarityModule, TranslateModule.forRoot()],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
providers: [
|
||||
TranslateService,
|
||||
{
|
||||
provide: ActivatedRoute,
|
||||
useValue: {
|
||||
snapshot: {
|
||||
parent: {
|
||||
params: {
|
||||
id: 1,
|
||||
},
|
||||
data: null,
|
||||
},
|
||||
params: {
|
||||
chart: 'chart',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{ provide: Router, useValue: null },
|
||||
{ provide: SessionService, useValue: fakeSessionService },
|
||||
],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ListChartVersionsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -1,57 +0,0 @@
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
import { Project } from '../../../project';
|
||||
import { SessionUser } from '../../../../../shared/entities/session-user';
|
||||
import { SessionService } from '../../../../../shared/services/session.service';
|
||||
|
||||
@Component({
|
||||
selector: 'list-chart-version',
|
||||
templateUrl: './list-chart-versions.component.html',
|
||||
styleUrls: ['./list-chart-versions.component.scss'],
|
||||
})
|
||||
export class ListChartVersionsComponent implements OnInit {
|
||||
loading = false;
|
||||
|
||||
projectId: number;
|
||||
projectName: string;
|
||||
chartName: string;
|
||||
roleName: string;
|
||||
|
||||
hasSignedIn: boolean;
|
||||
currentUser: SessionUser;
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private session: SessionService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
// Get projectId from router-guard params snapshot.
|
||||
this.projectId = +this.route.snapshot.parent.params['id'];
|
||||
this.chartName = this.route.snapshot.params['chart'];
|
||||
// Get current user from registered resolver.
|
||||
this.currentUser = this.session.getCurrentUser();
|
||||
let resolverData = this.route.snapshot.parent.data;
|
||||
if (resolverData) {
|
||||
let project = <Project>resolverData['projectResolver'];
|
||||
this.roleName = project.role_name;
|
||||
this.projectName = project.name;
|
||||
}
|
||||
}
|
||||
|
||||
onVersionClick(version: string) {
|
||||
this.router.navigateByUrl(`${this.router.url}/${version}`);
|
||||
}
|
||||
|
||||
gotoProjectList() {
|
||||
this.router.navigateByUrl('/harbor/projects');
|
||||
}
|
||||
|
||||
gotoChartList() {
|
||||
this.router.navigateByUrl(
|
||||
`/harbor/projects/${this.projectId}/helm-charts`
|
||||
);
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
// Copyright Project Harbor Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// 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 { NgModule } from '@angular/core';
|
||||
import { ListChartsComponent } from './list-charts.component';
|
||||
import { HelmChartComponent } from './list-charts-detail/helm-chart.component';
|
||||
import { SharedModule } from '../../../../shared/shared.module';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: ListChartsComponent,
|
||||
},
|
||||
];
|
||||
@NgModule({
|
||||
imports: [SharedModule, RouterModule.forChild(routes)],
|
||||
declarations: [ListChartsComponent, HelmChartComponent],
|
||||
})
|
||||
export class HelmChartListModule {}
|
@ -1,290 +0,0 @@
|
||||
<div>
|
||||
<div class="row chart-tool">
|
||||
<div class="toolbar">
|
||||
<div class="row flex-items-xs-right option-right rightPos">
|
||||
<div class="flex-xs-middle">
|
||||
<hbr-filter
|
||||
[withDivider]="true"
|
||||
filterPlaceholder="{{
|
||||
'HELM_CHART.FILTER_FOR_CHARTS' | translate
|
||||
}}"
|
||||
[currentValue]="lastFilteredChartName"
|
||||
(filterEvt)="updateFilterValue($event)"></hbr-filter>
|
||||
<span
|
||||
class="card-btn"
|
||||
(click)="showCard(true)"
|
||||
(mouseenter)="mouseEnter('card')"
|
||||
(mouseleave)="mouseLeave('card')">
|
||||
<clr-icon
|
||||
[ngClass]="{
|
||||
'is-highlight': isCardView || isHovering('card')
|
||||
}"
|
||||
shape="view-cards"></clr-icon>
|
||||
</span>
|
||||
<span
|
||||
class="list-btn"
|
||||
(click)="showCard(false)"
|
||||
(mouseenter)="mouseEnter('list')"
|
||||
(mouseleave)="mouseLeave('list')">
|
||||
<clr-icon
|
||||
[ngClass]="{
|
||||
'is-highlight':
|
||||
!isCardView || isHovering('list')
|
||||
}"
|
||||
shape="view-list"></clr-icon>
|
||||
</span>
|
||||
<span class="filter-divider"></span>
|
||||
<span class="refresh-btn" (click)="refresh()">
|
||||
<clr-icon shape="refresh"></clr-icon>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div
|
||||
*ngIf="!isCardView"
|
||||
class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
|
||||
<clr-datagrid
|
||||
(clrDgRefresh)="clrLoad($event)"
|
||||
[clrDgLoading]="loading"
|
||||
[(clrDgSelected)]="selectedRows">
|
||||
<clr-dg-action-bar>
|
||||
<button
|
||||
type="button"
|
||||
id="helm-chart-upload"
|
||||
class="btn btn-secondary"
|
||||
[disabled]="!hasUploadHelmChartsPermission"
|
||||
(click)="onChartUpload()">
|
||||
<clr-icon shape="upload" size="16"></clr-icon
|
||||
>{{ 'HELM_CHART.UPLOAD' | translate }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-secondary"
|
||||
[disabled]="
|
||||
!hasDeleteHelmChartsPermission ||
|
||||
selectedRows.length < 1
|
||||
"
|
||||
(click)="openChartDeleteModal()">
|
||||
<clr-icon shape="trash" size="16"></clr-icon
|
||||
>{{ 'BUTTON.DELETE' | translate }}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-secondary"
|
||||
[disabled]="
|
||||
!hasDownloadHelmChartsPermission ||
|
||||
selectedRows.length !== 1
|
||||
"
|
||||
(click)="downloadLatestVersion()">
|
||||
<clr-icon shape="download" size="16"></clr-icon
|
||||
>{{ 'HELM_CHART.DOWNLOAD' | translate }}
|
||||
</button>
|
||||
</clr-dg-action-bar>
|
||||
<clr-dg-column>{{
|
||||
'HELM_CHART.NAME' | translate
|
||||
}}</clr-dg-column>
|
||||
<clr-dg-column>{{
|
||||
'HELM_CHART.STATUS' | translate
|
||||
}}</clr-dg-column>
|
||||
<clr-dg-column>{{
|
||||
'HELM_CHART.CHARTVERSIONS' | translate
|
||||
}}</clr-dg-column>
|
||||
<clr-dg-column>{{
|
||||
'HELM_CHART.CREATED' | translate
|
||||
}}</clr-dg-column>
|
||||
<clr-dg-placeholder>{{
|
||||
'HELM_CHART.PLACEHOLDER' | translate
|
||||
}}</clr-dg-placeholder>
|
||||
<clr-dg-row
|
||||
*clrDgItems="let chart of charts"
|
||||
[clrDgItem]="chart">
|
||||
<clr-dg-cell>
|
||||
<span class="list-img">
|
||||
<img
|
||||
class="size-24 margin-right-12"
|
||||
[src]="
|
||||
chart.icon ? chart.icon : chartDefaultIcon
|
||||
"
|
||||
(error)="getDefaultIcon(chart)" />
|
||||
</span>
|
||||
<a
|
||||
href="javascript:void(0)"
|
||||
(click)="onChartClick(chart)"
|
||||
>{{ chart.name }}</a
|
||||
>
|
||||
</clr-dg-cell>
|
||||
<clr-dg-cell class="table-center">{{
|
||||
getStatusString(chart) | translate
|
||||
}}</clr-dg-cell>
|
||||
<clr-dg-cell class="table-center">{{
|
||||
chart.total_versions
|
||||
}}</clr-dg-cell>
|
||||
<clr-dg-cell class="table-center">{{
|
||||
chart.created | harborDatetime
|
||||
}}</clr-dg-cell>
|
||||
</clr-dg-row>
|
||||
<clr-dg-footer>
|
||||
<clr-dg-pagination
|
||||
#pagination
|
||||
[clrDgPageSize]="pageSize"
|
||||
[clrDgTotalItems]="totalCount">
|
||||
<clr-dg-page-size [clrPageSizeOptions]="[15, 25, 50]">{{
|
||||
'PAGINATION.PAGE_SIZE' | translate
|
||||
}}</clr-dg-page-size>
|
||||
<span *ngIf="totalCount">
|
||||
{{ pagination.firstItem + 1 }} -
|
||||
{{ pagination.lastItem + 1 }}
|
||||
{{ 'HELM_CHART.OF' | translate }}
|
||||
</span>
|
||||
{{ totalCount }} {{ 'HELM_CHART.ITEMS' | translate }}
|
||||
</clr-dg-pagination>
|
||||
</clr-dg-footer>
|
||||
</clr-datagrid>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="isCardView" class="row card-container version-position">
|
||||
<div *ngFor="let item of charts" class="chart-card">
|
||||
<a
|
||||
let
|
||||
i="index;"
|
||||
class="card clickable"
|
||||
(click)="onChartClick(item)">
|
||||
<div class="card-header">
|
||||
<div class="card-icon">
|
||||
<img
|
||||
class="size-60"
|
||||
[src]="item.icon ? item.icon : chartDefaultIcon"
|
||||
(error)="getDefaultIcon(item)" />
|
||||
</div>
|
||||
<div class="card-title">{{ item.name }}</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<div class="row flex-items-xs-between">
|
||||
<div>
|
||||
<span class="version-text">{{
|
||||
item.total_versions
|
||||
}}</span>
|
||||
<label
|
||||
class="card-label"
|
||||
*ngIf="item.total_versions !== 1"
|
||||
>{{ 'HELM_CHART.CHARTVERSIONS' | translate }}
|
||||
</label>
|
||||
<label
|
||||
class="card-label"
|
||||
*ngIf="item.total_versions === 1"
|
||||
>{{ 'HELM_CHART.VERSION' | translate }}
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<span
|
||||
class="label"
|
||||
[class.label-danger]="item.deprecated"
|
||||
[class.label-success]="!item.deprecated"
|
||||
>{{ getStatusString(item) | translate }}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div *ngIf="loading" class="center-x">
|
||||
<span class="vertical-helper"></span>
|
||||
<span class="spinner"></span>
|
||||
</div>
|
||||
</div>
|
||||
<confirmation-dialog
|
||||
#confirmationDialog
|
||||
(confirmAction)="confirmDeletion($event)"></confirmation-dialog>
|
||||
<clr-modal
|
||||
[(clrModalOpen)]="isUploadModalOpen"
|
||||
[clrModalStaticBackdrop]="true"
|
||||
[clrModalClosable]="false">
|
||||
<h3 class="modal-title">
|
||||
{{ 'HELM_CHART.UPLOAD_TITLE' | translate | titlecase }}
|
||||
</h3>
|
||||
<div class="modal-body">
|
||||
<form
|
||||
#chartUploadForm="ngForm"
|
||||
clrForm
|
||||
enctype="multipart/form-data">
|
||||
<div class="clr-form-control">
|
||||
<label
|
||||
class="filename-label clr-control-label clr-col-md-3">
|
||||
{{ 'HELM_CHART.CHART_FILE' | translate }}</label
|
||||
>
|
||||
<div class="clr-input-wrapper">
|
||||
<input
|
||||
class="filename-input clr-input"
|
||||
type="text"
|
||||
placeholder="{{
|
||||
this.chartFile?.name || 'BUTTON.NO_FILE'
|
||||
| translate
|
||||
}}"
|
||||
disabled />
|
||||
<label
|
||||
for="chart"
|
||||
class="btn btn-secondary file-browser-btn"
|
||||
>{{ 'BUTTON.BROWSE' | translate }}
|
||||
</label>
|
||||
<input
|
||||
class="file-input"
|
||||
type="file"
|
||||
id="chart"
|
||||
name="chart"
|
||||
ngModel
|
||||
(change)="onChartFileChangeEvent($event)" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="clr-form-control mb-10">
|
||||
<label
|
||||
class="filename-label clr-control-label clr-col-md-3">
|
||||
{{ 'HELM_CHART.CHART_PROV' | translate }}
|
||||
</label>
|
||||
<div class="clr-input-wrapper">
|
||||
<input
|
||||
class="filename-input clr-input"
|
||||
type="text"
|
||||
placeholder="{{
|
||||
this.provFile?.name || 'BUTTON.NO_FILE'
|
||||
| translate
|
||||
}}"
|
||||
disabled />
|
||||
<label
|
||||
for="prov"
|
||||
class="btn btn-secondary file-browser-btn"
|
||||
>{{ 'BUTTON.BROWSE' | translate }}
|
||||
</label>
|
||||
<input
|
||||
class="file-input"
|
||||
type="file"
|
||||
id="prov"
|
||||
name="prov"
|
||||
ngModel
|
||||
(change)="onProvFileChangeEvent($event)" />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button
|
||||
class="btn btn-secondary"
|
||||
[disabled]="isUploading"
|
||||
(click)="cancelUpload()">
|
||||
<span>{{ 'BUTTON.CANCEL' | translate }}</span>
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-primary"
|
||||
id="upload-chart"
|
||||
[disabled]="isUploading"
|
||||
(click)="upload()">
|
||||
<span>{{ 'HELM_CHART.UPLOAD' | translate }}</span>
|
||||
<span *ngIf="isUploading" class="spinner spinner-inline">
|
||||
Loading...
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</clr-modal>
|
||||
</div>
|
@ -1,148 +0,0 @@
|
||||
@import "../../../../../shared/mixin";
|
||||
|
||||
$size24:24px;
|
||||
$size60:60px;
|
||||
|
||||
@mixin flex-center {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.chart-tool {
|
||||
position: relative;
|
||||
margin-top: 5px;
|
||||
|
||||
.toolbar {
|
||||
overflow: hidden;
|
||||
/* stylelint-disable */
|
||||
.rightPos {
|
||||
@include grid-right-top-pos;
|
||||
|
||||
margin-top: 20px;
|
||||
|
||||
.filter-divider {
|
||||
display: inline-block;
|
||||
height: 16px;
|
||||
width: 1px;
|
||||
padding-top: 12px;
|
||||
padding-bottom: 12px;
|
||||
position: relative;
|
||||
top: 9px;
|
||||
margin-right: 6px;
|
||||
margin-left: 6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card-container {
|
||||
margin-top: 40px;
|
||||
|
||||
.chart-card {
|
||||
width: 200px;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
.card-icon {
|
||||
@include flex-center;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
@include text-overflow;
|
||||
|
||||
text-align:center;
|
||||
margin:15px;
|
||||
}
|
||||
}
|
||||
|
||||
.card-footer {
|
||||
background-color:#d7d7d7;
|
||||
|
||||
.version-text {
|
||||
font-size:1.1rem;
|
||||
}
|
||||
|
||||
.card-label {
|
||||
width: 60px;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.vertical-helper {
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.size-24 {
|
||||
width:$size24;
|
||||
height:$size24;
|
||||
}
|
||||
|
||||
.size-60 {
|
||||
height:$size60;
|
||||
max-width:100%;
|
||||
}
|
||||
|
||||
.margin-right-12 {
|
||||
margin-right:12px;
|
||||
}
|
||||
|
||||
.file-input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.filename-span {
|
||||
@include text-overflow;
|
||||
|
||||
display: inline-block;
|
||||
width: 50%;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
clr-modal {
|
||||
.filename-label {
|
||||
padding-top: 9px;
|
||||
}
|
||||
|
||||
.filename-input {
|
||||
margin-top: 12px;
|
||||
width: 68%;
|
||||
}
|
||||
|
||||
.file-browser-btn {
|
||||
margin-left: 15px;
|
||||
max-width: 34%;
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
clr-icon {
|
||||
margin-right: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.mb-10 {
|
||||
margin-bottom:10px;
|
||||
}
|
||||
|
||||
.table-center {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.center-x {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
top: 2.5rem;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.version-position {
|
||||
position: relative;
|
||||
}
|
@ -1,104 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { TranslateModule, TranslateService } from '@ngx-translate/core';
|
||||
import { HelmChartComponent } from './helm-chart.component';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||
import { ClarityModule } from '@clr/angular';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { of } from 'rxjs';
|
||||
import { HelmChartService } from '../../helm-chart-detail/helm-chart.service';
|
||||
import { ErrorHandler } from '../../../../../shared/units/error-handler';
|
||||
import {
|
||||
SystemInfoService,
|
||||
UserPermissionService,
|
||||
} from '../../../../../shared/services';
|
||||
import { OperationService } from '../../../../../shared/components/operation/operation.service';
|
||||
|
||||
describe('HelmChartComponent', () => {
|
||||
let component: HelmChartComponent;
|
||||
let fixture: ComponentFixture<HelmChartComponent>;
|
||||
const mockErrorHandler = null;
|
||||
const mockSystemInfoService = {
|
||||
getSystemInfo: () => {
|
||||
return of({
|
||||
with_notary: false,
|
||||
with_admiral: false,
|
||||
admiral_endpoint: '',
|
||||
auth_mode: 'oidc_auth',
|
||||
registry_url: 'nightly-oidc.harbor.io',
|
||||
external_url: 'https://nightly-oidc.harbor.io',
|
||||
project_creation_restriction: 'everyone',
|
||||
self_registration: false,
|
||||
has_ca_root: false,
|
||||
harbor_version: 'dev',
|
||||
registry_storage_provider_name: 'filesystem',
|
||||
read_only: false,
|
||||
with_chartmuseum: true,
|
||||
notification_enable: true,
|
||||
});
|
||||
},
|
||||
};
|
||||
const mockHelmChartService = {
|
||||
getChartVersions() {
|
||||
return of([
|
||||
{
|
||||
name: 'string',
|
||||
home: 'string',
|
||||
sources: [],
|
||||
version: 'string',
|
||||
description: 'string',
|
||||
keywords: [],
|
||||
maintainers: [],
|
||||
engine: 'string',
|
||||
icon: 'string',
|
||||
appVersion: 'string',
|
||||
apiVersion: 'string',
|
||||
urls: [],
|
||||
created: 'string',
|
||||
digest: 'string',
|
||||
labels: [],
|
||||
},
|
||||
]);
|
||||
},
|
||||
getHelmCharts() {
|
||||
return of([]);
|
||||
},
|
||||
};
|
||||
const mockUserPermissionService = {
|
||||
getPermission() {
|
||||
return of(true);
|
||||
},
|
||||
};
|
||||
const mockOperationService = {
|
||||
publishInfo: () => {
|
||||
return of([]);
|
||||
},
|
||||
};
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
imports: [ClarityModule, TranslateModule.forRoot(), FormsModule],
|
||||
declarations: [HelmChartComponent],
|
||||
providers: [
|
||||
TranslateService,
|
||||
{ provide: ErrorHandler, useValue: mockErrorHandler },
|
||||
{ provide: SystemInfoService, useValue: mockSystemInfoService },
|
||||
{ provide: HelmChartService, useValue: mockHelmChartService },
|
||||
{
|
||||
provide: UserPermissionService,
|
||||
useValue: mockUserPermissionService,
|
||||
},
|
||||
{ provide: OperationService, useValue: mockOperationService },
|
||||
],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(HelmChartComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -1,392 +0,0 @@
|
||||
import {
|
||||
Component,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnInit,
|
||||
Output,
|
||||
ViewChild,
|
||||
} from '@angular/core';
|
||||
import { NgForm } from '@angular/forms';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { forkJoin, Observable, throwError as observableThrowError } from 'rxjs';
|
||||
import { catchError, finalize, map } from 'rxjs/operators';
|
||||
import { HelmChartItem } from '../../helm-chart-detail/helm-chart.interface.service';
|
||||
import { HelmChartService } from '../../helm-chart-detail/helm-chart.service';
|
||||
import {
|
||||
State,
|
||||
SystemInfo,
|
||||
SystemInfoService,
|
||||
UserPermissionService,
|
||||
USERSTATICPERMISSION,
|
||||
} from '../../../../../shared/services';
|
||||
import {
|
||||
downloadFile,
|
||||
getPageSizeFromLocalStorage,
|
||||
PageSizeMapKeys,
|
||||
setPageSizeToLocalStorage,
|
||||
} from '../../../../../shared/units/utils';
|
||||
import { ErrorHandler } from '../../../../../shared/units/error-handler';
|
||||
import { OperationService } from '../../../../../shared/components/operation/operation.service';
|
||||
import {
|
||||
operateChanges,
|
||||
OperateInfo,
|
||||
OperationState,
|
||||
} from '../../../../../shared/components/operation/operate';
|
||||
import {
|
||||
ConfirmationButtons,
|
||||
ConfirmationState,
|
||||
ConfirmationTargets,
|
||||
DefaultHelmIcon,
|
||||
Roles,
|
||||
} from '../../../../../shared/entities/shared.const';
|
||||
import { errorHandler } from '../../../../../shared/units/shared.utils';
|
||||
import { ConfirmationDialogComponent } from '../../../../../shared/components/confirmation-dialog';
|
||||
import { ConfirmationMessage } from '../../../../global-confirmation-dialog/confirmation-message';
|
||||
import { ConfirmationAcknowledgement } from '../../../../global-confirmation-dialog/confirmation-state-message';
|
||||
import { ClrDatagridStateInterface } from '@clr/angular';
|
||||
|
||||
@Component({
|
||||
selector: 'hbr-helm-chart',
|
||||
templateUrl: './helm-chart.component.html',
|
||||
styleUrls: ['./helm-chart.component.scss'],
|
||||
})
|
||||
export class HelmChartComponent implements OnInit {
|
||||
signedCon: { [key: string]: any | string[] } = {};
|
||||
@Input() projectId: number;
|
||||
@Input() projectName = 'unknown';
|
||||
@Input() urlPrefix: string;
|
||||
@Input() hasSignedIn: boolean;
|
||||
@Input() projectRoleID = Roles.OTHER;
|
||||
@Output() chartClickEvt = new EventEmitter<any>();
|
||||
@Output() chartDownloadEve = new EventEmitter<string>();
|
||||
@Input() chartDefaultIcon: string = DefaultHelmIcon;
|
||||
|
||||
lastFilteredChartName: string;
|
||||
charts: HelmChartItem[] = [];
|
||||
chartsCopy: HelmChartItem[] = [];
|
||||
systemInfo: SystemInfo;
|
||||
selectedRows: HelmChartItem[] = [];
|
||||
loading = true;
|
||||
|
||||
// For Upload
|
||||
isUploading = false;
|
||||
isUploadModalOpen = false;
|
||||
provFile: File;
|
||||
chartFile: File;
|
||||
|
||||
// For View swtich
|
||||
isCardView: boolean;
|
||||
cardHover = false;
|
||||
listHover = false;
|
||||
|
||||
pageSize: number = getPageSizeFromLocalStorage(
|
||||
PageSizeMapKeys.HELM_CHART_COMPONENT
|
||||
);
|
||||
currentPage = 1;
|
||||
totalCount = 0;
|
||||
currentState: State;
|
||||
|
||||
@ViewChild('chartUploadForm') uploadForm: NgForm;
|
||||
|
||||
@ViewChild('confirmationDialog')
|
||||
confirmationDialog: ConfirmationDialogComponent;
|
||||
hasUploadHelmChartsPermission: boolean;
|
||||
hasDownloadHelmChartsPermission: boolean;
|
||||
hasDeleteHelmChartsPermission: boolean;
|
||||
constructor(
|
||||
private errorHandlerEntity: ErrorHandler,
|
||||
private translateService: TranslateService,
|
||||
private systemInfoService: SystemInfoService,
|
||||
private helmChartService: HelmChartService,
|
||||
private userPermissionService: UserPermissionService,
|
||||
private operationService: OperationService
|
||||
) {}
|
||||
|
||||
public get registryUrl(): string {
|
||||
return this.systemInfo ? this.systemInfo.registry_url : '';
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
// Get system info for tag views
|
||||
this.systemInfoService.getSystemInfo().subscribe(
|
||||
systemInfo => (this.systemInfo = systemInfo),
|
||||
error => this.errorHandlerEntity.error(error)
|
||||
);
|
||||
this.lastFilteredChartName = '';
|
||||
this.refresh();
|
||||
this.getHelmPermissionRule(this.projectId);
|
||||
}
|
||||
getHelmPermissionRule(projectId: number): void {
|
||||
let hasUploadHelmChartsPermission =
|
||||
this.userPermissionService.getPermission(
|
||||
projectId,
|
||||
USERSTATICPERMISSION.HELM_CHART.KEY,
|
||||
USERSTATICPERMISSION.HELM_CHART.VALUE.UPLOAD
|
||||
);
|
||||
let hasDownloadHelmChartsPermission =
|
||||
this.userPermissionService.getPermission(
|
||||
projectId,
|
||||
USERSTATICPERMISSION.HELM_CHART.KEY,
|
||||
USERSTATICPERMISSION.HELM_CHART.VALUE.DOWNLOAD
|
||||
);
|
||||
let hasDeleteHelmChartsPermission =
|
||||
this.userPermissionService.getPermission(
|
||||
projectId,
|
||||
USERSTATICPERMISSION.HELM_CHART.KEY,
|
||||
USERSTATICPERMISSION.HELM_CHART.VALUE.DELETE
|
||||
);
|
||||
forkJoin(
|
||||
hasUploadHelmChartsPermission,
|
||||
hasDownloadHelmChartsPermission,
|
||||
hasDeleteHelmChartsPermission
|
||||
).subscribe(
|
||||
permissions => {
|
||||
this.hasUploadHelmChartsPermission = permissions[0] as boolean;
|
||||
this.hasDownloadHelmChartsPermission =
|
||||
permissions[1] as boolean;
|
||||
this.hasDeleteHelmChartsPermission = permissions[2] as boolean;
|
||||
},
|
||||
error => this.errorHandlerEntity.error(error)
|
||||
);
|
||||
}
|
||||
updateFilterValue(value: string) {
|
||||
this.lastFilteredChartName = value;
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
refresh() {
|
||||
this.loading = true;
|
||||
this.selectedRows = [];
|
||||
this.helmChartService
|
||||
.getHelmCharts(this.projectName)
|
||||
.pipe(
|
||||
finalize(() => {
|
||||
this.loading = false;
|
||||
})
|
||||
)
|
||||
.subscribe(
|
||||
charts => {
|
||||
this.charts = charts.filter(x =>
|
||||
x.name.includes(this.lastFilteredChartName)
|
||||
);
|
||||
this.chartsCopy = charts.map(x => Object.assign({}, x));
|
||||
this.totalCount = charts.length;
|
||||
},
|
||||
err => {
|
||||
this.errorHandlerEntity.error(err);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
onChartClick(item: HelmChartItem) {
|
||||
this.chartClickEvt.emit(item.name);
|
||||
}
|
||||
|
||||
resetUploadForm() {
|
||||
this.chartFile = null;
|
||||
this.provFile = null;
|
||||
this.uploadForm.reset();
|
||||
}
|
||||
|
||||
onChartUpload() {
|
||||
this.resetUploadForm();
|
||||
this.isUploadModalOpen = true;
|
||||
}
|
||||
|
||||
cancelUpload() {
|
||||
this.resetUploadForm();
|
||||
this.isUploadModalOpen = false;
|
||||
}
|
||||
|
||||
upload() {
|
||||
if (!this.chartFile && !this.provFile) {
|
||||
return;
|
||||
}
|
||||
if (this.isUploading) {
|
||||
return;
|
||||
}
|
||||
this.isUploading = true;
|
||||
this.helmChartService
|
||||
.uploadChart(this.projectName, this.chartFile, this.provFile)
|
||||
.pipe(
|
||||
finalize(() => {
|
||||
this.isUploading = false;
|
||||
this.isUploadModalOpen = false;
|
||||
this.refresh();
|
||||
})
|
||||
)
|
||||
.subscribe(
|
||||
() => {
|
||||
this.translateService
|
||||
.get('HELM_CHART.FILE_UPLOADED')
|
||||
.subscribe(res => this.errorHandlerEntity.info(res));
|
||||
},
|
||||
err => this.errorHandlerEntity.error(err)
|
||||
);
|
||||
}
|
||||
|
||||
onChartFileChangeEvent(event) {
|
||||
if (event.target.files && event.target.files.length > 0) {
|
||||
this.chartFile = event.target.files[0];
|
||||
}
|
||||
}
|
||||
onProvFileChangeEvent(event) {
|
||||
if (event.target.files && event.target.files.length > 0) {
|
||||
this.provFile = event.target.files[0];
|
||||
}
|
||||
}
|
||||
|
||||
deleteChart(chartName: string): Observable<any> {
|
||||
let operateMsg = new OperateInfo();
|
||||
operateMsg.name = 'OPERATION.DELETE_CHART';
|
||||
operateMsg.data.id = chartName;
|
||||
operateMsg.state = OperationState.progressing;
|
||||
operateMsg.data.name = chartName;
|
||||
this.operationService.publishInfo(operateMsg);
|
||||
|
||||
return this.helmChartService
|
||||
.deleteHelmChart(this.projectName, chartName)
|
||||
.pipe(
|
||||
map(() => operateChanges(operateMsg, OperationState.success)),
|
||||
catchError(error => {
|
||||
const message = errorHandler(error);
|
||||
this.translateService
|
||||
.get(message)
|
||||
.subscribe(res =>
|
||||
operateChanges(
|
||||
operateMsg,
|
||||
OperationState.failure,
|
||||
res
|
||||
)
|
||||
);
|
||||
return observableThrowError(error);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
deleteCharts(charts: HelmChartItem[]) {
|
||||
if (charts && charts.length < 1) {
|
||||
return;
|
||||
}
|
||||
let chartsDelete$ = charts.map(chart => this.deleteChart(chart.name));
|
||||
forkJoin(chartsDelete$)
|
||||
.pipe(
|
||||
finalize(() => {
|
||||
this.refresh();
|
||||
this.selectedRows = [];
|
||||
})
|
||||
)
|
||||
.subscribe(
|
||||
() => {},
|
||||
error => {
|
||||
this.errorHandlerEntity.error(error);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
downloadLatestVersion(evt?: Event, item?: HelmChartItem) {
|
||||
if (evt) {
|
||||
evt.stopPropagation();
|
||||
}
|
||||
let selectedChart: HelmChartItem;
|
||||
|
||||
if (item) {
|
||||
selectedChart = item;
|
||||
} else {
|
||||
// return if selected version less then 1
|
||||
if (this.selectedRows.length < 1) {
|
||||
return;
|
||||
}
|
||||
selectedChart = this.selectedRows[0];
|
||||
}
|
||||
if (!selectedChart) {
|
||||
return;
|
||||
}
|
||||
let filename = `charts/${selectedChart.name}-${selectedChart.latest_version}.tgz`;
|
||||
this.helmChartService
|
||||
.downloadChart(this.projectName, filename)
|
||||
.subscribe(
|
||||
res => {
|
||||
downloadFile(res);
|
||||
},
|
||||
error => {
|
||||
this.errorHandlerEntity.error(error);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
openChartDeleteModal() {
|
||||
let chartNames = this.selectedRows.map(chart => chart.name).join(',');
|
||||
let message = new ConfirmationMessage(
|
||||
'HELM_CHART.DELETE_CHART_VERSION_TITLE',
|
||||
'HELM_CHART.DELETE_CHART_VERSION',
|
||||
chartNames,
|
||||
this.selectedRows,
|
||||
ConfirmationTargets.HELM_CHART,
|
||||
ConfirmationButtons.DELETE_CANCEL
|
||||
);
|
||||
this.confirmationDialog.open(message);
|
||||
}
|
||||
|
||||
confirmDeletion(message: ConfirmationAcknowledgement) {
|
||||
if (
|
||||
message &&
|
||||
message.source === ConfirmationTargets.HELM_CHART &&
|
||||
message.state === ConfirmationState.CONFIRMED
|
||||
) {
|
||||
let charts = message.data;
|
||||
this.deleteCharts(charts);
|
||||
}
|
||||
}
|
||||
|
||||
showCard(cardView: boolean) {
|
||||
if (this.isCardView === cardView) {
|
||||
return;
|
||||
}
|
||||
this.isCardView = cardView;
|
||||
}
|
||||
|
||||
mouseEnter(itemName: string) {
|
||||
if (itemName === 'card') {
|
||||
this.cardHover = true;
|
||||
} else {
|
||||
this.listHover = true;
|
||||
}
|
||||
}
|
||||
|
||||
mouseLeave(itemName: string) {
|
||||
if (itemName === 'card') {
|
||||
this.cardHover = false;
|
||||
} else {
|
||||
this.listHover = false;
|
||||
}
|
||||
}
|
||||
|
||||
isHovering(itemName: string) {
|
||||
if (itemName === 'card') {
|
||||
return this.cardHover;
|
||||
} else {
|
||||
return this.listHover;
|
||||
}
|
||||
}
|
||||
|
||||
getDefaultIcon(chart: HelmChartItem) {
|
||||
chart.icon = this.chartDefaultIcon;
|
||||
}
|
||||
|
||||
getStatusString(chart: HelmChartItem) {
|
||||
if (chart.deprecated) {
|
||||
return 'HELM_CHART.DEPRECATED';
|
||||
} else {
|
||||
return 'HELM_CHART.ACTIVE';
|
||||
}
|
||||
}
|
||||
clrLoad(state: ClrDatagridStateInterface) {
|
||||
if (state?.page?.size) {
|
||||
setPageSizeToLocalStorage(
|
||||
PageSizeMapKeys.HELM_CHART_COMPONENT,
|
||||
state.page.size
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
<hbr-helm-chart
|
||||
[projectId]="projectId"
|
||||
[projectName]="projectName"
|
||||
[urlPrefix]="urlPrefix"
|
||||
[hasSignedIn]="hasSignedIn"
|
||||
[projectRoleID]="project_member_role_id"
|
||||
(chartClickEvt)="onChartClick($event)">
|
||||
</hbr-helm-chart>
|
@ -1,53 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { SessionService } from '../../../../shared/services/session.service';
|
||||
import { ListChartsComponent } from './list-charts.component';
|
||||
import { SharedTestingModule } from '../../../../shared/shared.module';
|
||||
|
||||
describe('ListChartsComponent', () => {
|
||||
let component: ListChartsComponent;
|
||||
let fixture: ComponentFixture<ListChartsComponent>;
|
||||
let fakeSessionService = {
|
||||
getCurrentUser: function () {
|
||||
return 'admin';
|
||||
},
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ListChartsComponent],
|
||||
imports: [SharedTestingModule],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
providers: [
|
||||
{
|
||||
provide: ActivatedRoute,
|
||||
useValue: {
|
||||
snapshot: {
|
||||
parent: {
|
||||
parent: {
|
||||
params: {
|
||||
id: 1,
|
||||
},
|
||||
data: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{ provide: Router, useValue: null },
|
||||
{ provide: SessionService, useValue: fakeSessionService },
|
||||
],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ListChartsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -1,44 +0,0 @@
|
||||
import { Project } from '../../project';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
|
||||
import { SessionService } from '../../../../shared/services/session.service';
|
||||
import { SessionUser } from '../../../../shared/entities/session-user';
|
||||
|
||||
@Component({
|
||||
selector: 'project-list-charts',
|
||||
templateUrl: './list-charts.component.html',
|
||||
styleUrls: ['./list-charts.component.scss'],
|
||||
})
|
||||
export class ListChartsComponent implements OnInit {
|
||||
projectId: number;
|
||||
|
||||
projectName: string;
|
||||
urlPrefix: string;
|
||||
hasSignedIn: boolean;
|
||||
project_member_role_id: number;
|
||||
currentUser: SessionUser;
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
private router: Router,
|
||||
private session: SessionService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
// Get projectId from router-guard params snapshot.
|
||||
this.projectId = +this.route.snapshot.parent.parent.params['id'];
|
||||
// Get current user from registered resolver.
|
||||
this.currentUser = this.session.getCurrentUser();
|
||||
let resolverData = this.route.snapshot.parent.parent.data;
|
||||
if (resolverData) {
|
||||
let project = <Project>resolverData['projectResolver'];
|
||||
this.projectName = project.name;
|
||||
this.project_member_role_id = project.current_user_role_id;
|
||||
}
|
||||
}
|
||||
|
||||
onChartClick(chartName: string) {
|
||||
this.router.navigateByUrl(`${this.router.url}/${chartName}/versions`);
|
||||
}
|
||||
}
|
@ -64,7 +64,6 @@ export class ProjectDetailComponent
|
||||
roleName: string;
|
||||
projectId: number;
|
||||
hasProjectReadPermission: boolean;
|
||||
hasHelmChartsListPermission: boolean;
|
||||
hasRepositoryListPermission: boolean;
|
||||
hasMemberListPermission: boolean;
|
||||
hasLabelListPermission: boolean;
|
||||
@ -91,13 +90,6 @@ export class ProjectDetailComponent
|
||||
showTabName: 'PROJECT_DETAIL.REPOSITORIES',
|
||||
permissions: () => this.hasRepositoryListPermission,
|
||||
},
|
||||
{
|
||||
linkName: 'helm-charts',
|
||||
tabLinkInOverflow: false,
|
||||
showTabName: 'PROJECT_DETAIL.HELMCHART',
|
||||
permissions: () =>
|
||||
this.withHelmChart && this.hasHelmChartsListPermission,
|
||||
},
|
||||
{
|
||||
linkName: 'members',
|
||||
tabLinkInOverflow: false,
|
||||
@ -109,9 +101,7 @@ export class ProjectDetailComponent
|
||||
tabLinkInOverflow: false,
|
||||
showTabName: 'PROJECT_DETAIL.LABELS',
|
||||
permissions: () =>
|
||||
this.hasLabelListPermission &&
|
||||
this.hasLabelCreatePermission &&
|
||||
!this.withAdmiral,
|
||||
this.hasLabelListPermission && this.hasLabelCreatePermission,
|
||||
},
|
||||
{
|
||||
linkName: 'scanner',
|
||||
@ -272,13 +262,6 @@ export class ProjectDetailComponent
|
||||
USERSTATICPERMISSION.REPOSITORY.VALUE.LIST
|
||||
)
|
||||
);
|
||||
permissionsList.push(
|
||||
this.userPermissionService.getPermission(
|
||||
projectId,
|
||||
USERSTATICPERMISSION.HELM_CHART.KEY,
|
||||
USERSTATICPERMISSION.HELM_CHART.VALUE.LIST
|
||||
)
|
||||
);
|
||||
permissionsList.push(
|
||||
this.userPermissionService.getPermission(
|
||||
projectId,
|
||||
@ -345,7 +328,6 @@ export class ProjectDetailComponent
|
||||
this.hasMemberListPermission,
|
||||
this.hasLabelListPermission,
|
||||
this.hasRepositoryListPermission,
|
||||
this.hasHelmChartsListPermission,
|
||||
this.hasRobotListPermission,
|
||||
this.hasLabelCreatePermission,
|
||||
this.hasTagRetentionPermission,
|
||||
@ -383,14 +365,6 @@ export class ProjectDetailComponent
|
||||
return this.sessionService.getCurrentUser() != null;
|
||||
}
|
||||
|
||||
public get withAdmiral(): boolean {
|
||||
return this.appConfigService.getConfig().with_admiral;
|
||||
}
|
||||
|
||||
public get withHelmChart(): boolean {
|
||||
return this.appConfigService.getConfig().with_chartmuseum;
|
||||
}
|
||||
|
||||
backToProject(): void {
|
||||
if (window.sessionStorage) {
|
||||
window.sessionStorage.setItem('fromDetails', 'true');
|
||||
|
@ -51,20 +51,6 @@ const routes: Routes = [
|
||||
m => m.RepositoryModule
|
||||
),
|
||||
},
|
||||
{
|
||||
path: 'helm-charts',
|
||||
canActivate: [MemberPermissionGuard],
|
||||
data: {
|
||||
permissionParam: {
|
||||
resource: USERSTATICPERMISSION.HELM_CHART.KEY,
|
||||
action: USERSTATICPERMISSION.HELM_CHART.VALUE.LIST,
|
||||
},
|
||||
},
|
||||
loadChildren: () =>
|
||||
import(
|
||||
'./helm-chart/helm-chart-list/helm-chart-list.module'
|
||||
).then(m => m.HelmChartListModule),
|
||||
},
|
||||
{
|
||||
path: 'members',
|
||||
canActivate: [MemberPermissionGuard],
|
||||
|
@ -23,7 +23,6 @@ export class Project {
|
||||
update_time: Date;
|
||||
current_user_role_id: number;
|
||||
repo_count: number;
|
||||
chart_count: number;
|
||||
has_project_admin_role: boolean;
|
||||
is_member: boolean;
|
||||
role_name: string;
|
||||
|
@ -1,5 +1,3 @@
|
||||
import { HelmChartMaintainer } from '../../../helm-chart/helm-chart-detail/helm-chart.interface.service';
|
||||
|
||||
export class ArtifactBuildHistory {
|
||||
created: Date;
|
||||
created_by: string;
|
||||
@ -9,22 +7,6 @@ export interface ArtifactDependency {
|
||||
version: string;
|
||||
repository: string;
|
||||
}
|
||||
export interface ArtifactSummary {
|
||||
name: string;
|
||||
home: string;
|
||||
sources: string[];
|
||||
version: string;
|
||||
description: string;
|
||||
keywords: string[];
|
||||
maintainers: HelmChartMaintainer[];
|
||||
engine: string;
|
||||
icon: string;
|
||||
appVersion: string;
|
||||
urls: string[];
|
||||
created?: string;
|
||||
digest: string;
|
||||
}
|
||||
|
||||
export interface Addition {
|
||||
type: string;
|
||||
data?: object;
|
||||
|
@ -170,61 +170,6 @@
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="card clickable"
|
||||
*ngIf="hasReadChartPermission && withHelmChart">
|
||||
<div class="card-header">
|
||||
<div>{{ 'PROJECT_DETAIL.HELMCHART' | translate }}</div>
|
||||
<div class="clr-row number">
|
||||
{{
|
||||
summaryInformation?.chart_count
|
||||
? summaryInformation?.chart_count
|
||||
: 0
|
||||
}}
|
||||
</div>
|
||||
<div class="clr-row">
|
||||
<div class="clr-col-4 column">
|
||||
{{ 'HELM_CHART.NAME' | translate }}
|
||||
</div>
|
||||
<div class="clr-col-2 column">
|
||||
{{ 'HELM_CHART.STATUS' | translate }}
|
||||
</div>
|
||||
<div class="clr-col-2 column">
|
||||
{{ 'HELM_CHART.CHARTVERSIONS' | translate }}
|
||||
</div>
|
||||
<div class="clr-col-4 column">
|
||||
{{ 'HELM_CHART.CREATED' | translate }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-block">
|
||||
<div class="clr-row" *ngFor="let chart of charts">
|
||||
<div class="clr-col-4 ellipsis chart-name">
|
||||
<img
|
||||
class="size-24 mr-5px"
|
||||
[src]="chart.icon ? chart.icon : chartDefaultIcon"
|
||||
(error)="getDefaultIcon(chart)" />
|
||||
<a
|
||||
href="javascript:void(0)"
|
||||
(click)="onChartClick(chart.name)"
|
||||
>{{ chart.name }}</a
|
||||
>
|
||||
</div>
|
||||
<div class="clr-col-2">
|
||||
{{ getStatusString(chart) | translate }}
|
||||
</div>
|
||||
<div class="clr-col-2">{{ chart.total_versions }}</div>
|
||||
<div class="clr-col-4 ellipsis">
|
||||
{{ chart.created | harborDatetime: 'short' }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<button class="btn btn-link" (click)="goToCharts()">
|
||||
{{ 'SUMMARY.SEE_ALL' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card clickable" *ngIf="showProjectMemberInfo">
|
||||
<div class="card-header no-underline">
|
||||
<div>{{ 'PROJECT_DETAIL.USERS' | translate }}</div>
|
||||
|
@ -140,7 +140,6 @@ describe('SummaryComponent', () => {
|
||||
it('should show two cards', async () => {
|
||||
component.summaryInformation = mockedSummaryInformation;
|
||||
component.isCardView = true;
|
||||
component.hasReadChartPermission = true;
|
||||
fixture.detectChanges();
|
||||
await fixture.whenStable();
|
||||
const cards = fixture.nativeElement.querySelectorAll('.card');
|
||||
|
@ -9,7 +9,6 @@ import {
|
||||
} from '../../../shared/services';
|
||||
import { ErrorHandler } from '../../../shared/units/error-handler';
|
||||
import {
|
||||
DefaultHelmIcon,
|
||||
FALSE_STR,
|
||||
PROJECT_SUMMARY_CARD_VIEW_LOCALSTORAGE_KEY,
|
||||
TRUE_STR,
|
||||
@ -17,8 +16,6 @@ import {
|
||||
import { RepositoryService } from '../../../../../ng-swagger-gen/services/repository.service';
|
||||
import { Project } from '../../../../../ng-swagger-gen/models/project';
|
||||
import { Repository } from '../../../../../ng-swagger-gen/models/repository';
|
||||
import { HelmChartItem } from '../helm-chart/helm-chart-detail/helm-chart.interface.service';
|
||||
import { HelmChartService } from '../helm-chart/helm-chart-detail/helm-chart.service';
|
||||
|
||||
@Component({
|
||||
selector: 'summary',
|
||||
@ -28,7 +25,6 @@ import { HelmChartService } from '../helm-chart/helm-chart-detail/helm-chart.ser
|
||||
export class SummaryComponent implements OnInit {
|
||||
showProjectMemberInfo: boolean = false;
|
||||
hasReadRepoPermission: boolean = false;
|
||||
hasReadChartPermission: boolean = false;
|
||||
projectId: number;
|
||||
projectName: string;
|
||||
summaryInformation: any;
|
||||
@ -37,8 +33,6 @@ export class SummaryComponent implements OnInit {
|
||||
cardHover: boolean = false;
|
||||
listHover: boolean = false;
|
||||
repos: Repository[] = [];
|
||||
charts: HelmChartItem[] = [];
|
||||
chartDefaultIcon: string = DefaultHelmIcon;
|
||||
constructor(
|
||||
private projectService: ProjectService,
|
||||
private userPermissionService: UserPermissionService,
|
||||
@ -46,8 +40,7 @@ export class SummaryComponent implements OnInit {
|
||||
private appConfigService: AppConfigService,
|
||||
private route: ActivatedRoute,
|
||||
private repoService: RepositoryService,
|
||||
private router: Router,
|
||||
private helmChartService: HelmChartService
|
||||
private router: Router
|
||||
) {
|
||||
if (localStorage) {
|
||||
if (
|
||||
@ -83,17 +76,12 @@ export class SummaryComponent implements OnInit {
|
||||
resource: USERSTATICPERMISSION.REPOSITORY.KEY,
|
||||
action: USERSTATICPERMISSION.REPOSITORY.VALUE.LIST,
|
||||
},
|
||||
{
|
||||
resource: USERSTATICPERMISSION.HELM_CHART.KEY,
|
||||
action: USERSTATICPERMISSION.HELM_CHART.VALUE.LIST,
|
||||
},
|
||||
];
|
||||
this.userPermissionService
|
||||
.hasProjectPermissions(this.projectId, permissions)
|
||||
.subscribe((results: Array<boolean>) => {
|
||||
this.showProjectMemberInfo = results[0];
|
||||
this.hasReadRepoPermission = results[1];
|
||||
this.hasReadChartPermission = results[2];
|
||||
});
|
||||
this.projectService.getProjectSummary(this.projectId).subscribe(
|
||||
res => {
|
||||
@ -107,10 +95,6 @@ export class SummaryComponent implements OnInit {
|
||||
this.getDataForCardView();
|
||||
}
|
||||
}
|
||||
public get withHelmChart(): boolean {
|
||||
return this.appConfigService.getConfig().with_chartmuseum;
|
||||
}
|
||||
|
||||
showCard(cardView: boolean) {
|
||||
if (this.isCardView === cardView) {
|
||||
return;
|
||||
@ -159,7 +143,6 @@ export class SummaryComponent implements OnInit {
|
||||
}
|
||||
getDataForCardView() {
|
||||
this.getTop4Repos();
|
||||
this.getTop4Charts();
|
||||
}
|
||||
getTop4Repos() {
|
||||
if (this.hasReadRepoPermission) {
|
||||
@ -174,17 +157,6 @@ export class SummaryComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
}
|
||||
getTop4Charts() {
|
||||
if (this.hasReadChartPermission) {
|
||||
this.helmChartService
|
||||
.getHelmCharts(this.projectName)
|
||||
.subscribe(res => {
|
||||
if (res && res.length) {
|
||||
this.charts = res.slice(0, 4);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
goIntoRepo(repoEvt: Repository): void {
|
||||
const linkUrl = [
|
||||
'harbor',
|
||||
@ -199,31 +171,6 @@ export class SummaryComponent implements OnInit {
|
||||
const linkUrl = ['harbor', 'projects', this.projectId, 'repositories'];
|
||||
this.router.navigate(linkUrl);
|
||||
}
|
||||
getDefaultIcon(chart: HelmChartItem) {
|
||||
chart.icon = this.chartDefaultIcon;
|
||||
}
|
||||
getStatusString(chart: HelmChartItem) {
|
||||
if (chart.deprecated) {
|
||||
return 'HELM_CHART.DEPRECATED';
|
||||
} else {
|
||||
return 'HELM_CHART.ACTIVE';
|
||||
}
|
||||
}
|
||||
onChartClick(chartName: string) {
|
||||
const linkUrl = [
|
||||
'harbor',
|
||||
'projects',
|
||||
this.projectId,
|
||||
'helm-charts',
|
||||
chartName,
|
||||
'versions',
|
||||
];
|
||||
this.router.navigate(linkUrl);
|
||||
}
|
||||
goToCharts() {
|
||||
const linkUrl = ['harbor', 'projects', this.projectId, 'helm-charts'];
|
||||
this.router.navigate(linkUrl);
|
||||
}
|
||||
goToMembers() {
|
||||
const linkUrl = ['harbor', 'projects', this.projectId, 'members'];
|
||||
this.router.navigate(linkUrl);
|
||||
|
@ -22,7 +22,6 @@ export enum RouteConfigId {
|
||||
const ShouldNotReuseRouteRegExps: RegExp[] = [
|
||||
/\/harbor\/projects\/(\d+)\/repositories$/,
|
||||
/\/harbor\/projects\/(\d+)\/repositories\/(\S+)\/artifacts-tab$/,
|
||||
/\/harbor\/projects\/(\d+)\/helm-charts\/(\S+)\/versions\/(\S+)/,
|
||||
];
|
||||
|
||||
function testRoute(url: string) {
|
||||
|
@ -47,7 +47,6 @@ describe('AppConfigService', () => {
|
||||
expect(req.request.method).toBe('GET');
|
||||
req.flush(systeminfo);
|
||||
expect(service.getConfig()).toEqual(systeminfo);
|
||||
expect(service.isIntegrationMode()).toBeFalsy();
|
||||
expect(service.isLdapMode()).toBeFalsy();
|
||||
expect(service.isHttpAuthMode()).toBeFalsy();
|
||||
expect(service.isOidcMode()).toBeFalsy();
|
||||
|
@ -62,14 +62,6 @@ export class AppConfigService {
|
||||
return this.configurations;
|
||||
}
|
||||
|
||||
public isIntegrationMode(): boolean {
|
||||
return (
|
||||
this.configurations &&
|
||||
this.configurations.with_admiral &&
|
||||
this.configurations.admiral_endpoint.trim() !== ''
|
||||
);
|
||||
}
|
||||
|
||||
public isLdapMode(): boolean {
|
||||
return (
|
||||
this.configurations &&
|
||||
|
@ -16,7 +16,6 @@ import { ClairDBStatus } from '../shared/services';
|
||||
|
||||
export class AppConfig {
|
||||
with_notary: boolean;
|
||||
with_admiral: boolean;
|
||||
with_trivy: boolean;
|
||||
admiral_endpoint: string;
|
||||
auth_mode: string;
|
||||
@ -29,13 +28,11 @@ export class AppConfig {
|
||||
next_scan_all: number;
|
||||
registry_storage_provider_name: string;
|
||||
read_only: boolean;
|
||||
with_chartmuseum: boolean;
|
||||
show_popular_repo: boolean;
|
||||
|
||||
constructor() {
|
||||
// Set default value
|
||||
this.with_notary = false;
|
||||
this.with_admiral = false;
|
||||
this.with_trivy = false;
|
||||
this.admiral_endpoint = '';
|
||||
this.auth_mode = 'db_auth';
|
||||
@ -51,7 +48,6 @@ export class AppConfig {
|
||||
this.next_scan_all = 0;
|
||||
this.registry_storage_provider_name = '';
|
||||
this.read_only = false;
|
||||
this.with_chartmuseum = false;
|
||||
this.show_popular_repo = false;
|
||||
}
|
||||
}
|
||||
|
@ -84,10 +84,6 @@ export class GlobalSearchComponent implements OnInit, OnDestroy {
|
||||
this.closeSub = this.searchTrigger.searchClearChan$.subscribe(clear => {
|
||||
this.searchTerm = '';
|
||||
});
|
||||
|
||||
if (this.appConfigService.isIntegrationMode()) {
|
||||
this.placeholderText = 'GLOBAL_SEARCH.PLACEHOLDER_VIC';
|
||||
}
|
||||
// init _searchTerm from queryParams
|
||||
this._searchTerm = this.activatedRoute.snapshot.queryParams[SEARCH_KEY];
|
||||
if (this._searchTerm) {
|
||||
|
@ -20,10 +20,5 @@
|
||||
<list-repository-ro
|
||||
[repositories]="searchResults.repository"></list-repository-ro>
|
||||
</div>
|
||||
<div *ngIf="withHelmChart" id="chart-results">
|
||||
<h2>{{ 'HELM_CHART.HELMCHARTS' | translate }}</h2>
|
||||
<list-chart-version-ro
|
||||
[charts]="searchResults.chart"></list-chart-version-ro>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -50,8 +50,7 @@ export class SearchResultComponent implements OnInit, OnDestroy {
|
||||
constructor(
|
||||
private search: GlobalSearchService,
|
||||
private msgHandler: MessageHandlerService,
|
||||
private searchTrigger: SearchTriggerService,
|
||||
private appConfigService: AppConfigService
|
||||
private searchTrigger: SearchTriggerService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
@ -61,9 +60,6 @@ export class SearchResultComponent implements OnInit, OnDestroy {
|
||||
if (term === '') {
|
||||
this.searchResults.project = [];
|
||||
this.searchResults.repository = [];
|
||||
if (this.withHelmChart) {
|
||||
this.searchResults.chart = [];
|
||||
}
|
||||
}
|
||||
return !!(term && term.trim());
|
||||
}),
|
||||
@ -116,11 +112,6 @@ export class SearchResultComponent implements OnInit, OnDestroy {
|
||||
src.repository.forEach(repo =>
|
||||
res.repository.push(Object.assign({}, repo))
|
||||
);
|
||||
if (this.withHelmChart) {
|
||||
src.chart.forEach(chart =>
|
||||
res.chart.push(JSON.parse(JSON.stringify(chart)))
|
||||
);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -157,9 +148,6 @@ export class SearchResultComponent implements OnInit, OnDestroy {
|
||||
if (!term || term.trim() === '') {
|
||||
this.searchResults.project = [];
|
||||
this.searchResults.repository = [];
|
||||
if (this.withHelmChart) {
|
||||
this.searchResults.chart = [];
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Do nothing if search is ongoing
|
||||
@ -188,7 +176,4 @@ export class SearchResultComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
);
|
||||
}
|
||||
get withHelmChart(): boolean {
|
||||
return this.appConfigService.getConfig().with_chartmuseum;
|
||||
}
|
||||
}
|
||||
|
@ -12,17 +12,14 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
import { Project } from '../../../base/project/project';
|
||||
import { HelmChartSearchResultItem } from '../../../base/project/helm-chart/helm-chart-detail/helm-chart.interface.service';
|
||||
import { Repository } from '../../../../../ng-swagger-gen/models/repository';
|
||||
|
||||
export class SearchResults {
|
||||
constructor() {
|
||||
this.project = [];
|
||||
this.repository = [];
|
||||
this.chart = [];
|
||||
}
|
||||
|
||||
project: Project[];
|
||||
repository: Repository[];
|
||||
chart: HelmChartSearchResultItem[];
|
||||
}
|
||||
|
@ -1,40 +0,0 @@
|
||||
<clr-datagrid>
|
||||
<clr-dg-column>{{ 'HELM_CHART.NAME' | translate }}</clr-dg-column>
|
||||
<clr-dg-column>{{ 'HELM_CHART.VERSION' | translate }}</clr-dg-column>
|
||||
<clr-dg-column>{{ 'HELM_CHART.STATUS' | translate }}</clr-dg-column>
|
||||
<clr-dg-column>{{ 'HELM_CHART.MAINTAINERS' | translate }}</clr-dg-column>
|
||||
<clr-dg-column>{{ 'HELM_CHART.CREATED' | translate }}</clr-dg-column>
|
||||
<clr-dg-placeholder>{{
|
||||
'HELM_CHART.NO_VERSION_PLACEHOLDER' | translate
|
||||
}}</clr-dg-placeholder>
|
||||
<clr-dg-row *clrDgItems="let chart of charts" [clrDgItem]="chart">
|
||||
<clr-dg-cell>
|
||||
<a
|
||||
href="javascript:void(0)"
|
||||
(click)="gotoChartVersion(chart.Chart)"
|
||||
>{{ chart.Name }}</a
|
||||
>
|
||||
</clr-dg-cell>
|
||||
<clr-dg-cell>{{ chart.Chart.version }}</clr-dg-cell>
|
||||
<clr-dg-cell>{{
|
||||
getStatusString(chart.Chart) | translate
|
||||
}}</clr-dg-cell>
|
||||
<clr-dg-cell>{{
|
||||
getMaintainerString(chart.Chart.maintainers)
|
||||
| translate: getMaintainerTranslateInfo(chart.Chart.maintainers)
|
||||
}}</clr-dg-cell>
|
||||
<clr-dg-cell>{{ chart.Chart.created | harborDatetime }}</clr-dg-cell>
|
||||
</clr-dg-row>
|
||||
<clr-dg-footer>
|
||||
<clr-dg-pagination
|
||||
#pagination
|
||||
[clrDgPageSize]="5"
|
||||
[clrDgTotalItems]="charts?.length">
|
||||
<span *ngIf="charts?.length">
|
||||
{{ pagination.firstItem + 1 }} - {{ pagination.lastItem + 1 }}
|
||||
{{ 'HELM_CHART.OF' | translate }}
|
||||
</span>
|
||||
{{ charts?.length }} {{ 'HELM_CHART.ITEMS' | translate }}
|
||||
</clr-dg-pagination>
|
||||
</clr-dg-footer>
|
||||
</clr-datagrid>
|
@ -1,46 +0,0 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ListChartVersionRoComponent } from './list-chart-version-ro.component';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||
import { of } from 'rxjs';
|
||||
import { SearchTriggerService } from '../global-search/search-trigger.service';
|
||||
import { ProjectService } from '../../services';
|
||||
import { SharedTestingModule } from '../../shared.module';
|
||||
|
||||
describe('ListChartVersionRoComponent', () => {
|
||||
let component: ListChartVersionRoComponent;
|
||||
let fixture: ComponentFixture<ListChartVersionRoComponent>;
|
||||
const mockSearchTriggerService = {
|
||||
closeSearch: () => {},
|
||||
};
|
||||
const mockProjectService = {
|
||||
listProjects: () => {
|
||||
return of({
|
||||
body: [],
|
||||
});
|
||||
},
|
||||
};
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||
imports: [SharedTestingModule],
|
||||
declarations: [ListChartVersionRoComponent],
|
||||
providers: [
|
||||
{ provide: ProjectService, useValue: mockProjectService },
|
||||
{
|
||||
provide: SearchTriggerService,
|
||||
useValue: mockSearchTriggerService,
|
||||
},
|
||||
],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ListChartVersionRoComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -1,75 +0,0 @@
|
||||
import { Router } from '@angular/router';
|
||||
import { Component, Input, ChangeDetectionStrategy } from '@angular/core';
|
||||
import {
|
||||
HelmChartSearchResultItem,
|
||||
HelmChartVersion,
|
||||
HelmChartMaintainer,
|
||||
} from '../../../base/project/helm-chart/helm-chart-detail/helm-chart.interface.service';
|
||||
import { SearchTriggerService } from '../global-search/search-trigger.service';
|
||||
import { ProjectService } from '../../services';
|
||||
|
||||
@Component({
|
||||
selector: 'list-chart-version-ro',
|
||||
templateUrl: './list-chart-version-ro.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ListChartVersionRoComponent {
|
||||
@Input() charts: HelmChartSearchResultItem[];
|
||||
|
||||
constructor(
|
||||
private searchTrigger: SearchTriggerService,
|
||||
private projectService: ProjectService,
|
||||
private router: Router
|
||||
) {}
|
||||
|
||||
getStatusString(chart: HelmChartVersion) {
|
||||
if (chart.deprecated) {
|
||||
return 'HELM_CHART.DEPRECATED';
|
||||
} else {
|
||||
return 'HELM_CHART.ACTIVE';
|
||||
}
|
||||
}
|
||||
|
||||
getMaintainerString(maintainers: HelmChartMaintainer[]) {
|
||||
if (!maintainers || maintainers.length < 1) {
|
||||
return '';
|
||||
}
|
||||
|
||||
let maintainer_string = maintainers[0].name;
|
||||
if (maintainers.length > 1) {
|
||||
maintainer_string = 'HELM_CHART.OTHER_MAINTAINERS';
|
||||
}
|
||||
return maintainer_string;
|
||||
}
|
||||
|
||||
getMaintainerTranslateInfo(maintainers: HelmChartMaintainer[]) {
|
||||
if (!maintainers || maintainers.length < 1) {
|
||||
return {};
|
||||
}
|
||||
let name = maintainers[0].name;
|
||||
let number = maintainers.length;
|
||||
return { name: name, number: number };
|
||||
}
|
||||
|
||||
gotoChartVersion(chartVersion: HelmChartVersion) {
|
||||
this.searchTrigger.closeSearch(true);
|
||||
let [projectName, chartName] = chartVersion.name.split('/');
|
||||
this.projectService.listProjects(projectName).subscribe(res => {
|
||||
let projects = res.body || [];
|
||||
if (projects || projects.length >= 1) {
|
||||
let linkUrl = [
|
||||
'harbor',
|
||||
'projects',
|
||||
projects[0].project_id,
|
||||
'helm-charts',
|
||||
chartName,
|
||||
'versions',
|
||||
chartVersion.version,
|
||||
];
|
||||
this.router.navigate(linkUrl);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -15,24 +15,10 @@
|
||||
}}</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="header-nav">
|
||||
<a href="{{ admiralLink }}" class="nav-link" *ngIf="isIntegrationMode"
|
||||
><span class="nav-text">{{ 'APP_TITLE.MGMT' | translate }}</span></a
|
||||
>
|
||||
<a
|
||||
href="javascript:void(0)"
|
||||
(click)="registryAction()"
|
||||
routerLink="/harbor"
|
||||
class="active nav-link"
|
||||
*ngIf="isIntegrationMode"
|
||||
><span class="nav-text">{{ 'APP_TITLE.REG' | translate }}</span></a
|
||||
>
|
||||
</div>
|
||||
|
||||
<global-search></global-search>
|
||||
<div class="header-actions">
|
||||
<clr-dropdown
|
||||
class="dropdown-lang dropdown bottom-left"
|
||||
*ngIf="!isIntegrationMode">
|
||||
<clr-dropdown class="dropdown-lang dropdown bottom-left">
|
||||
<button class="nav-icon nav-icon-width" clrDropdownToggle>
|
||||
<clr-icon shape="world" class="icon-left"></clr-icon>
|
||||
<span class="currentLocale">{{ currentLang }}</span>
|
||||
@ -49,9 +35,7 @@
|
||||
>
|
||||
</clr-dropdown-menu>
|
||||
</clr-dropdown>
|
||||
<clr-dropdown
|
||||
class="dropdown-locale dropdown bottom-left"
|
||||
*ngIf="!isIntegrationMode">
|
||||
<clr-dropdown class="dropdown-locale dropdown bottom-left">
|
||||
<button class="nav-icon nav-icon-width" clrDropdownToggle>
|
||||
<clr-icon shape="date" class="icon-left"></clr-icon>
|
||||
<span class="currentLocale">{{
|
||||
|
@ -9,9 +9,6 @@ import { MessageHandlerService } from '../../services/message-handler.service';
|
||||
import { SearchTriggerService } from '../global-search/search-trigger.service';
|
||||
import { SkinableConfig } from '../../../services/skinable-config.service';
|
||||
import { SharedTestingModule } from '../../shared.module';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { DeFaultLang } from '../../entities/shared.const';
|
||||
import { of } from 'rxjs';
|
||||
|
||||
describe('NavigatorComponent', () => {
|
||||
let component: TestComponentWrapperComponent;
|
||||
|
@ -84,10 +84,6 @@ export class NavigatorComponent implements OnInit {
|
||||
this.translateClarityComponents();
|
||||
}
|
||||
this.selectedDatetimeRendering = getDatetimeRendering();
|
||||
if (this.appConfigService.isIntegrationMode()) {
|
||||
this.appTitle = 'APP_TITLE.VIC';
|
||||
}
|
||||
|
||||
if (this.appConfigService.getConfig().read_only) {
|
||||
this.msgHandler.handleReadOnly();
|
||||
}
|
||||
@ -126,7 +122,10 @@ export class NavigatorComponent implements OnInit {
|
||||
}
|
||||
|
||||
public get currentLang(): string {
|
||||
return LANGUAGES[this.selectedLang][0] as string;
|
||||
if (this.selectedLang) {
|
||||
return LANGUAGES[this.selectedLang][0] as string;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public get currentDatetimeRendering(): string {
|
||||
@ -136,11 +135,6 @@ export class NavigatorComponent implements OnInit {
|
||||
public get admiralLink(): string {
|
||||
return this.appConfigService.getAdmiralEndpoint(window.location.href);
|
||||
}
|
||||
|
||||
public get isIntegrationMode(): boolean {
|
||||
return this.appConfigService.isIntegrationMode();
|
||||
}
|
||||
|
||||
public get canDownloadCert(): boolean {
|
||||
return (
|
||||
this.session.getCurrentUser() &&
|
||||
|
@ -48,8 +48,6 @@ export const enum ConfirmationTargets {
|
||||
CONFIG,
|
||||
CONFIG_ROUTE,
|
||||
CONFIG_TAB,
|
||||
HELM_CHART,
|
||||
HELM_CHART_VERSION,
|
||||
STOP_EXECUTIONS,
|
||||
SCANNER,
|
||||
REPLICATION,
|
||||
|
@ -38,26 +38,11 @@ export class ModeGuard implements CanActivate, CanActivateChild {
|
||||
): Observable<boolean> | boolean {
|
||||
// Show the right sign-in page for different modes
|
||||
return new Observable(observer => {
|
||||
if (this.appConfigService.isIntegrationMode()) {
|
||||
if (state.url.startsWith(CommonRoutes.SIGN_IN)) {
|
||||
this.router.navigate(
|
||||
[CommonRoutes.EMBEDDED_SIGN_IN],
|
||||
route.queryParams
|
||||
);
|
||||
observer.next(false);
|
||||
} else {
|
||||
observer.next(true);
|
||||
}
|
||||
if (state.url.startsWith(CommonRoutes.EMBEDDED_SIGN_IN)) {
|
||||
this.router.navigate([CommonRoutes.SIGN_IN], route.queryParams);
|
||||
observer.next(false);
|
||||
} else {
|
||||
if (state.url.startsWith(CommonRoutes.EMBEDDED_SIGN_IN)) {
|
||||
this.router.navigate(
|
||||
[CommonRoutes.SIGN_IN],
|
||||
route.queryParams
|
||||
);
|
||||
observer.next(false);
|
||||
} else {
|
||||
observer.next(true);
|
||||
}
|
||||
observer.next(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -112,31 +112,6 @@ export const USERSTATICPERMISSION = {
|
||||
DELETE: 'delete',
|
||||
},
|
||||
},
|
||||
HELM_CHART: {
|
||||
KEY: 'helm-chart',
|
||||
VALUE: {
|
||||
UPLOAD: 'create',
|
||||
DOWNLOAD: 'read',
|
||||
DELETE: 'delete',
|
||||
LIST: 'list',
|
||||
},
|
||||
},
|
||||
HELM_CHART_VERSION: {
|
||||
KEY: 'helm-chart-version',
|
||||
VALUE: {
|
||||
DELETE: 'delete',
|
||||
LIST: 'list',
|
||||
CREATE: 'create',
|
||||
READ: 'read',
|
||||
},
|
||||
},
|
||||
HELM_CHART_VERSION_LABEL: {
|
||||
KEY: 'helm-chart-version-label',
|
||||
VALUE: {
|
||||
CREATE: 'create',
|
||||
DELETE: 'delete',
|
||||
},
|
||||
},
|
||||
ROBOT: {
|
||||
KEY: 'robot',
|
||||
VALUE: {
|
||||
|
@ -62,17 +62,12 @@ import { LabelComponent } from './components/label/label.component';
|
||||
import { LabelSignPostComponent } from './components/label/label-signpost/label-signpost.component';
|
||||
import { LabelPieceComponent } from './components/label/label-piece/label-piece.component';
|
||||
import { CreateEditLabelComponent } from './components/label/create-edit-label/create-edit-label.component';
|
||||
import { ListChartVersionRoComponent } from './components/list-chart-version-ro/list-chart-version-ro.component';
|
||||
import { DatePickerComponent } from './components/datetime-picker/datetime-picker.component';
|
||||
import {
|
||||
EndpointDefaultService,
|
||||
EndpointService,
|
||||
} from './services/endpoint.service';
|
||||
import { ImageNameInputComponent } from './components/image-name-input/image-name-input.component';
|
||||
import {
|
||||
HelmChartDefaultService,
|
||||
HelmChartService,
|
||||
} from '../base/project/helm-chart/helm-chart-detail/helm-chart.service';
|
||||
import { MessageHandlerService } from './services/message-handler.service';
|
||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
@ -142,7 +137,6 @@ ClarityIcons.add({
|
||||
LabelPieceComponent,
|
||||
CreateEditLabelComponent,
|
||||
CronScheduleComponent,
|
||||
ListChartVersionRoComponent,
|
||||
DatePickerComponent,
|
||||
ImageNameInputComponent,
|
||||
HarborDatetimePipe,
|
||||
@ -182,7 +176,6 @@ ClarityIcons.add({
|
||||
LabelPieceComponent,
|
||||
CreateEditLabelComponent,
|
||||
CronScheduleComponent,
|
||||
ListChartVersionRoComponent,
|
||||
DatePickerComponent,
|
||||
ImageNameInputComponent,
|
||||
HarborDatetimePipe,
|
||||
@ -198,7 +191,6 @@ ClarityIcons.add({
|
||||
provide: ScanningResultService,
|
||||
useClass: ScanningResultDefaultService,
|
||||
},
|
||||
{ provide: HelmChartService, useClass: HelmChartDefaultService },
|
||||
],
|
||||
})
|
||||
export class SharedModule {}
|
||||
|
@ -957,8 +957,6 @@ export enum PageSizeMapKeys {
|
||||
ARTIFACT_LIST_TAB_COMPONENT = 'ArtifactListTabComponent',
|
||||
ARTIFACT_TAGS_COMPONENT = 'ArtifactTagComponent',
|
||||
ARTIFACT_VUL_COMPONENT = 'ArtifactVulnerabilitiesComponent',
|
||||
HELM_CHART_COMPONENT = 'HelmChartComponent',
|
||||
CHART_VERSION_COMPONENT = 'ChartVersionComponent',
|
||||
MEMBER_COMPONENT = 'MemberComponent',
|
||||
LABEL_COMPONENT = 'LabelComponent',
|
||||
P2P_POLICY_COMPONENT = 'P2pPolicyComponent',
|
||||
|
@ -651,7 +651,6 @@
|
||||
"FLATTEN_LEVEL_TIP_1": "'Reduzierung um 1 Ebene'(Default): 'a/b/c/d/img' -> 'ns/b/c/d/img'",
|
||||
"FLATTEN_LEVEL_TIP_2": "'Reduzierung um 2 Ebenen': 'a/b/c/d/img' -> 'ns/c/d/img'",
|
||||
"FLATTEN_LEVEL_TIP_3": "'Reduzierung um 3 Ebenen': 'a/b/c/d/img' -> 'ns/d/img'",
|
||||
"NOTE": "Hinweis: Charts im Chartmuseum unterstützen lediglich eine Struktur mit zwei Komponenten im Pfad: 'a/chart'",
|
||||
"BANDWIDTH": "Bandbreite",
|
||||
"BANDWIDTH_ERROR_TIP": "Bitte -1 oder einen Integer-Wert größer als 0 eingeben",
|
||||
"BANDWIDTH_TOOLTIP": "Legt die maximale Netzwerkbandbreite für jede Ausführung fest. Bitte auf die Anzahl der parallelen Ausführungen achten. Für umbegrenzte Bandbreite, bitte -1 eingeben",
|
||||
@ -763,68 +762,9 @@
|
||||
"MARKDOWN": "Markdown wird unterstützt",
|
||||
"LAST_MODIFIED": "Geändert am"
|
||||
},
|
||||
"HELM_CHART": {
|
||||
"HELMCHARTS": "Charts",
|
||||
"CHARTVERSIONS": "Versionen",
|
||||
"UPLOAD_TITLE": "Chart Dateien hochladen",
|
||||
"CHART_FILE": "Chart Datei",
|
||||
"CHART_PROV": "Prov Datei",
|
||||
"DOWNLOAD": "Download",
|
||||
"SUMMARY": "Zusammenfassung",
|
||||
"DEPENDENCIES": "Dependencies",
|
||||
"VALUES": "Values",
|
||||
"OVERVIEW": "Übersicht",
|
||||
"HOME": "Home",
|
||||
"SRC_REPO": "Quell Repository",
|
||||
"CREATED": "Erstellt am",
|
||||
"MAINTAINERS": "Maintainers",
|
||||
"OTHER_MAINTAINERS": "{{ name }} und {{ number }} andere",
|
||||
"PULLS": "Pull Anzahl",
|
||||
"VERSION": "Version",
|
||||
"APP_VERSION": "Application Version",
|
||||
"INSTALL": "Installieren",
|
||||
"INSTALL_CHART": "Chart installieren",
|
||||
"NAME": "Name",
|
||||
"REPO": "Repository",
|
||||
"FILTER_FOR_CHARTS": "Filter Charts",
|
||||
"DELETE": "Löschen",
|
||||
"OF": "von",
|
||||
"VERSIONS": "Versionen",
|
||||
"IMAGES": "Images",
|
||||
"ENGINE": "Engine",
|
||||
"ACTION": "Aktion",
|
||||
"UPLOAD": "Hochladen",
|
||||
"DELETE_CHART_VERSION_TITLE": "Lösche Chart Version",
|
||||
"DELETE_CHART_VERSION": "Soll die Version {{param}} gelöscht werden?",
|
||||
"IMPORT": "Importieren",
|
||||
"EXPORT": "Exportieren",
|
||||
"ADD_REPO": "Repo hinzufügen",
|
||||
"SHOW_KV": "Key/Value-Paare",
|
||||
"SHOW_YAML": "YAML Datei",
|
||||
"PLACEHOLDER": "Es konnte kein Chart gefunden werden!",
|
||||
"NO_VERSION_PLACEHOLDER": "Es konnten keine Versionen gefunden werden!",
|
||||
"FILE_UPLOADED": "Datei erfolgreich hochgeladen",
|
||||
"SIGN": "Signieren",
|
||||
"SIGNED": "signiert",
|
||||
"UNSIGNED": "nicht signiert",
|
||||
"ITEMS": "Einträge",
|
||||
"NO_README": "Kein Readme für dieses Chart verfügbar.",
|
||||
"SECURITY": "Sicherheit",
|
||||
"ACTIVE": "Aktiv",
|
||||
"DEPRECATED": "Veraltet",
|
||||
"VERIFY_CHART": "Verifiziere Chart",
|
||||
"COMMAND": "Befehle",
|
||||
"PROV_FILE": "Prov Datei",
|
||||
"READY": "Bereit",
|
||||
"NOT_READY": "Nicht bereit",
|
||||
"LABELS": "Label",
|
||||
"ADD_LABEL_TO_CHART_VERSION": "Label zu dieser Chart-Version hinzufügen",
|
||||
"STATUS": "Status"
|
||||
},
|
||||
"SUMMARY": {
|
||||
"QUOTAS": "Beschränkungen",
|
||||
"PROJECT_REPOSITORY": "Repositories",
|
||||
"PROJECT_HELM_CHART": "Helm Chart",
|
||||
"PROJECT_MEMBER": "Mitglieder",
|
||||
"PROJECT_QUOTAS": "Beschränkungen",
|
||||
"ARTIFACT_COUNT": "Anzahl an Artefakten",
|
||||
@ -852,6 +792,7 @@
|
||||
"SUB_TITLE_SUFIX": "logs"
|
||||
},
|
||||
"CONFIG": {
|
||||
"SECURITY": "Security",
|
||||
"HISTORY": "Archiv",
|
||||
"TITLE": "Konfiguration",
|
||||
"AUTH": "Authentifizierung",
|
||||
@ -1636,8 +1577,6 @@
|
||||
"READ": "Lesen",
|
||||
"CREATE": "Erzeugen",
|
||||
"ARTIFACT": "Artefakt",
|
||||
"HELM": "Helm Chart",
|
||||
"HELM_VERSION": "Helm Chart Version",
|
||||
"ADD_ROBOT": "Robot-Zugang hinzufügen",
|
||||
"UPDATE_ROBOT": "Robot-Zugang aktualisieren",
|
||||
"UPDATE_ROBOT_SUCCESSFULLY": "Robot-Zugang aktualisieren erfolgreich",
|
||||
@ -1707,7 +1646,6 @@
|
||||
"STOP": "Stoppen",
|
||||
"LIST": "Auflisten",
|
||||
"REPOSITORY": "Repository",
|
||||
"HELM_LABEL": "Helm Chart Label",
|
||||
"EXPIRES_IN": "Läuft ab in",
|
||||
"EXPIRED": "Abgelaufen"
|
||||
},
|
||||
|
@ -651,7 +651,6 @@
|
||||
"FLATTEN_LEVEL_TIP_1": "'Flatten 1 Level'(Default): 'a/b/c/d/img' -> 'ns/b/c/d/img'",
|
||||
"FLATTEN_LEVEL_TIP_2": "'Flatten 2 Levels': 'a/b/c/d/img' -> 'ns/c/d/img'",
|
||||
"FLATTEN_LEVEL_TIP_3": "'Flatten 3 Levels': 'a/b/c/d/img' -> 'ns/d/img'",
|
||||
"NOTE": "Notes: The Chartmuseum Charts only support the repository structure with 2 path components: 'a/chart'",
|
||||
"BANDWIDTH": "Bandwidth",
|
||||
"BANDWIDTH_ERROR_TIP": "Please enter -1 or an integer greater than 0",
|
||||
"BANDWIDTH_TOOLTIP": "Set the maximum network bandwidth for each execution. Please pay attention to the number of concurrent executions. For unlimited bandwidth, please enter -1",
|
||||
@ -763,68 +762,9 @@
|
||||
"MARKDOWN": "Styling with Markdown is supported",
|
||||
"LAST_MODIFIED": "Last Modified Time"
|
||||
},
|
||||
"HELM_CHART": {
|
||||
"HELMCHARTS": "Charts",
|
||||
"CHARTVERSIONS": "Versions",
|
||||
"UPLOAD_TITLE": "Upload chart files",
|
||||
"CHART_FILE": "Chart File",
|
||||
"CHART_PROV": "Prov File",
|
||||
"DOWNLOAD": "Download",
|
||||
"SUMMARY": "Summary",
|
||||
"DEPENDENCIES": "Dependencies",
|
||||
"VALUES": "Values",
|
||||
"OVERVIEW": "Overview",
|
||||
"HOME": "Home",
|
||||
"SRC_REPO": "Source Repository",
|
||||
"CREATED": "Created Time",
|
||||
"MAINTAINERS": "Maintainers",
|
||||
"OTHER_MAINTAINERS": "{{ name }} and {{ number }} others",
|
||||
"PULLS": "Pull Count",
|
||||
"VERSION": "Version",
|
||||
"APP_VERSION": "Application Version",
|
||||
"INSTALL": "Install",
|
||||
"INSTALL_CHART": "Install Chart",
|
||||
"NAME": "Name",
|
||||
"REPO": "Repository",
|
||||
"FILTER_FOR_CHARTS": "Filter for charts",
|
||||
"DELETE": "Delete",
|
||||
"OF": "of",
|
||||
"VERSIONS": "versions",
|
||||
"IMAGES": "Images",
|
||||
"ENGINE": "Engine",
|
||||
"ACTION": "Action",
|
||||
"UPLOAD": "Upload",
|
||||
"DELETE_CHART_VERSION_TITLE": "Delete Chart Versions",
|
||||
"DELETE_CHART_VERSION": "Do you want to delete version {{param}}?",
|
||||
"IMPORT": "Import",
|
||||
"EXPORT": "Export",
|
||||
"ADD_REPO": "Add Repo",
|
||||
"SHOW_KV": "Key Value Pairs",
|
||||
"SHOW_YAML": "YAML File",
|
||||
"PLACEHOLDER": "We couldn't find any charts!",
|
||||
"NO_VERSION_PLACEHOLDER": "We couldn't find any versions!",
|
||||
"FILE_UPLOADED": "File upload successfully",
|
||||
"SIGN": "Sign",
|
||||
"SIGNED": "Signed",
|
||||
"UNSIGNED": "Unsigned",
|
||||
"ITEMS": "items",
|
||||
"NO_README": "No readme file provided by this chart.",
|
||||
"SECURITY": "Security",
|
||||
"ACTIVE": "Active",
|
||||
"DEPRECATED": "Deprecated",
|
||||
"VERIFY_CHART": "Verify Chart",
|
||||
"COMMAND": "Commands",
|
||||
"PROV_FILE": "Prov File",
|
||||
"READY": "Ready",
|
||||
"NOT_READY": "Not Ready",
|
||||
"LABELS": "Labels",
|
||||
"ADD_LABEL_TO_CHART_VERSION": "Add labels to this chart version",
|
||||
"STATUS": "Status"
|
||||
},
|
||||
"SUMMARY": {
|
||||
"QUOTAS": "quotas",
|
||||
"PROJECT_REPOSITORY": "Repositories",
|
||||
"PROJECT_HELM_CHART": "Helm Chart",
|
||||
"PROJECT_MEMBER": "Members",
|
||||
"PROJECT_QUOTAS": "Quotas",
|
||||
"ARTIFACT_COUNT": "Artifact count",
|
||||
@ -852,6 +792,7 @@
|
||||
"SUB_TITLE_SUFIX": "logs"
|
||||
},
|
||||
"CONFIG": {
|
||||
"SECURITY": "Security",
|
||||
"HISTORY": "History",
|
||||
"TITLE": "Configuration",
|
||||
"AUTH": "Authentication",
|
||||
@ -1636,8 +1577,6 @@
|
||||
"READ": "Read",
|
||||
"CREATE": "Create",
|
||||
"ARTIFACT": "Artifact",
|
||||
"HELM": "Helm Chart",
|
||||
"HELM_VERSION": "Helm Chart Version",
|
||||
"ADD_ROBOT": "Add Robot",
|
||||
"UPDATE_ROBOT": "Update Robot",
|
||||
"UPDATE_ROBOT_SUCCESSFULLY": "Updated robot successfully",
|
||||
@ -1707,7 +1646,6 @@
|
||||
"STOP": "Stop",
|
||||
"LIST": "List",
|
||||
"REPOSITORY": "Repository",
|
||||
"HELM_LABEL": "Helm Chart label",
|
||||
"EXPIRES_IN": "Expires in",
|
||||
"EXPIRED": "Expired"
|
||||
},
|
||||
|
@ -653,7 +653,6 @@
|
||||
"FLATTEN_LEVEL_TIP_1": "'Flatten 1 Level'(Default): 'a/b/c/d/img' -> 'ns/b/c/d/img'",
|
||||
"FLATTEN_LEVEL_TIP_2": "'Flatten 2 Levels': 'a/b/c/d/img' -> 'ns/c/d/img'",
|
||||
"FLATTEN_LEVEL_TIP_3": "'Flatten 3 Levels': 'a/b/c/d/img' -> 'ns/d/img'",
|
||||
"NOTE": "Notes: The Chartmuseum Charts only support the repository structure with 2 path components: 'a/chart'",
|
||||
"BANDWIDTH": "Bandwidth",
|
||||
"BANDWIDTH_ERROR_TIP": "Please enter -1 or an integer greater than 0",
|
||||
"BANDWIDTH_TOOLTIP": "Set the maximum network bandwidth for each execution. Please pay attention to the number of concurrent executions. For unlimited bandwidth, please enter -1",
|
||||
@ -765,68 +764,9 @@
|
||||
"MARKDOWN": "Styling with Markdown is supported",
|
||||
"LAST_MODIFIED": "Last Modified Time"
|
||||
},
|
||||
"HELM_CHART": {
|
||||
"HELMCHARTS": "Charts",
|
||||
"CHARTVERSIONS": "Versions",
|
||||
"UPLOAD_TITLE": "Upload chart files",
|
||||
"CHART_FILE": "Chart File",
|
||||
"CHART_PROV": "Prov File",
|
||||
"DOWNLOAD": "Download",
|
||||
"SUMMARY": "Summary",
|
||||
"DEPENDENCIES": "Dependencies",
|
||||
"VALUES": "Values",
|
||||
"OVERVIEW": "Overview",
|
||||
"HOME": "Home",
|
||||
"SRC_REPO": "Source Repository",
|
||||
"CREATED": "Created Time",
|
||||
"MAINTAINERS": "Maintainers",
|
||||
"OTHER_MAINTAINERS": "{{ name }} and {{ number }} others",
|
||||
"PULLS": "Pull Count",
|
||||
"VERSION": "Version",
|
||||
"APP_VERSION": "Application Version",
|
||||
"INSTALL": "Install",
|
||||
"INSTALL_CHART": "Install Chart",
|
||||
"NAME": "Name",
|
||||
"REPO": "Repository",
|
||||
"FILTER_FOR_CHARTS": "Filter for charts",
|
||||
"DELETE": "Delete",
|
||||
"OF": "of",
|
||||
"VERSIONS": "versions",
|
||||
"IMAGES": "Images",
|
||||
"ENGINE": "Engine",
|
||||
"ACTION": "Action",
|
||||
"UPLOAD": "Upload",
|
||||
"DELETE_CHART_VERSION_TITLE": "Delete Chart Versions",
|
||||
"DELETE_CHART_VERSION": "Do you want to delete version {{param}}?",
|
||||
"IMPORT": "Import",
|
||||
"EXPORT": "Export",
|
||||
"ADD_REPO": "Add Repo",
|
||||
"SHOW_KV": "Key Value Pairs",
|
||||
"SHOW_YAML": "YAML File",
|
||||
"PLACEHOLDER": "We couldn't find any charts!",
|
||||
"NO_VERSION_PLACEHOLDER": "We couldn't find any versions!",
|
||||
"FILE_UPLOADED": "File upload successfully",
|
||||
"SIGN": "Sign",
|
||||
"SIGNED": "Signed",
|
||||
"UNSIGNED": "Unsigned",
|
||||
"ITEMS": "items",
|
||||
"NO_README": "No readme file provided by this chart.",
|
||||
"SECURITY": "Security",
|
||||
"ACTIVE": "Active",
|
||||
"DEPRECATED": "Deprecated",
|
||||
"VERIFY_CHART": "Verify Chart",
|
||||
"COMMAND": "Commands",
|
||||
"PROV_FILE": "Prov File",
|
||||
"READY": "Ready",
|
||||
"NOT_READY": "Not Ready",
|
||||
"LABELS": "Labels",
|
||||
"ADD_LABEL_TO_CHART_VERSION": "Add labels to this chart version",
|
||||
"STATUS": "Status"
|
||||
},
|
||||
"SUMMARY": {
|
||||
"QUOTAS": "quotas",
|
||||
"PROJECT_REPOSITORY": "Repositories",
|
||||
"PROJECT_HELM_CHART": "Helm Chart",
|
||||
"PROJECT_MEMBER": "Members",
|
||||
"PROJECT_QUOTAS": "Quotas",
|
||||
"ARTIFACT_COUNT": "Artifact count",
|
||||
@ -854,6 +794,7 @@
|
||||
"SUB_TITLE_SUFIX": "logs"
|
||||
},
|
||||
"CONFIG": {
|
||||
"SECURITY": "Security",
|
||||
"HISTORY": "History",
|
||||
"TITLE": "Configuración",
|
||||
"AUTH": "Autentificación",
|
||||
@ -1635,8 +1576,6 @@
|
||||
"READ": "Read",
|
||||
"CREATE": "Create",
|
||||
"ARTIFACT": "Artifact",
|
||||
"HELM": "Helm Chart",
|
||||
"HELM_VERSION": "Helm Chart Version",
|
||||
"ADD_ROBOT": "Add Robot",
|
||||
"UPDATE_ROBOT": "Update Robot",
|
||||
"UPDATE_ROBOT_SUCCESSFULLY": "Updated robot successfully",
|
||||
@ -1706,7 +1645,6 @@
|
||||
"STOP": "Stop",
|
||||
"LIST": "List",
|
||||
"REPOSITORY": "Repository",
|
||||
"HELM_LABEL": "Helm Chart label",
|
||||
"EXPIRES_IN": "Expires in",
|
||||
"EXPIRED": "Expired"
|
||||
},
|
||||
|
@ -641,7 +641,6 @@
|
||||
"FLATTEN_LEVEL_TIP_1": "'Aplanissement sur 1 niveau'(Default): 'a/b/c/d/img' -> 'ns/b/c/d/img'",
|
||||
"FLATTEN_LEVEL_TIP_2": "'Aplanissement sur 2 niveaux': 'a/b/c/d/img' -> 'ns/c/d/img'",
|
||||
"FLATTEN_LEVEL_TIP_3": "'Aplanissement sur 3 niveaux': 'a/b/c/d/img' -> 'ns/d/img'",
|
||||
"NOTE": "Notes: Les graphiques Chartmuseum ne prennent en charge que la structure du référentiel avec 2 composants de chemin : `a/chart` ",
|
||||
"BANDWIDTH": "Bande passante",
|
||||
"BANDWIDTH_ERROR_TIP": "Veuillez saisir -1 ou un nombre entier supérieur à 0",
|
||||
"BANDWIDTH_TOOLTIP": "Définissez la bande passante réseau maximale pour chaque exécution. Veuillez faire attention au nombre d'exécutions simultanées. Pour une bande passante illimitée, veuillez entrer -1",
|
||||
@ -750,67 +749,9 @@
|
||||
"MARKDOWN": "La syntaxe Markdown est supportée",
|
||||
"LAST_MODIFIED": "Dernière modification"
|
||||
},
|
||||
"HELM_CHART": {
|
||||
"HELMCHARTS": "Charts",
|
||||
"CHARTVERSIONS": "Versions",
|
||||
"UPLOAD_TITLE": "Téléverser des charts",
|
||||
"CHART_FILE": "Fichier de Chart",
|
||||
"CHART_PROV": "Prov File",
|
||||
"DOWNLOAD": "Télécharger",
|
||||
"SUMMARY": "Résumé",
|
||||
"DEPENDENCIES": "Dépendances",
|
||||
"VALUES": "Valeurs",
|
||||
"OVERVIEW": "Aperçu",
|
||||
"HOME": "Accueil",
|
||||
"SRC_REPO": "Dépôt source",
|
||||
"CREATED": "Date/Heure de création",
|
||||
"MAINTAINERS": "Mainteneurs",
|
||||
"OTHER_MAINTAINERS": "{{ name }} et {{ number }} autres",
|
||||
"PULLS": "Nombre de Pull",
|
||||
"VERSION": "Version",
|
||||
"APP_VERSION": "Version de l'Application",
|
||||
"INSTALL": "Installer",
|
||||
"INSTALL_CHART": "Installer le Chart",
|
||||
"NAME": "Nom",
|
||||
"REPO": "Dépôt",
|
||||
"FILTER_FOR_CHARTS": "Filtrer les charts",
|
||||
"DELETE": "Supprimer",
|
||||
"OF": "sur",
|
||||
"VERSIONS": "versions",
|
||||
"IMAGES": "Images",
|
||||
"ENGINE": "Moteur",
|
||||
"ACTION": "Action",
|
||||
"UPLOAD": "Téléverser",
|
||||
"DELETE_CHART_VERSION_TITLE": "Supprimer des versions de Chart",
|
||||
"DELETE_CHART_VERSION": "Voulez-vous supprimer la version {{param}}?",
|
||||
"IMPORT": "Importer",
|
||||
"EXPORT": "Exporter",
|
||||
"ADD_REPO": "Ajouter Repo",
|
||||
"SHOW_KV": "Paires Clé/Valeur",
|
||||
"SHOW_YAML": "Fichier YAML",
|
||||
"PLACEHOLDER": "Nous n'avons trouvé aucun chart !",
|
||||
"NO_VERSION_PLACEHOLDER": "Nous n'avons trouvé aucune version !",
|
||||
"FILE_UPLOADED": "Fichier envoyé avec succès",
|
||||
"SIGN": "Signer",
|
||||
"SIGNED": "Signé",
|
||||
"UNSIGNED": "Non signé",
|
||||
"ITEMS": "items",
|
||||
"SECURITY": "Sécurité",
|
||||
"ACTIVE": "Actif",
|
||||
"DEPRECATED": "Obsolète",
|
||||
"VERIFY_CHART": "Verifier le Chart",
|
||||
"COMMAND": "Commandes",
|
||||
"PROV_FILE": "Prov File",
|
||||
"READY": "Prêt",
|
||||
"NOT_READY": "Non prêt",
|
||||
"LABELS": "Labels",
|
||||
"ADD_LABEL_TO_CHART_VERSION": "Ajouter des labels à cette version de chart",
|
||||
"STATUS": "Statut"
|
||||
},
|
||||
"SUMMARY": {
|
||||
"QUOTAS": "Quotas",
|
||||
"PROJECT_REPOSITORY": "Dépôts",
|
||||
"PROJECT_HELM_CHART": "Chart Helm",
|
||||
"PROJECT_MEMBER": "Membres",
|
||||
"PROJECT_QUOTAS": "Quotas",
|
||||
"ARTIFACT_COUNT": "Nombre d'Artefact",
|
||||
@ -838,6 +779,7 @@
|
||||
"SUB_TITLE_SUFIX": "logs"
|
||||
},
|
||||
"CONFIG": {
|
||||
"SECURITY": "Security",
|
||||
"HISTORY": "Historique",
|
||||
"TITLE": "Configuration",
|
||||
"AUTH": "Identification",
|
||||
@ -1606,8 +1548,6 @@
|
||||
"READ": "Lecture",
|
||||
"CREATE": "Création",
|
||||
"ARTIFACT": "Artefact",
|
||||
"HELM": "Chart Helm",
|
||||
"HELM_VERSION": "Version du Chart Helm",
|
||||
"ADD_ROBOT": "Ajouter un Robot",
|
||||
"UPDATE_ROBOT": "Mettre à jour le Robot",
|
||||
"UPDATE_ROBOT_SUCCESSFULLY": "Robot mis à jour avec succès",
|
||||
@ -1676,7 +1616,6 @@
|
||||
"PUSH_PERMISSION_TOOLTIP": "L'autorisation 'push' ne peut pas fonctionner seule, elle doit fonctionner avec l'autorisation 'pull'", "STOP": "Stop",
|
||||
"LIST": "Liste",
|
||||
"REPOSITORY": "Dépôt",
|
||||
"HELM_LABEL": "Label du Chart Helm",
|
||||
"EXPIRES_IN": "Expire dans",
|
||||
"EXPIRED": "Expiré"
|
||||
},
|
||||
|
@ -651,7 +651,6 @@
|
||||
"FLATTEN_LEVEL_TIP_1": "'Nivelar 1 posição' (padrão): 'a/b/c/d/img' -> 'ns/b/c/d/img'",
|
||||
"FLATTEN_LEVEL_TIP_2": "'Nivelar 2 posições': 'a/b/c/d/img' -> 'ns/c/d/img'",
|
||||
"FLATTEN_LEVEL_TIP_3": "'Nivelar 3 posições': 'a/b/c/d/img' -> 'ns/d/img'",
|
||||
"NOTE": "Nota: Chartmuseum suporta helm charts apenas com 2 níveis: 'a/chart'",
|
||||
"BANDWIDTH": "Banda",
|
||||
"BANDWIDTH_ERROR_TIP": "Informe um número inteiro maior que 0 (zero) ou -1",
|
||||
"BANDWIDTH_TOOLTIP": "Informe o limite de banda para cada execução. Tome cuidado e observe a relação com o número de execuções simultâneas. Para remover qualquer limite, informe -1",
|
||||
@ -762,66 +761,9 @@
|
||||
"MARKDOWN": "Estilização com Markdown suportada",
|
||||
"LAST_MODIFIED": "Data da última alteração"
|
||||
},
|
||||
"HELM_CHART": {
|
||||
"HELMCHARTS": "Charts",
|
||||
"CHARTVERSIONS": "Versões",
|
||||
"UPLOAD_TITLE": "Enviar arquivos de chart",
|
||||
"CHART_FILE": "Arquivo Chart",
|
||||
"CHART_PROV": "Arquivo Prov",
|
||||
"DOWNLOAD": "Baixar",
|
||||
"SUMMARY": "Resumo",
|
||||
"DEPENDENCIES": "Dependências",
|
||||
"VALUES": "Valores",
|
||||
"OVERVIEW": "Visão Geral",
|
||||
"HOME": "Painel Principal",
|
||||
"SRC_REPO": "Repositório de origem",
|
||||
"CREATED": "Data de criação",
|
||||
"MAINTAINERS": "Mantenedor",
|
||||
"PULLS": "Contagem de Pulls",
|
||||
"VERSION": "Versão",
|
||||
"APP_VERSION": "Versão da Aplicação",
|
||||
"INSTALL": "Instalar",
|
||||
"INSTALL_CHART": "Instalar Chart",
|
||||
"NAME": "Nome",
|
||||
"REPO": "Repositório",
|
||||
"FILTER_FOR_CHARTS": "Filtrar por charts",
|
||||
"DELETE": "Remover",
|
||||
"OF": "de",
|
||||
"VERSIONS": "versões",
|
||||
"IMAGES": "Imagens",
|
||||
"ENGINE": "Engine",
|
||||
"ACTION": "Ação",
|
||||
"UPLOAD": "Enviar",
|
||||
"DELETE_CHART_VERSION_TITLE": "Remover versões de Chart",
|
||||
"DELETE_CHART_VERSION": "Você quer remover a versão {{param}}?",
|
||||
"IMPORT": "Importar",
|
||||
"EXPORT": "Exportar",
|
||||
"ADD_REPO": "Adicionar Repositório",
|
||||
"SHOW_KV": "Pares chave-valor",
|
||||
"SHOW_YAML": "Arquivo YAML",
|
||||
"PLACEHOLDER": "Não foi possível encontrar nenhum charts!",
|
||||
"NO_VERSION_PLACEHOLDER": "Não foi possível encontrar nenhuma versão!",
|
||||
"FILE_UPLOADED": "Envio de arquivo realizado com sucesso",
|
||||
"SIGN": "Assinar",
|
||||
"SIGNED": "Assinado",
|
||||
"UNSIGNED": "Não assinado",
|
||||
"ITEMS": "itens",
|
||||
"NO_README": "Nenhum arquivo de README fornecido por esse chart.",
|
||||
"SECURITY": "Segurança",
|
||||
"ACTIVE": "Ativo",
|
||||
"DEPRECATED": "Obsoleto",
|
||||
"VERIFY_CHART": "Verificar Chart",
|
||||
"COMMAND": "Comandos",
|
||||
"PROV_FILE": "Arquivo Prov",
|
||||
"READY": "Pronto",
|
||||
"NOT_READY": "Não Pronto",
|
||||
"ADD_LABEL_TO_CHART_VERSION": "Adicionar marcadores",
|
||||
"STATUS": "Situação"
|
||||
},
|
||||
"SUMMARY": {
|
||||
"QUOTAS": "cotas",
|
||||
"PROJECT_REPOSITORY": "Repositórios",
|
||||
"PROJECT_HELM_CHART": "Helm Chart",
|
||||
"PROJECT_MEMBER": "Membros",
|
||||
"PROJECT_QUOTAS": "Cotas",
|
||||
"ARTIFACT_COUNT": "Contagem de artefatos",
|
||||
@ -849,6 +791,7 @@
|
||||
"SUB_TITLE_SUFIX": "logs"
|
||||
},
|
||||
"CONFIG": {
|
||||
"SECURITY": "Security",
|
||||
"HISTORY": "Histórico",
|
||||
"TITLE": "Configuração",
|
||||
"AUTH": "Autenticação",
|
||||
@ -1632,8 +1575,6 @@
|
||||
"READ": "Ler",
|
||||
"CREATE": "Criar",
|
||||
"ARTIFACT": "Artefato",
|
||||
"HELM": "Helm Chart",
|
||||
"HELM_VERSION": "Versão do Helm Chart",
|
||||
"ADD_ROBOT": "Adicionar conta",
|
||||
"UPDATE_ROBOT": "Atualizar conta",
|
||||
"UPDATE_ROBOT_SUCCESSFULLY": "Conta atualizada com sucesso",
|
||||
@ -1703,7 +1644,6 @@
|
||||
"STOP": "Parar",
|
||||
"LIST": "Listar",
|
||||
"REPOSITORY": "Repositório",
|
||||
"HELM_LABEL": "Marcador do Helm Chart",
|
||||
"EXPIRES_IN": "Expires in",
|
||||
"EXPIRED": "Expired"
|
||||
},
|
||||
|
@ -651,7 +651,6 @@
|
||||
"FLATTEN_LEVEL_TIP_1": "'Flatten 1 Level'(Default): 'a/b/c/d/img' -> 'ns/b/c/d/img'",
|
||||
"FLATTEN_LEVEL_TIP_2": "'Flatten 2 Levels': 'a/b/c/d/img' -> 'ns/c/d/img'",
|
||||
"FLATTEN_LEVEL_TIP_3": "'Flatten 3 Levels': 'a/b/c/d/img' -> 'ns/d/img'",
|
||||
"NOTE": "Notes: The Chartmuseum Charts only support the repository structure with 2 path components: 'a/chart'",
|
||||
"BANDWIDTH": "Bandwidth",
|
||||
"BANDWIDTH_ERROR_TIP": "Please enter -1 or an integer greater than 0",
|
||||
"BANDWIDTH_TOOLTIP": "Set the maximum network bandwidth for each execution. Please pay attention to the number of concurrent executions. For unlimited bandwidth, please enter -1",
|
||||
@ -763,68 +762,9 @@
|
||||
"MARKDOWN": "Markdown ile stil desteklenir",
|
||||
"LAST_MODIFIED": "Last Modified Time"
|
||||
},
|
||||
"HELM_CHART": {
|
||||
"HELMCHARTS": "Tablolar",
|
||||
"CHARTVERSIONS": "Versiyonlar",
|
||||
"UPLOAD_TITLE": "Tabloları dosyalarını yükle",
|
||||
"CHART_FILE": "Tablo Dosyası",
|
||||
"CHART_PROV": "Prov Dosyası",
|
||||
"DOWNLOAD": "Yükle",
|
||||
"SUMMARY": "Özet",
|
||||
"DEPENDENCIES": "Bağımlılıklar",
|
||||
"VALUES": "Değerler",
|
||||
"OVERVIEW": "Genel bakış",
|
||||
"HOME": "Ev",
|
||||
"SRC_REPO": "Kaynak Deposu",
|
||||
"CREATED": "Yaratılış Zamanı",
|
||||
"MAINTAINERS": "Sürdürenler",
|
||||
"OTHER_MAINTAINERS": "{{ name }} ve {{ number }} diğerleri",
|
||||
"PULLS": "İndirme Sayısı",
|
||||
"VERSION": "Versiyon",
|
||||
"APP_VERSION": "Uygulama Versiyonu",
|
||||
"INSTALL": "Yükle",
|
||||
"INSTALL_CHART": "Tablo Yükle",
|
||||
"NAME": "İsim",
|
||||
"REPO": "Depo",
|
||||
"FILTER_FOR_CHARTS": "Tabloları filtrele",
|
||||
"DELETE": "Sil",
|
||||
"OF": "of",
|
||||
"VERSIONS": "versiyonlar",
|
||||
"IMAGES": "İmajlar",
|
||||
"ENGINE": "Motor",
|
||||
"ACTION": "Aksiyon",
|
||||
"UPLOAD": "Yükle",
|
||||
"DELETE_CHART_VERSION_TITLE": "Tablo versiyonlarını sil",
|
||||
"DELETE_CHART_VERSION": "Sürümü silmek istiyor musunuz {{param}}?",
|
||||
"IMPORT": "İçe Aktar",
|
||||
"EXPORT": "Dışa Aktar",
|
||||
"ADD_REPO": "Depo Ekle",
|
||||
"SHOW_KV": "Anahtar Değer Çiftleri",
|
||||
"SHOW_YAML": "YAML Dosyası",
|
||||
"PLACEHOLDER": "Hiçbir tablo bulamadık!",
|
||||
"NO_VERSION_PLACEHOLDER": "Herhangi bir sürüm bulamadık!",
|
||||
"FILE_UPLOADED": "Dosya başarıyla yüklendi",
|
||||
"SIGN": "İmza",
|
||||
"SIGNED": "İmzalandı",
|
||||
"UNSIGNED": "İmzalanmadı",
|
||||
"ITEMS": "öğeler",
|
||||
"NO_README": "Bu tablo tarafından sağlanan beni oku dosyası yok.",
|
||||
"SECURITY": "Güvenlik",
|
||||
"ACTIVE": "Aktif",
|
||||
"DEPRECATED": "Kullanımdan kaldırılan",
|
||||
"VERIFY_CHART": "Tabloyu doğrula",
|
||||
"COMMAND": "Komutlar",
|
||||
"PROV_FILE": "Prov Dosyası",
|
||||
"READY": "Hazır",
|
||||
"NOT_READY": "Hazır Değil",
|
||||
"LABELS": "Etiketler",
|
||||
"ADD_LABEL_TO_CHART_VERSION": "Bu tablo sürümüne etiketler ekle",
|
||||
"STATUS": "Durum"
|
||||
},
|
||||
"SUMMARY": {
|
||||
"QUOTAS": "kotalar",
|
||||
"PROJECT_REPOSITORY": "Proje depoları",
|
||||
"PROJECT_HELM_CHART": "Proje Helm Tablosu",
|
||||
"PROJECT_MEMBER": "Proje Üyeleri",
|
||||
"PROJECT_QUOTAS": "Proje kotaları",
|
||||
"ARTIFACT_COUNT": "Buluntu adeti",
|
||||
@ -852,6 +792,7 @@
|
||||
"SUB_TITLE_SUFIX": "kayıtlar"
|
||||
},
|
||||
"CONFIG": {
|
||||
"SECURITY": "Security",
|
||||
"HISTORY": "Geçmiş",
|
||||
"TITLE": "Ayarlar",
|
||||
"AUTH": "Doğrulama",
|
||||
@ -1636,8 +1577,6 @@
|
||||
"READ": "Read",
|
||||
"CREATE": "Create",
|
||||
"ARTIFACT": "Artifact",
|
||||
"HELM": "Helm Chart",
|
||||
"HELM_VERSION": "Helm Chart Version",
|
||||
"ADD_ROBOT": "Add Robot",
|
||||
"UPDATE_ROBOT": "Update Robot",
|
||||
"UPDATE_ROBOT_SUCCESSFULLY": "Updated robot successfully",
|
||||
@ -1707,7 +1646,6 @@
|
||||
"STOP": "Stop",
|
||||
"LIST": "List",
|
||||
"REPOSITORY": "Repository",
|
||||
"HELM_LABEL": "Helm Chart label",
|
||||
"EXPIRES_IN": "Expires in",
|
||||
"EXPIRED": "Expired"
|
||||
},
|
||||
|
@ -653,7 +653,6 @@
|
||||
"FLATTEN_LEVEL_TIP_1": "'替换1级'(默认项): 'a/b/c/d/img' -> 'ns/b/c/d/img'",
|
||||
"FLATTEN_LEVEL_TIP_2": "'替换2级': 'a/b/c/d/img' -> 'ns/c/d/img'",
|
||||
"FLATTEN_LEVEL_TIP_3": "'替换3级': 'a/b/c/d/img' -> 'ns/d/img'",
|
||||
"NOTE": "注意: Chartmuseum Charts 仅支持2层的仓库结构:如 'a/chart'",
|
||||
"BANDWIDTH": "带宽",
|
||||
"BANDWIDTH_ERROR_TIP": "请输入-1或者大于0的整数",
|
||||
"BANDWIDTH_TOOLTIP": "设置执行该条同步规则时的最大网络带宽。实际总带宽需要考虑并发执行的情况。如无需限制,请输入-1",
|
||||
@ -765,68 +764,9 @@
|
||||
"MARKDOWN": "支持使用Markdown进行样式设置",
|
||||
"LAST_MODIFIED": "最新变更时间"
|
||||
},
|
||||
"HELM_CHART": {
|
||||
"HELMCHARTS": "Charts",
|
||||
"CHARTVERSIONS": "版本",
|
||||
"UPLOAD_TITLE": "上传chart文件",
|
||||
"CHART_FILE": "Chart 文件",
|
||||
"CHART_PROV": "Prov 文件",
|
||||
"DOWNLOAD": "下载",
|
||||
"SUMMARY": "概要",
|
||||
"DEPENDENCIES": "依赖",
|
||||
"VALUES": "取值",
|
||||
"OVERVIEW": "总览",
|
||||
"HOME": "首页",
|
||||
"SRC_REPO": "源仓库",
|
||||
"CREATED": "创建时间",
|
||||
"MAINTAINERS": "维护者",
|
||||
"OTHER_MAINTAINERS": "{{ name }} 与其他 {{ number }} 位",
|
||||
"PULLS": "拉取数",
|
||||
"VERSION": "版本",
|
||||
"INSTALL": "安装",
|
||||
"INSTALL_CHART": "安装Chart",
|
||||
"NAME": "名称",
|
||||
"REPO": "仓库",
|
||||
"FILTER_FOR_CHARTS": "过滤Chart",
|
||||
"DELETE": "删除",
|
||||
"OF": "共计",
|
||||
"VERSIONS": "版本",
|
||||
"APP_VERSION": "应用版本",
|
||||
"IMAGES": "镜像",
|
||||
"ENGINE": "引擎",
|
||||
"ACTION": "动作",
|
||||
"UPLOAD": "上传",
|
||||
"DELETE_CHART_VERSION_TITLE": "删除Chart版本",
|
||||
"DELETE_CHART_VERSION": "您要删除chart版本 {{param}} 吗?",
|
||||
"IMPORT": "导入",
|
||||
"EXPORT": "导出",
|
||||
"ADD_REPO": "添加仓库",
|
||||
"SHOW_KV": "展示健值对",
|
||||
"SHOW_YAML": "展示YAML文件",
|
||||
"PLACEHOLDER": "找不到任何的chart!",
|
||||
"NO_VERSION_PLACEHOLDER": "找不到任何的chart版本!",
|
||||
"FILE_UPLOADED": "文件上传成功",
|
||||
"SIGN": "签名",
|
||||
"SIGNED": "已签名",
|
||||
"UNSIGNED": "未签名",
|
||||
"ITEMS": "条记录",
|
||||
"NO_README": "此Chart未提供README文件",
|
||||
"SECURITY": "安全",
|
||||
"ACTIVE": "正常",
|
||||
"DEPRECATED": "废弃",
|
||||
"VERIFY_CHART": "验证Chart",
|
||||
"COMMAND": "命令",
|
||||
"PROV_FILE": "Prov 文件",
|
||||
"READY": "就绪",
|
||||
"NOT_READY": "未就绪",
|
||||
"LABELS": "标签",
|
||||
"ADD_LABEL_TO_CHART_VERSION": "添加标签到此 Chart Version",
|
||||
"STATUS": "状态"
|
||||
},
|
||||
"SUMMARY": {
|
||||
"QUOTAS": "容量",
|
||||
"PROJECT_REPOSITORY": "镜像仓库",
|
||||
"PROJECT_HELM_CHART": "Helm Chart",
|
||||
"PROJECT_MEMBER": "成员",
|
||||
"PROJECT_QUOTAS": "容量",
|
||||
"ARTIFACT_COUNT": "Artifact 数量",
|
||||
@ -854,6 +794,7 @@
|
||||
"SUB_TITLE_SUFIX": "条日志"
|
||||
},
|
||||
"CONFIG": {
|
||||
"SECURITY": "安全",
|
||||
"HISTORY": "历史记录",
|
||||
"TITLE": "配置",
|
||||
"AUTH": "认证模式",
|
||||
@ -1635,8 +1576,6 @@
|
||||
"READ": "读取",
|
||||
"CREATE": "创建",
|
||||
"ARTIFACT": "Artifact",
|
||||
"HELM": "Helm Chart",
|
||||
"HELM_VERSION": "Helm Chart Version",
|
||||
"ADD_ROBOT": "添加机器人",
|
||||
"UPDATE_ROBOT": "更新机器人",
|
||||
"UPDATE_ROBOT_SUCCESSFULLY": "更新机器人成功",
|
||||
@ -1706,7 +1645,6 @@
|
||||
"STOP": "停止",
|
||||
"LIST": "查询",
|
||||
"REPOSITORY": "仓库",
|
||||
"HELM_LABEL": "Helm Chart 标签",
|
||||
"EXPIRES_IN": "有效期剩余",
|
||||
"EXPIRED": "已过期"
|
||||
},
|
||||
|
@ -648,7 +648,6 @@
|
||||
"FLATTEN_LEVEL_TIP_1": "'Flatten 1 Level'(Default): 'a/b/c/d/img' -> 'ns/b/c/d/img'",
|
||||
"FLATTEN_LEVEL_TIP_2": "'Flatten 2 Levels': 'a/b/c/d/img' -> 'ns/c/d/img'",
|
||||
"FLATTEN_LEVEL_TIP_3": "'Flatten 3 Levels': 'a/b/c/d/img' -> 'ns/d/img'",
|
||||
"NOTE": "Notes: The Chartmuseum Charts only support the repository structure with 2 path components: 'a/chart'",
|
||||
"BANDWIDTH": "Bandwidth",
|
||||
"BANDWIDTH_ERROR_TIP": "Please enter -1 or an integer greater than 0",
|
||||
"BANDWIDTH_TOOLTIP": "Set the maximum network bandwidth for each execution. Please pay attention to the number of concurrent executions. For unlimited bandwidth, please enter -1",
|
||||
@ -761,68 +760,9 @@
|
||||
"MARKDOWN": "支持使用Markdown進行樣式設置",
|
||||
"LAST_MODIFIED": "Last Modified Time"
|
||||
},
|
||||
"HELM_CHART":{
|
||||
"HELMCHARTS":"圖表",
|
||||
"CHARTVERSIONS": "版本",
|
||||
"UPLOAD_TITLE": "上傳chart文件",
|
||||
"CHART_FILE": "Chart 文件",
|
||||
"CHART_PROV": "Prov 文件",
|
||||
"DOWNLOAD": "下載",
|
||||
"SUMMARY": "概要",
|
||||
"DEPENDENCIES": "依賴",
|
||||
"VALUES": "取值",
|
||||
"OVERVIEW": "總覽",
|
||||
"HOME": "首頁",
|
||||
"SRC_REPO":"源倉庫",
|
||||
"CREATED": "創建時間",
|
||||
"MAINTAINERS": "維護者",
|
||||
"OTHER_MAINTAINERS": "{{ name }} 與其他{{ number }} 位",
|
||||
"PULLS": "拉取數",
|
||||
"VERSION": "版本",
|
||||
"INSTALL": "安裝",
|
||||
"INSTALL_CHART": "安裝Chart",
|
||||
"NAME": "名稱",
|
||||
"REPO": "倉庫",
|
||||
"FILTER_FOR_CHARTS": "過濾Chart",
|
||||
"DELETE": "刪除",
|
||||
"OF": "共計",
|
||||
"VERSIONS": "版本",
|
||||
"APP_VERSION": "應用版本",
|
||||
"IMAGES": "鏡像",
|
||||
"ENGINE": "引擎",
|
||||
"ACTION": "動作",
|
||||
"UPLOAD": "上傳",
|
||||
"DELETE_CHART_VERSION_TITLE": "刪除Chart版本",
|
||||
"DELETE_CHART_VERSION": "您要刪除chart版本{{param}} 嗎?",
|
||||
"IMPORT": "導入",
|
||||
"EXPORT": "導出",
|
||||
"ADD_REPO": "添加倉庫",
|
||||
"SHOW_KV": "展示健值對",
|
||||
"SHOW_YAML": "展示YAML文件",
|
||||
"PLACEHOLDER": "找不到任何的chart!",
|
||||
"NO_VERSION_PLACEHOLDER": "找不到任何的chart版本!",
|
||||
"FILE_UPLOADED": "文件上傳成功",
|
||||
"SIGN": "簽名",
|
||||
"SIGNED": "已簽名",
|
||||
"UNSIGNED": "未簽名",
|
||||
"ITEMS": "條記錄",
|
||||
"NO_README": "此Chart未提供README文件",
|
||||
"SECURITY": "安全",
|
||||
"ACTIVE": "正常",
|
||||
"DEPRECATED": "廢棄",
|
||||
"VERIFY_CHART": "驗證Chart",
|
||||
"COMMAND":"命令",
|
||||
"PROV_FILE": "Prov 文件",
|
||||
"READY":"就緒",
|
||||
"NOT_READY": "未就緒",
|
||||
"LABELS": "標籤",
|
||||
"ADD_LABEL_TO_CHART_VERSION": "添加標籤到此Chart Version",
|
||||
"STATUS": "狀態"
|
||||
},
|
||||
"SUMMARY":{
|
||||
"QUOTAS": "容量",
|
||||
"PROJECT_REPOSITORY": "鏡像倉庫",
|
||||
"PROJECT_HELM_CHART":"Helm Chart",
|
||||
"PROJECT_MEMBER": "成員",
|
||||
"PROJECT_QUOTAS": "容量",
|
||||
"ARTIFACT_COUNT":"工件數量",
|
||||
@ -850,6 +790,7 @@
|
||||
"SUB_TITLE_SUFIX": "條日誌"
|
||||
},
|
||||
"CONFIG":{
|
||||
"SECURITY": "Security",
|
||||
"TITLE": "配置",
|
||||
"AUTH": "認證模式",
|
||||
"REPLICATION": "複製",
|
||||
@ -1627,8 +1568,6 @@
|
||||
"READ": "Read",
|
||||
"CREATE": "Create",
|
||||
"ARTIFACT": "Artifact",
|
||||
"HELM": "Helm Chart",
|
||||
"HELM_VERSION": "Helm Chart Version",
|
||||
"ADD_ROBOT": "Add Robot",
|
||||
"UPDATE_ROBOT": "Update Robot",
|
||||
"UPDATE_ROBOT_SUCCESSFULLY": "Updated robot successfully",
|
||||
@ -1698,7 +1637,6 @@
|
||||
"STOP": "Stop",
|
||||
"LIST": "List",
|
||||
"REPOSITORY": "Repository",
|
||||
"HELM_LABEL": "Helm Chart label",
|
||||
"EXPIRES_IN": "Expires in",
|
||||
"EXPIRED": "Expired"
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user