From 547ac95d4d177208c37186bc6cb36dbd886230bd Mon Sep 17 00:00:00 2001 From: cyuamber Date: Fri, 21 Jun 2019 15:24:19 +0800 Subject: Topic interface Function modification Change-Id: Ifa8c7c4a929f2bd6fcbd660a86e05a079786cc8b Issue-ID: DCAEGEN2-1623 Signed-off-by: cyuamber --- .../admin/src/src/app/app.module.ts | 3 + .../admin/src/src/app/core/models/topic.model.ts | 1 + .../src/src/app/core/services/rest-api.service.ts | 16 +- .../new-topic-model/new-topic-model.component.css | 15 + .../new-topic-model/new-topic-model.component.html | 229 ++++++++++ .../new-topic-model.component.spec.ts | 40 ++ .../new-topic-model/new-topic-model.component.ts | 157 +++++++ .../topic-detail-modal.component.html | 2 +- .../topics/topic-list/topic-list.component.html | 502 +++++++++++++-------- .../app/topics/topic-list/topic-list.component.ts | 126 ++++-- .../admin/src/src/assets/i18n/en-us.json | 1 + .../admin/src/src/assets/i18n/zh-hans.json | 1 + .../admin/src/src/assets/i18n/zh-hant.json | 1 + 13 files changed, 871 insertions(+), 223 deletions(-) create mode 100644 components/datalake-handler/admin/src/src/app/topics/topic-list/new-topic-model/new-topic-model.component.css create mode 100644 components/datalake-handler/admin/src/src/app/topics/topic-list/new-topic-model/new-topic-model.component.html create mode 100644 components/datalake-handler/admin/src/src/app/topics/topic-list/new-topic-model/new-topic-model.component.spec.ts create mode 100644 components/datalake-handler/admin/src/src/app/topics/topic-list/new-topic-model/new-topic-model.component.ts (limited to 'components/datalake-handler') diff --git a/components/datalake-handler/admin/src/src/app/app.module.ts b/components/datalake-handler/admin/src/src/app/app.module.ts index 575e9b78..1c73cfd2 100644 --- a/components/datalake-handler/admin/src/src/app/app.module.ts +++ b/components/datalake-handler/admin/src/src/app/app.module.ts @@ -82,6 +82,7 @@ import { CreateDashboardComponent } from './dashboard-setting/dashboard-list/cre import { TemplateListComponent } from './dashboard-setting/template/template-list/template-list.component'; import { NewTemplateModalComponent } from './dashboard-setting/template/template-list/new-template-modal/new-template-modal.component'; import { EditTemplateModalComponent } from './dashboard-setting/template/template-list/edit-template-modal/edit-template-modal.component'; +import { NewTopicModelComponent } from './topics/topic-list/new-topic-model/new-topic-model.component'; @NgModule({ declarations: [ @@ -111,6 +112,7 @@ import { EditTemplateModalComponent } from './dashboard-setting/template/templat TemplateListComponent, NewTemplateModalComponent, EditTemplateModalComponent, + NewTopicModelComponent, ], imports: [ @@ -141,6 +143,7 @@ import { EditTemplateModalComponent } from './dashboard-setting/template/templat HdfsComponent, TopicDetailModalComponent, TopicConfigModalComponent, + NewTopicModelComponent, CreateDashboardComponent, NewTemplateModalComponent, EditTemplateModalComponent diff --git a/components/datalake-handler/admin/src/src/app/core/models/topic.model.ts b/components/datalake-handler/admin/src/src/app/core/models/topic.model.ts index ac6a52b7..7abc18b6 100644 --- a/components/datalake-handler/admin/src/src/app/core/models/topic.model.ts +++ b/components/datalake-handler/admin/src/src/app/core/models/topic.model.ts @@ -37,3 +37,4 @@ export class Topic { // for UI display type: boolean; // 1: Configure 0: Unconfiure } + diff --git a/components/datalake-handler/admin/src/src/app/core/services/rest-api.service.ts b/components/datalake-handler/admin/src/src/app/core/services/rest-api.service.ts index 7eb5cf0c..05bfdd1f 100644 --- a/components/datalake-handler/admin/src/src/app/core/services/rest-api.service.ts +++ b/components/datalake-handler/admin/src/src/app/core/services/rest-api.service.ts @@ -116,9 +116,19 @@ export class RestApiService { ); } + addNewTopic(t: Topic): Observable { + return this.http + .post(prefix + "topics", t) + .pipe( + retry(1), + tap(_ => console.log(`add topic name=${t.name}`)), + catchError(this.handleError) + ); + } + addTopic(t: Topic): Observable { return this.http - .post(prefix + "topics", JSON.stringify(t), httpOptions) + .post(prefix + "topics", t) .pipe( retry(1), tap(_ => console.log(`add topic name=${t.name}`)), @@ -128,7 +138,7 @@ export class RestApiService { upadteTopic(t: Topic): Observable { return this.http - .put(prefix + "topics/" + t.name, JSON.stringify(t), httpOptions) + .put(prefix + "topics/" + t.name, t) .pipe( retry(1), tap(_ => this.extractData), @@ -137,7 +147,7 @@ export class RestApiService { } deleteTopic(name: string): Observable { - return this.http.delete(prefix + "topics/" + name, httpOptions).pipe( + return this.http.delete(prefix + "topics/" + name).pipe( retry(1), tap(_ => console.log(`deleted topic name=${name}`)), catchError(this.handleError) diff --git a/components/datalake-handler/admin/src/src/app/topics/topic-list/new-topic-model/new-topic-model.component.css b/components/datalake-handler/admin/src/src/app/topics/topic-list/new-topic-model/new-topic-model.component.css new file mode 100644 index 00000000..424c839b --- /dev/null +++ b/components/datalake-handler/admin/src/src/app/topics/topic-list/new-topic-model/new-topic-model.component.css @@ -0,0 +1,15 @@ +/* + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + 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. +*/ diff --git a/components/datalake-handler/admin/src/src/app/topics/topic-list/new-topic-model/new-topic-model.component.html b/components/datalake-handler/admin/src/src/app/topics/topic-list/new-topic-model/new-topic-model.component.html new file mode 100644 index 00000000..c45b8fdb --- /dev/null +++ b/components/datalake-handler/admin/src/src/app/topics/topic-list/new-topic-model/new-topic-model.component.html @@ -0,0 +1,229 @@ + + +
+ + + + + +
diff --git a/components/datalake-handler/admin/src/src/app/topics/topic-list/new-topic-model/new-topic-model.component.spec.ts b/components/datalake-handler/admin/src/src/app/topics/topic-list/new-topic-model/new-topic-model.component.spec.ts new file mode 100644 index 00000000..536f3a9e --- /dev/null +++ b/components/datalake-handler/admin/src/src/app/topics/topic-list/new-topic-model/new-topic-model.component.spec.ts @@ -0,0 +1,40 @@ +/* + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + 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 { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { NewTopicModelComponent } from './new-topic-model.component'; + +describe('NewTopicModelComponent', () => { + let component: NewTopicModelComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ NewTopicModelComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(NewTopicModelComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/components/datalake-handler/admin/src/src/app/topics/topic-list/new-topic-model/new-topic-model.component.ts b/components/datalake-handler/admin/src/src/app/topics/topic-list/new-topic-model/new-topic-model.component.ts new file mode 100644 index 00000000..91be8d0a --- /dev/null +++ b/components/datalake-handler/admin/src/src/app/topics/topic-list/new-topic-model/new-topic-model.component.ts @@ -0,0 +1,157 @@ +/* + Copyright (C) 2019 CMCC, Inc. and others. All rights reserved. + + 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 { + Component, + OnInit, + Input, + Output, + EventEmitter, + ViewChild, + ElementRef +} from "@angular/core"; +import {NgbActiveModal} from "@ng-bootstrap/ng-bootstrap"; +import {RestApiService} from "src/app/core/services/rest-api.service"; +import {AdminService} from "src/app/core/services/admin.service"; +import {Topic} from "src/app/core/models/topic.model"; + +@Component({ + selector: 'app-new-topic-model', + templateUrl: './new-topic-model.component.html', + styleUrls: ['./new-topic-model.component.css'] +}) +export class NewTopicModelComponent implements OnInit { + @Input() newTopic: Topic; + @Output() passEntry: EventEmitter = new EventEmitter(); + TopicInput: Topic; + // page elements + dbs: any = []; + dataFormats: Array = ["JSON", "XML"]; + tempSeletedDbs: any = []; + idExFields: Array = []; + idExNewField: any = {}; + @ViewChild("t_topicname") t_topicname: ElementRef; + @ViewChild("t_login") t_login: ElementRef; + @ViewChild("t_password") t_password: ElementRef; + @ViewChild("t_dataFormat") t_dataFormat: ElementRef; + @ViewChild("t_ttl") t_ttl: ElementRef; + + constructor( + public activeModal: NgbActiveModal, + public adminService: AdminService, + private restApiService: RestApiService + ) { + this.getDbs(); + } + + ngOnInit() { + this.newTopic = { + name: "", + login: "", + password:"", + sinkdbs: [], + enabled: false, + saveRaw: false, + dataFormat: this.dataFormats[0], + ttl: null, + correlateClearedMessage: false, + messageIdPath: null, + type:null + }; + this.TopicInput = new Topic(); + const feeds = { + name: this.newTopic.name, + login: this.newTopic.login, + password:this.newTopic.password, + sinkdbs: this.newTopic.sinkdbs, + enabled: this.newTopic.enabled, + saveRaw: this.newTopic.saveRaw, + dataFormat: this.newTopic.dataFormat, + ttl: this.newTopic.ttl, + correlateClearedMessage: this.newTopic.correlateClearedMessage, + messageIdPath: this.newTopic.messageIdPath, + type:null + }; + this.TopicInput = feeds; + this. idExFields = []; + if (this.TopicInput.messageIdPath != null) { + var feed = this.TopicInput.messageIdPath.split(","); + for (var i = 0; i < feed.length; i++) { + var data = { item: feed[i] }; + this.idExFields.push(data); + } + } else { + this.idExFields.push([]); + } + } + + getDbs() { + this.dbs = []; + this.restApiService.getDbList().subscribe((data: {}) => { + this.dbs = data; + }); + } + + updateSelectedDB(event: any, name: string) { + if (event.target.checked) { + if (!this.tempSeletedDbs.find(db => db === name)) { + this.tempSeletedDbs.push(name); + } + } else { + const index = this.tempSeletedDbs.indexOf(name, 0); + if (index > -1) { + this.tempSeletedDbs.splice(index, 1); + } + } + } + + addIdField() { + this.idExFields.push(this.idExNewField); + this.idExNewField = {}; + } + + deleteIdField(index: number) { + if (this.idExFields.length > 1) { + this.idExFields.splice(index, 1); + } + } + + passBack() { + this.newTopic = this.TopicInput; + this.newTopic.name = this.t_topicname.nativeElement.value; + this.newTopic.login = this.t_login.nativeElement.value; + this.newTopic.password = this.t_password.nativeElement.value; + this.newTopic.sinkdbs = this.tempSeletedDbs; + this.newTopic.dataFormat = this.t_dataFormat.nativeElement.value; + this.newTopic.ttl = this.t_ttl.nativeElement.value; + this.newTopic.messageIdPath = ""; + for (var i = 0; i < this.idExFields.length; i++) { + let item = "/"+this.idExFields[i].item; + if (i == 0) { + this.newTopic.messageIdPath = item; + } else { + this.newTopic.messageIdPath = + this.newTopic.messageIdPath + "," + item; + } + } + // Reset to default + if (this.newTopic.sinkdbs.length == 0) { + return false; + } + console.log(this.newTopic); + this.passEntry.emit(this.newTopic); + } + +} diff --git a/components/datalake-handler/admin/src/src/app/topics/topic-list/topic-detail-modal/topic-detail-modal.component.html b/components/datalake-handler/admin/src/src/app/topics/topic-list/topic-detail-modal/topic-detail-modal.component.html index 67b84b74..fa07903b 100644 --- a/components/datalake-handler/admin/src/src/app/topics/topic-list/topic-detail-modal/topic-detail-modal.component.html +++ b/components/datalake-handler/admin/src/src/app/topics/topic-list/topic-detail-modal/topic-detail-modal.component.html @@ -176,7 +176,7 @@ limitations under the License.
-
+
diff --git a/components/datalake-handler/admin/src/src/app/topics/topic-list/topic-list.component.html b/components/datalake-handler/admin/src/src/app/topics/topic-list/topic-list.component.html index 1e4ed1cc..519cc9da 100644 --- a/components/datalake-handler/admin/src/src/app/topics/topic-list/topic-list.component.html +++ b/components/datalake-handler/admin/src/src/app/topics/topic-list/topic-list.component.html @@ -37,9 +37,12 @@ limitations under the License.
- +
@@ -49,8 +52,9 @@ limitations under the License.
+ [footerHeight]="40" [rowHeight]="50" [scrollbarV]="true" [scrollbarH]="true" + [loadingIndicator]="loadingIndicator" [messages]="mesgNoData" [limit]="10" + (activate)="onActivate($event)"> @@ -346,193 +350,303 @@ limitations under the License. - - - - - - - - + container="body" tooltipClass="dl-db-icon-hover-enable" [openDelay]="300" [closeDelay]="300"> + + + + + + + + + + + + + + + - - - - - - - - + container="body" tooltipClass="dl-db-icon-hover-disable" [openDelay]="300" [closeDelay]="300"> + + + + + + + + + + + + + + + @@ -586,8 +700,8 @@ limitations under the License. - @@ -595,14 +709,16 @@ limitations under the License. + let-selectedCount="selectedCount" let-curPage="curPage" let-offset="offset" + let-isVisible="isVisible">
total: {{ rowCount.toLocaleString() }}
+ [pagerPreviousIcon]="'datatable-icon-prev'" [pagerNextIcon]="'datatable-icon-skip'" + [page]="curPage" + [size]="pageSize" [count]="rowCount" [hidden]="!(rowCount / pageSize > 1)" + (change)="topicTable.onFooterPage($event)">
diff --git a/components/datalake-handler/admin/src/src/app/topics/topic-list/topic-list.component.ts b/components/datalake-handler/admin/src/src/app/topics/topic-list/topic-list.component.ts index 6cb3852d..8f22307d 100644 --- a/components/datalake-handler/admin/src/src/app/topics/topic-list/topic-list.component.ts +++ b/components/datalake-handler/admin/src/src/app/topics/topic-list/topic-list.component.ts @@ -32,12 +32,14 @@ import { NgbModal } from "@ng-bootstrap/ng-bootstrap"; // modal import { TopicDetailModalComponent } from "./topic-detail-modal/topic-detail-modal.component"; import { TopicConfigModalComponent } from "./topic-config-modal/topic-config-modal.component"; +import { NewTopicModelComponent } from "./new-topic-model/new-topic-model.component"; // notify import { ToastrNotificationService } from "src/app/core/services/toastr-notification.service"; // Loading spinner import { NgxSpinnerService } from "ngx-spinner"; +import {AlertComponent} from "../../core/alert/alert.component"; @Component({ selector: "app-topic-list", @@ -52,6 +54,7 @@ export class TopicListComponent { topics: Topic[] = []; temp: Topic[] = []; // cache for topics tempTopicDetail: Topic; // temp for a topic + tempNewTopic: Topic; // temp for a newtopic loadingIndicator: boolean = true; mesgNoData = { @@ -76,7 +79,15 @@ export class TopicListComponent { setTimeout(() => { this.loadingIndicator = false; }, 5000); + this.init() + } + + ngOnInit() { + this.spinner.show(); + } + + init(){ this.initData().then(data => { this.initTopicList(this.topicListDmaap, this.topicListFeeder).then( data => { @@ -91,10 +102,6 @@ export class TopicListComponent { }); } - ngOnInit() { - this.spinner.show(); - } - async initData() { this.topicListDmaap = []; this.topicListDmaap = await this.getTopicList("dmaap"); @@ -133,7 +140,8 @@ export class TopicListComponent { // dmaap has topics if (dmaapList.length > 0) { - for (var i = 0; i < dmaapList.length; i++) { + let listLength = dmaapList.length>feederList.length ? dmaapList.length:feederList.length; + for (var i = 0; i < listLength; i++) { if (feederList.includes(dmaapList[i])) { let data = await this.getTopicDetail(dmaapList[i]); let feed = { @@ -150,7 +158,7 @@ export class TopicListComponent { type: true }; t.push(feed); - } else { + } else if(!feederList.includes(dmaapList[i]) && dmaapList[i]!=undefined){ let feed = { name: dmaapList[i], login: this.topicDefaultConfig.login, @@ -167,6 +175,24 @@ export class TopicListComponent { }; t.push(feed); } + if(!dmaapList.includes(feederList[i]) && feederList[i]!=undefined){ + let data = await this.getTopicDetail(feederList[i]); + let feed = { + name: feederList[i], + login: data.login, + password: data.password, + sinkdbs: data.sinkdbs, + enabled: data.enabled, + saveRaw: data.saveRaw, + dataFormat: data.dataFormat, + ttl: data.ttl, + correlateClearedMessage: data.correlateClearedMessage, + messageIdPath: data.messageIdPath, + type: true, + topicDb:true + }; + t.push(feed); + } } } else { // dmaap has no topics, only show topic in db @@ -192,6 +218,43 @@ export class TopicListComponent { return t; } + onActivate(event) { + const emitType = event.type; + if(emitType == "dblclick"){ + console.log('Activate Event', event); + let name = event.row.name; + this.openTopicModal(name); + } + + } + + openNewTopicModal(){ + const modalRef = this.modalService.open(NewTopicModelComponent, { + size: "lg", + centered: true + }); + modalRef.componentInstance.newTopic = this.tempNewTopic; + modalRef.componentInstance.passEntry.subscribe(receivedEntry => { + console.log(receivedEntry,"newtopic receivedEntry"); + this.tempNewTopic = receivedEntry; + this.restApiService.addNewTopic(this.tempNewTopic).subscribe( + res => { + this.init(); + this.notificationService.success("SUCCESSFULLY_CREARED"); + modalRef.close(); + this.updateFilter(this.searchText.nativeElement.value); + }, + err => { + this.notificationService.error(err); + modalRef.close(); + this.updateFilter(this.searchText.nativeElement.value); + } + ); + }) + + + } + openTopicModal(name: string) { if (name == "config") { const modalRef = this.modalService.open(TopicConfigModalComponent, { @@ -238,7 +301,6 @@ export class TopicListComponent { modalRef.componentInstance.topic = this.temp[index]; modalRef.componentInstance.passEntry.subscribe(receivedEntry => { this.tempTopicDetail = receivedEntry; - // Configured topic if (this.tempTopicDetail.type) { this.restApiService.getTopicsFromFeeder().subscribe( @@ -249,7 +311,7 @@ export class TopicListComponent { res => { this.temp[index] = this.tempTopicDetail; this.topics = this.temp; - this.notificationService.success("Success updated."); + this.notificationService.success("SUCCESSFULLY_UPDATED"); modalRef.close(); this.updateFilter(this.searchText.nativeElement.value); }, @@ -263,7 +325,8 @@ export class TopicListComponent { // Insert topic from db this.restApiService.addTopic(this.tempTopicDetail).subscribe( res => { - this.notificationService.success("Success inserted."); + this.init(); + this.notificationService.success("SUCCESSFULLY_CREARED"); modalRef.close(); this.updateFilter(this.searchText.nativeElement.value); }, @@ -284,23 +347,8 @@ export class TopicListComponent { // Reset to default and delete topic from db this.restApiService.deleteTopic(this.tempTopicDetail.name).subscribe( res => { - this.temp[index].enabled = this.topicDefaultConfig.enabled; - this.temp[index].login = this.topicDefaultConfig.login; - this.temp[index].password = this.topicDefaultConfig.password; - this.temp[index].sinkdbs = this.topicDefaultConfig.sinkdbs; - this.temp[index].dataFormat = this.topicDefaultConfig.dataFormat; - this.temp[index].ttl = this.topicDefaultConfig.ttl; - this.temp[index].saveRaw = this.topicDefaultConfig.saveRaw; - this.temp[ - index - ].correlateClearedMessage = this.topicDefaultConfig.correlateClearedMessage; - this.temp[ - index - ].messageIdPath = this.topicDefaultConfig.messageIdPath; - this.temp[index].type = false; - - this.topics = this.temp; - this.notificationService.success("Success deleted."); + this.init(); + this.notificationService.success("SUCCESSFULLY_DELETED"); modalRef.close(); this.updateFilter(this.searchText.nativeElement.value); }, @@ -315,6 +363,32 @@ export class TopicListComponent { } } + deleteTopicModal(name: string){ + const index = this.temp.findIndex(t => t.name === name); + const modalRef = this.modalService.open(AlertComponent, { + size: "sm", + centered: true + }); + modalRef.componentInstance.message = "ARE_YOU_SURE_DELETE"; + console.log(this.temp[index]); + modalRef.componentInstance.passEntry.subscribe(receivedEntry => { + this.restApiService.deleteTopic(this.temp[index].name).subscribe( + res => { + this.init(); + this.notificationService.success("SUCCESSFULLY_DELETED"); + modalRef.close(); + this.updateFilter(this.searchText.nativeElement.value); + }, + err => { + this.notificationService.error(err); + modalRef.close(); + this.updateFilter(this.searchText.nativeElement.value); + } + ); + + }) + } + getTopicDetail(name: string) { return this.restApiService.getTopicDetail(name).toPromise(); } diff --git a/components/datalake-handler/admin/src/src/assets/i18n/en-us.json b/components/datalake-handler/admin/src/src/assets/i18n/en-us.json index 8675df7d..64a54bb5 100644 --- a/components/datalake-handler/admin/src/src/assets/i18n/en-us.json +++ b/components/datalake-handler/admin/src/src/assets/i18n/en-us.json @@ -21,6 +21,7 @@ "ID_EXTRACTION": "ID extraction", "CONFIGURED": "Configured", "UNCONFIGURED": "Unconfigured", + "NEW_TOPIC":"New topic", "DATABASE_CONNECTIONS": "Database connections", "BUCKET": "Bucket", diff --git a/components/datalake-handler/admin/src/src/assets/i18n/zh-hans.json b/components/datalake-handler/admin/src/src/assets/i18n/zh-hans.json index df171b59..16d5b58d 100644 --- a/components/datalake-handler/admin/src/src/assets/i18n/zh-hans.json +++ b/components/datalake-handler/admin/src/src/assets/i18n/zh-hans.json @@ -21,6 +21,7 @@ "ID_EXTRACTION": "ID提取​", "CONFIGURED": "已配置", "UNCONFIGURED": "未配置​", + "NEW_TOPIC":"新建主题", "DATABASE_CONNECTIONS": "数据库连接​", "BUCKET": "Bucket", diff --git a/components/datalake-handler/admin/src/src/assets/i18n/zh-hant.json b/components/datalake-handler/admin/src/src/assets/i18n/zh-hant.json index 48e370b0..f8fc0fa7 100644 --- a/components/datalake-handler/admin/src/src/assets/i18n/zh-hant.json +++ b/components/datalake-handler/admin/src/src/assets/i18n/zh-hant.json @@ -21,6 +21,7 @@ "ID_EXTRACTION": "ID提取​", "CONFIGURED": "已配置", "UNCONFIGURED": "未配置​", + "NEW_TOPIC":"新建主題", "DATABASE_CONNECTIONS": "資料庫連線​", -- cgit