diff --git a/src/frontend/src/app/admin/cluster/list-cluster/list-cluster.component.html b/src/frontend/src/app/admin/cluster/list-cluster/list-cluster.component.html index 1f906784e..d1d7b6fdb 100644 --- a/src/frontend/src/app/admin/cluster/list-cluster/list-cluster.component.html +++ b/src/frontend/src/app/admin/cluster/list-cluster/list-cluster.component.html @@ -9,6 +9,11 @@ {{'TITLE.NAME' | translate}} + + + displayname + + Master @@ -51,6 +56,7 @@ {{cluster.id}} {{cluster.name}} + {{cluster.displayname}} {{cluster.master}} {{getClusterStatus(cluster.status)}} + + + displayname + + Master @@ -41,6 +46,7 @@

已删除集群列表

{{cluster.id}} {{cluster.name}} + {{cluster.displayname}} {{cluster.master}} {{cluster.description}} {{cluster.user}} diff --git a/src/frontend/src/app/admin/namespace/list-namespace/list-namespace.component.html b/src/frontend/src/app/admin/namespace/list-namespace/list-namespace.component.html index 50a59d23e..fd69baec8 100644 --- a/src/frontend/src/app/admin/namespace/list-namespace/list-namespace.component.html +++ b/src/frontend/src/app/admin/namespace/list-namespace/list-namespace.component.html @@ -37,6 +37,7 @@ + {{ns.id}} diff --git a/src/frontend/src/app/admin/namespace/list-namespace/list-namespace.component.ts b/src/frontend/src/app/admin/namespace/list-namespace/list-namespace.component.ts index 4e846979d..8fa17c892 100644 --- a/src/frontend/src/app/admin/namespace/list-namespace/list-namespace.component.ts +++ b/src/frontend/src/app/admin/namespace/list-namespace/list-namespace.component.ts @@ -21,6 +21,7 @@ export class ListNamespaceComponent { @Output() paginate = new EventEmitter(); @Output() delete = new EventEmitter(); @Output() edit = new EventEmitter(); + @Output() migrate = new EventEmitter(); constructor(private router: Router, private aceEditorService: AceEditorService) { @@ -46,6 +47,10 @@ export class ListNamespaceComponent { this.edit.emit(ns); } + migrateNamespace(ns: Namespace) { + this.migrate.emit(ns); + } + goToLink(ns: Namespace, gate: string) { let linkUrl = ''; switch (gate) { diff --git a/src/frontend/src/app/admin/namespace/migrate-namespace/migrate-namespace.component.html b/src/frontend/src/app/admin/namespace/migrate-namespace/migrate-namespace.component.html new file mode 100644 index 000000000..4b4682d72 --- /dev/null +++ b/src/frontend/src/app/admin/namespace/migrate-namespace/migrate-namespace.component.html @@ -0,0 +1,17 @@ + + 命名空间迁移 + +
+ + + + + + + + +
+
+
\ No newline at end of file diff --git a/src/frontend/src/app/admin/namespace/migrate-namespace/migrate-namespace.component.scss b/src/frontend/src/app/admin/namespace/migrate-namespace/migrate-namespace.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/src/frontend/src/app/admin/namespace/migrate-namespace/migrate-namespace.component.spec.ts b/src/frontend/src/app/admin/namespace/migrate-namespace/migrate-namespace.component.spec.ts new file mode 100644 index 000000000..0f36cc819 --- /dev/null +++ b/src/frontend/src/app/admin/namespace/migrate-namespace/migrate-namespace.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { MigrateNamespaceComponent } from './migrate-namespace.component'; + +describe('MigrateNamespaceComponent', () => { + let component: MigrateNamespaceComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ MigrateNamespaceComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(MigrateNamespaceComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/frontend/src/app/admin/namespace/migrate-namespace/migrate-namespace.component.ts b/src/frontend/src/app/admin/namespace/migrate-namespace/migrate-namespace.component.ts new file mode 100644 index 000000000..35df16397 --- /dev/null +++ b/src/frontend/src/app/admin/namespace/migrate-namespace/migrate-namespace.component.ts @@ -0,0 +1,78 @@ +import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core'; +import { Namespace } from 'app/shared/model/v1/namespace'; +import { NgForm } from '@angular/forms'; +import { ModalComponent } from 'app/shared/modal/modal.component'; +import { ModalService } from 'app/shared/modal/modal.service'; +import { Subscription } from 'rxjs'; +import { NamespaceService } from 'app/shared/client/v1/namespace.service'; +import { MessageHandlerService } from 'app/shared/message-handler/message-handler.service'; +@Component({ + selector: 'migrate-namespace', + templateUrl: './migrate-namespace.component.html', + styleUrls: ['./migrate-namespace.component.scss'] +}) +export class MigrateNamespaceComponent implements OnInit, OnDestroy { + namespaceForm: NgForm; + @ViewChild('namespaceForm', { static: false }) + currentForm: NgForm; + @ViewChild(ModalComponent, { static: false }) + modalComponent: ModalComponent; + + currentNamespace: Namespace = new Namespace; + target: number; + namespaces: Namespace[] = []; + subscription: Subscription; + constructor( + private modalService: ModalService, + private namespaceService: NamespaceService, + private message: MessageHandlerService + ) { + this.subscription = this.modalService.modalObservable$.subscribe(res => { + switch (res.method) { + case 'cancel': + this.cancelEvent(); + break; + case 'confirm': + this.confirmEvent(); + break; + } + }); + } + + ngOnInit() { + } + + ngOnDestroy() { + this.subscription.unsubscribe(); + } + + cancelEvent() { + this.namespaces = []; + this.modalComponent.opened = false; + } + + confirmEvent() { + this.namespaceService.migrateNamespace(this.currentNamespace.id, Number(this.target)) + .subscribe( + res => { + this.message.showSuccess(`${this.currentNamespace.name}迁移成功`); + this.modalComponent.opened = false; + }, + error => this.message.error(error) + ); + } + + open(ns: Namespace, namespaceList: Namespace[]) { + this.target = undefined; + this.currentNamespace = ns; + this.modalComponent.opened = true; + this.namespaces = namespaceList.filter(namespace => { + return namespace.id !== ns.id; + }) || []; + } + + public get isValid() { + return !!this.target; + } + +} diff --git a/src/frontend/src/app/admin/namespace/namespace.component.html b/src/frontend/src/app/admin/namespace/namespace.component.html index 078ab8915..a01922d5a 100644 --- a/src/frontend/src/app/admin/namespace/namespace.component.html +++ b/src/frontend/src/app/admin/namespace/namespace.component.html @@ -11,9 +11,10 @@

命名空间列表

+ + (migrate)="migrateNamespace($event)" (paginate)="retrieve($event)" [page]="pageState.page"> diff --git a/src/frontend/src/app/admin/namespace/namespace.component.ts b/src/frontend/src/app/admin/namespace/namespace.component.ts index bf8f7bc82..ef96fe49a 100644 --- a/src/frontend/src/app/admin/namespace/namespace.component.ts +++ b/src/frontend/src/app/admin/namespace/namespace.component.ts @@ -12,6 +12,7 @@ import { NamespaceService } from '../../shared/client/v1/namespace.service'; import { PageState } from '../../shared/page/page-state'; import { ClusterService } from '../../shared/client/v1/cluster.service'; import { Cluster } from '../../shared/model/v1/cluster'; +import { MigrateNamespaceComponent } from './migrate-namespace/migrate-namespace.component'; @Component({ selector: 'wayne-namespace', @@ -23,6 +24,8 @@ export class NamespaceComponent implements OnInit, OnDestroy { listNamespace: ListNamespaceComponent; @ViewChild(CreateEditNamespaceComponent, { static: false }) createEditNamespace: CreateEditNamespaceComponent; + @ViewChild(MigrateNamespaceComponent, {static: false}) + migrateNamespaceComponent: MigrateNamespaceComponent; pageState: PageState = new PageState(); changedNamespaces: Namespace[]; @@ -133,4 +136,15 @@ export class NamespaceComponent implements OnInit, OnDestroy { editNamespace(ns: Namespace): void { this.createEditNamespace.newOrEditNamespace(this.clusters, ns.id); } + + migrateNamespace(ns: Namespace): void { + const pageState = new PageState({ + pageNo: 1, + pageSize: 10000 + }); + this.namespaceService.listNamespace(pageState, 'false') + .subscribe(res => { + this.migrateNamespaceComponent.open(ns, res.data.list); + }); + } } diff --git a/src/frontend/src/app/admin/namespace/namespace.module.ts b/src/frontend/src/app/admin/namespace/namespace.module.ts index fc301c551..def841b4b 100644 --- a/src/frontend/src/app/admin/namespace/namespace.module.ts +++ b/src/frontend/src/app/admin/namespace/namespace.module.ts @@ -5,6 +5,7 @@ import { ListNamespaceComponent } from './list-namespace/list-namespace.componen import { TrashNamespaceComponent } from './trash-namespace/trash-namespace.component'; import { SharedModule } from '../../shared/shared.module'; import { NamespaceService } from '../../shared/client/v1/namespace.service'; +import { MigrateNamespaceComponent } from './migrate-namespace/migrate-namespace.component'; @NgModule({ imports: [ @@ -21,7 +22,8 @@ import { NamespaceService } from '../../shared/client/v1/namespace.service'; NamespaceComponent, TrashNamespaceComponent, ListNamespaceComponent, - CreateEditNamespaceComponent + CreateEditNamespaceComponent, + MigrateNamespaceComponent ] }) diff --git a/src/frontend/src/app/portal/deployment/list-deployment/list-deployment.component.html b/src/frontend/src/app/portal/deployment/list-deployment/list-deployment.component.html index f1eb54d16..4661a3344 100644 --- a/src/frontend/src/app/portal/deployment/list-deployment/list-deployment.component.html +++ b/src/frontend/src/app/portal/deployment/list-deployment/list-deployment.component.html @@ -94,6 +94,10 @@ (click)="offlineDeployment(deploymentTpl)" *ngIf="deploymentTpl.status && (authService.currentAppPermission.kubeDeployment.delete || authService.currentUser.admin)"> {{'BUTTON.DROP' | translate}} +
diff --git a/src/frontend/src/app/portal/deployment/list-deployment/list-deployment.component.ts b/src/frontend/src/app/portal/deployment/list-deployment/list-deployment.component.ts index efed32406..6d87a88b7 100644 --- a/src/frontend/src/app/portal/deployment/list-deployment/list-deployment.component.ts +++ b/src/frontend/src/app/portal/deployment/list-deployment/list-deployment.component.ts @@ -174,6 +174,17 @@ export class ListDeploymentComponent implements OnInit, OnDestroy { }); } + modifyReplicas(tpl: DeploymentTpl) { + this.deploymentService.getById(tpl.deploymentId, this.appId).subscribe( + status => { + const deployment = status.data; + this.publishDeploymentTpl.newPublishTpl(deployment, tpl, ResourcesActionType.MODIFY_REPLICA); + }, + error => { + this.messageHandlerService.handleError(error); + }); + } + published(success: boolean) { if (success) { this.refresh(); diff --git a/src/frontend/src/app/portal/deployment/publish-tpl/publish-tpl.component.html b/src/frontend/src/app/portal/deployment/publish-tpl/publish-tpl.component.html index 5c171cbf2..664d427ad 100644 --- a/src/frontend/src/app/portal/deployment/publish-tpl/publish-tpl.component.html +++ b/src/frontend/src/app/portal/deployment/publish-tpl/publish-tpl.component.html @@ -14,8 +14,8 @@ - - + 部署份数超过系统最大限制{{replicaLimit}} diff --git a/src/frontend/src/app/portal/deployment/publish-tpl/publish-tpl.component.ts b/src/frontend/src/app/portal/deployment/publish-tpl/publish-tpl.component.ts index 890b3ad03..26f637b9d 100644 --- a/src/frontend/src/app/portal/deployment/publish-tpl/publish-tpl.component.ts +++ b/src/frontend/src/app/portal/deployment/publish-tpl/publish-tpl.component.ts @@ -1,5 +1,5 @@ import { Component, EventEmitter, Output, ViewChild } from '@angular/core'; -import { forkJoin } from 'rxjs'; +import { forkJoin, ObservableInput } from 'rxjs'; import 'rxjs/add/operator/debounceTime'; import 'rxjs/add/operator/distinctUntilChanged'; import { NgForm } from '@angular/forms'; @@ -114,6 +114,9 @@ export class PublishDeploymentTplComponent { case ResourcesActionType.OFFLINE: this.title = '下线部署[' + this.deployment.name + ']'; break; + case ResourcesActionType.MODIFY_REPLICA: + this.title = `修改状态副本集[${this.deployment.name}]`; + break; } } @@ -162,6 +165,9 @@ export class PublishDeploymentTplComponent { case ResourcesActionType.OFFLINE: this.offline(); break; + case ResourcesActionType.MODIFY_REPLICA: + this.modifyReplica(); + break; } this.isSubmitOnGoing = false; @@ -188,6 +194,24 @@ export class PublishDeploymentTplComponent { }); } + modifyReplica() { + const observables: ObservableInput[] = []; + Object.getOwnPropertyNames(this.clusterMetas).forEach(cluster => { + if (this.clusterMetas[cluster].checked) { + observables.push( + this.deploymentClient.modifyReplica(this.appId, cluster, this.deployment.name, this.cacheService.kubeNamespace, { + num: Number(this.clusterMetas[cluster].value) + }) + ); + } + }); + forkJoin(observables) + .subscribe( + res => this.messageHandlerService.showSuccess('修改成功'), + error => this.messageHandlerService.handleError(error) + ); + } + deletePublishStatus(id: number) { this.publishStatusService.deleteById(id).subscribe( response => { diff --git a/src/frontend/src/app/shared/client/v1/kubernetes/deployment.ts b/src/frontend/src/app/shared/client/v1/kubernetes/deployment.ts index 6fd057c5b..fdaa73073 100644 --- a/src/frontend/src/app/shared/client/v1/kubernetes/deployment.ts +++ b/src/frontend/src/app/shared/client/v1/kubernetes/deployment.ts @@ -5,6 +5,7 @@ import { PageState } from '../../../page/page-state'; import { BaseClient } from './base-client'; import { KubeDeployment, ObjectMeta } from '../../../model/v1/kubernetes/deployment'; import { throwError } from 'rxjs'; +import { catchError } from 'rxjs/operators'; @Injectable() export class DeploymentClient { @@ -39,4 +40,12 @@ export class DeploymentClient { .delete(`/api/v1/kubernetes/apps/${appId}/deployments/${name}/namespaces/${namespace}/clusters/${cluster}`) .catch(error => throwError(error)); } + + modifyReplica(appId: number, cluster: string, name: string, namespace: string, data: any) { + return this.http + .post(`/api/v1/kubernetes/apps/${appId}/deployments/${name}/namespaces/${namespace}/clusters/${cluster}/updatescale`, data) + .pipe( + catchError(error => throwError(error)) + ); + } } diff --git a/src/frontend/src/app/shared/client/v1/namespace.service.ts b/src/frontend/src/app/shared/client/v1/namespace.service.ts index 7baf80554..9737d47cc 100644 --- a/src/frontend/src/app/shared/client/v1/namespace.service.ts +++ b/src/frontend/src/app/shared/client/v1/namespace.service.ts @@ -110,4 +110,13 @@ export class NamespaceService { .get(`/api/v1/namespaces/${namespaceId}/history`, {params: params}) .catch(error => throwError(error)); } + + migrateNamespace(sourceId: number, targetId: number) { + return this.http + .post(`/api/v1/namespaces/migration`, { + sourceId, + targetId + }) + .catch(error => throwError(error)); + } } diff --git a/src/frontend/src/app/shared/filter-box/filter-box.component.scss b/src/frontend/src/app/shared/filter-box/filter-box.component.scss index 024920114..d26691822 100644 --- a/src/frontend/src/app/shared/filter-box/filter-box.component.scss +++ b/src/frontend/src/app/shared/filter-box/filter-box.component.scss @@ -9,6 +9,7 @@ right: -200px; top: -12px; z-index: 520; + filter: drop-shadow(1px 2px 4px #ccc); &:before { content: ''; @@ -20,7 +21,6 @@ width: 16px; height: 16px; background: #fff; - box-shadow: 0 2px 8px 1px #dee6f3; z-index: 1; } diff --git a/src/frontend/src/app/shared/modal/modal.component.html b/src/frontend/src/app/shared/modal/modal.component.html new file mode 100644 index 000000000..b67ce91ed --- /dev/null +++ b/src/frontend/src/app/shared/modal/modal.component.html @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file diff --git a/src/frontend/src/app/shared/modal/modal.component.scss b/src/frontend/src/app/shared/modal/modal.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/src/frontend/src/app/shared/modal/modal.component.spec.ts b/src/frontend/src/app/shared/modal/modal.component.spec.ts new file mode 100644 index 000000000..fc32a90f0 --- /dev/null +++ b/src/frontend/src/app/shared/modal/modal.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ModalComponent } from './modal.component'; + +describe('ModalComponent', () => { + let component: ModalComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ ModalComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ModalComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/frontend/src/app/shared/modal/modal.component.ts b/src/frontend/src/app/shared/modal/modal.component.ts new file mode 100644 index 000000000..0adfd5bda --- /dev/null +++ b/src/frontend/src/app/shared/modal/modal.component.ts @@ -0,0 +1,27 @@ +import { Component, OnInit, Input } from '@angular/core'; +import { ModalService } from 'app/shared/modal/modal.service'; + +@Component({ + selector: 'wayne-modal', + templateUrl: './modal.component.html', + styleUrls: ['./modal.component.scss'] +}) +export class ModalComponent implements OnInit { + opened = false; + @Input() isValid = false; + constructor( + private modalService: ModalService + ) { } + + ngOnInit() { + } + + onSubmit() { + this.modalService.comfirm(); + } + + onCancel() { + this.modalService.cancel(); + } + +} diff --git a/src/frontend/src/app/shared/modal/modal.service.ts b/src/frontend/src/app/shared/modal/modal.service.ts new file mode 100644 index 000000000..8c1893e16 --- /dev/null +++ b/src/frontend/src/app/shared/modal/modal.service.ts @@ -0,0 +1,18 @@ +import { Injectable } from '@angular/core'; +import { Subject } from 'rxjs/Subject'; + +export class ModalService { + modalObservable = new Subject(); + + modalObservable$ = this.modalObservable.asObservable(); + + open() { + this.modalObservable.next({method: 'open'}); + } + cancel() { + this.modalObservable.next({method: 'cancel'}); + } + comfirm() { + this.modalObservable.next({method: 'confirm'}); + } +} diff --git a/src/frontend/src/app/shared/shared.const.ts b/src/frontend/src/app/shared/shared.const.ts index ae67776d2..3999035af 100644 --- a/src/frontend/src/app/shared/shared.const.ts +++ b/src/frontend/src/app/shared/shared.const.ts @@ -45,7 +45,7 @@ export const enum AlertType { } export const enum ResourcesActionType { - PUBLISH, SCALE, RESTART, OFFLINE, UPDATE + PUBLISH, SCALE, RESTART, OFFLINE, UPDATE, MODIFY_REPLICA } export const enum TemplateState { diff --git a/src/frontend/src/app/shared/shared.module.ts b/src/frontend/src/app/shared/shared.module.ts index 9a3708450..9cfad84c2 100644 --- a/src/frontend/src/app/shared/shared.module.ts +++ b/src/frontend/src/app/shared/shared.module.ts @@ -54,6 +54,9 @@ import { ListEventComponent } from './list-event/list-event.component'; import { SideNavService } from './client/v1/sidenav.service'; import { SearchSectionComponent } from './tabs/search-section/search-section.component'; import { CollapseModule } from './collapse/collapse.module'; +import { ModalComponent } from './modal/modal.component'; +import { ModalService } from './modal/modal.service'; + @NgModule({ imports: [ BrowserAnimationsModule, @@ -97,7 +100,8 @@ import { CollapseModule } from './collapse/collapse.module'; DiffComponent, ListPodComponent, ListEventComponent, - SearchSectionComponent + SearchSectionComponent, + ModalComponent ], exports: [ BrowserAnimationsModule, @@ -131,6 +135,7 @@ import { CollapseModule } from './collapse/collapse.module'; CheckboxComponent, CheckboxGroupComponent, DropDownComponent, + ModalComponent, DropdownItemComponent, RelativeTimeFilterPipe, TranslateModule, @@ -154,7 +159,8 @@ import { CollapseModule } from './collapse/collapse.module'; CopyService, TabDragService, SelectCopyService, - DiffService + DiffService, + ModalService ] }) export class SharedModule { diff --git a/src/frontend/src/assets/i18n/zh-Hans.json b/src/frontend/src/assets/i18n/zh-Hans.json index 885316b15..3b7258880 100644 --- a/src/frontend/src/assets/i18n/zh-Hans.json +++ b/src/frontend/src/assets/i18n/zh-Hans.json @@ -185,7 +185,8 @@ "CREATE_TMP": "创建部署模板", "DELETE": "删除部署", "EDIT": "编辑部署", - "NUM": "部署份数" + "NUM": "部署份数", + "MODIFY_REPLICA": "修改副本数" }, "DEPLOYMENT_ADMIN": { "CREATE": {