diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..e69de29b diff --git a/docs/docs/assets/images/others/monitor/query/img.png b/docs/docs/assets/images/others/monitor/query/img.png new file mode 100644 index 00000000..37cf9d99 Binary files /dev/null and b/docs/docs/assets/images/others/monitor/query/img.png differ diff --git a/docs/docs/assets/images/others/monitor/query/img_1.png b/docs/docs/assets/images/others/monitor/query/img_1.png new file mode 100644 index 00000000..8c11d08d Binary files /dev/null and b/docs/docs/assets/images/others/monitor/query/img_1.png differ diff --git a/docs/docs/assets/images/others/monitor/query/img_2.png b/docs/docs/assets/images/others/monitor/query/img_2.png new file mode 100644 index 00000000..d4294109 Binary files /dev/null and b/docs/docs/assets/images/others/monitor/query/img_2.png differ diff --git a/docs/docs/assets/images/others/monitor/query/img_3.png b/docs/docs/assets/images/others/monitor/query/img_3.png new file mode 100644 index 00000000..28585dd7 Binary files /dev/null and b/docs/docs/assets/images/others/monitor/query/img_3.png differ diff --git a/docs/docs/assets/images/query/img.png b/docs/docs/assets/images/query/img.png new file mode 100644 index 00000000..07bc9fad Binary files /dev/null and b/docs/docs/assets/images/query/img.png differ diff --git a/docs/docs/assets/images/query/snippet/img.png b/docs/docs/assets/images/query/snippet/img.png new file mode 100644 index 00000000..3043b11b Binary files /dev/null and b/docs/docs/assets/images/query/snippet/img.png differ diff --git a/docs/docs/assets/images/query/snippet/img_1.png b/docs/docs/assets/images/query/snippet/img_1.png new file mode 100644 index 00000000..52130586 Binary files /dev/null and b/docs/docs/assets/images/query/snippet/img_1.png differ diff --git a/docs/docs/assets/images/query/snippet/img_2.png b/docs/docs/assets/images/query/snippet/img_2.png new file mode 100644 index 00000000..acc660f4 Binary files /dev/null and b/docs/docs/assets/images/query/snippet/img_2.png differ diff --git a/docs/docs/assets/images/query/snippet/img_3.png b/docs/docs/assets/images/query/snippet/img_3.png new file mode 100644 index 00000000..253585ff Binary files /dev/null and b/docs/docs/assets/images/query/snippet/img_3.png differ diff --git a/docs/docs/assets/images/query/snippet/img_4.png b/docs/docs/assets/images/query/snippet/img_4.png new file mode 100644 index 00000000..6f330b0c Binary files /dev/null and b/docs/docs/assets/images/query/snippet/img_4.png differ diff --git a/docs/docs/assets/images/versions/1.15.0/img.png b/docs/docs/assets/images/versions/1.15.0/img.png new file mode 100644 index 00000000..2433e627 Binary files /dev/null and b/docs/docs/assets/images/versions/1.15.0/img.png differ diff --git a/docs/docs/assets/images/versions/1.15.0/img_1.png b/docs/docs/assets/images/versions/1.15.0/img_1.png new file mode 100644 index 00000000..bcc87eea Binary files /dev/null and b/docs/docs/assets/images/versions/1.15.0/img_1.png differ diff --git a/docs/docs/assets/images/versions/1.15.0/img_2.png b/docs/docs/assets/images/versions/1.15.0/img_2.png new file mode 100644 index 00000000..ff93e984 Binary files /dev/null and b/docs/docs/assets/images/versions/1.15.0/img_2.png differ diff --git a/docs/docs/assets/images/versions/1.15.0/img_3.png b/docs/docs/assets/images/versions/1.15.0/img_3.png new file mode 100644 index 00000000..b9073bc1 Binary files /dev/null and b/docs/docs/assets/images/versions/1.15.0/img_3.png differ diff --git a/docs/docs/assets/images/versions/1.15.0/img_4.png b/docs/docs/assets/images/versions/1.15.0/img_4.png new file mode 100644 index 00000000..2e2fc7a3 Binary files /dev/null and b/docs/docs/assets/images/versions/1.15.0/img_4.png differ diff --git a/docs/docs/assets/images/versions/1.15.0/img_5.png b/docs/docs/assets/images/versions/1.15.0/img_5.png new file mode 100644 index 00000000..e9288db3 Binary files /dev/null and b/docs/docs/assets/images/versions/1.15.0/img_5.png differ diff --git a/docs/docs/assets/images/versions/1.15.0/img_6.png b/docs/docs/assets/images/versions/1.15.0/img_6.png new file mode 100644 index 00000000..4089f073 Binary files /dev/null and b/docs/docs/assets/images/versions/1.15.0/img_6.png differ diff --git a/docs/docs/assets/images/versions/1.15.0/img_7.png b/docs/docs/assets/images/versions/1.15.0/img_7.png new file mode 100644 index 00000000..3a3472e1 Binary files /dev/null and b/docs/docs/assets/images/versions/1.15.0/img_7.png differ diff --git a/docs/docs/assets/images/versions/1.15.0/img_8.png b/docs/docs/assets/images/versions/1.15.0/img_8.png new file mode 100644 index 00000000..41e9e086 Binary files /dev/null and b/docs/docs/assets/images/versions/1.15.0/img_8.png differ diff --git a/docs/docs/assets/images/versions/1.15.0/img_9.png b/docs/docs/assets/images/versions/1.15.0/img_9.png new file mode 100644 index 00000000..17c77de7 Binary files /dev/null and b/docs/docs/assets/images/versions/1.15.0/img_9.png differ diff --git a/docs/docs/assets/images/versions/1.15.0/themes.png b/docs/docs/assets/images/versions/1.15.0/themes.png new file mode 100644 index 00000000..d1630c73 Binary files /dev/null and b/docs/docs/assets/images/versions/1.15.0/themes.png differ diff --git a/docs/docs/development/version/1.15.0-development.md b/docs/docs/development/version/1.16.0-development.md similarity index 91% rename from docs/docs/development/version/1.15.0-development.md rename to docs/docs/development/version/1.16.0-development.md index 4ab27505..21f917ab 100644 --- a/docs/docs/development/version/1.15.0-development.md +++ b/docs/docs/development/version/1.16.0-development.md @@ -3,7 +3,7 @@ template: overrides/main.html icon: material/gesture-tap-button --- -DBM Version for `1.15.0` is development! +DBM Version for `1.16.0` is development! !!! danger "Warning" diff --git a/docs/docs/reference/monitor/monitor_query.md b/docs/docs/reference/monitor/monitor_query.md new file mode 100644 index 00000000..ea9020fa --- /dev/null +++ b/docs/docs/reference/monitor/monitor_query.md @@ -0,0 +1,54 @@ +--- +template: overrides/main.html +--- + +This document mainly introduces how we can use the `Slow query` monitoring function provided by the software. + +Move the mouse to the top menu `Monitor` and wait for the drop-down options to appear, click `Query` to enter the query monitoring interface, which is similar to the following page + +![img.png](../../assets/images/others/monitor/query/img.png) + +The upper part of the page is the data chart display & function configuration area, and the lower part is the detailed data list area + +#### Data charting & Feature Configuration + +--- + +The drop-down selection box on the top left is used to select the configured data source. After selection, the software will initiate a request to the service to obtain information, and return a data chart similar to the following + +![img_1.png](../../assets/images/others/monitor/query/img_1.png) + +There is a `Number` input device at the top right + +`Numeric input` is used to mark the maximum time-consuming limit of the query (unit: milliseconds) + +#### Details of the data + +--- + +The drop-down selection box on the top left is used to select the configured data source. After selection, the software will initiate a request to the service to obtain information, and return results similar to the following + +![img_2.png](../../assets/images/others/monitor/query/img_2.png) + +| Property | Description | +|--------------|------------------------------------------------------------| +| user | Query the user used | +| host | Query the client host | +| hash | Query the generated hash data | +| time | Query creation time | +| elapsed(ms) | Query time (ms) | +| memoryUsage | Memory used by query | +| rows | Query the total number of rows | +| bytes | Total number of bytes queried | +| readRows | Query the total number of rows of read metadata | +| bytesRead | Query the total number of bytes of metadata read | +| writtenRows | The total number of bytes of metadata written to the query | +| bytesWritten | The total number of bytes of metadata written to the query | + +#### Action + +--- + +:octicons-search-16:{.blue} button To query the DDL statement of the operation + +![img_3.png](../../assets/images/others/monitor/query/img_3.png) diff --git a/docs/docs/reference/query/query_history.md b/docs/docs/reference/query/query_history.md index 1c207a58..8002da2a 100644 --- a/docs/docs/reference/query/query_history.md +++ b/docs/docs/reference/query/query_history.md @@ -4,10 +4,6 @@ template: overrides/main.html The query history function is mainly used to mark some of our query records for each data source. -!!! warning - - Currently supports up to `100` query history, we will expand this function to support more data storage in the future! - Move the mouse to the top menu `Query` and wait for the drop-down options to appear, click `History` to enter the query history interface, which is similar to the following page ![Query History](/assets/images/query/query_history.png) @@ -31,10 +27,24 @@ On the top right side of the page we can see the ", "description": "ClickHouse DataBase GUI", "github": "https://github.com/EdurtIO/dbm.git", @@ -59,11 +59,12 @@ "highcharts": "^9.3.2", "jsstore": "^4.3.8", "lodash": "^4.17.21", - "moment": "^2.29.1", + "moment": "^2.29.2", "ng-zorro-antd": "^12.1.0", "ngx-clipboard": "^14.0.2", "ngx-easy-table": "^15.2.0", "ngx-markdown": "^13.1.0", + "ngx-moment": "^6.0.2", "node-sql-parser": "^4.1.1", "rxjs": "~6.6.0", "sass-loader": "^12.3.0", diff --git a/src/renderer/app/app.module.ts b/src/renderer/app/app.module.ts index 7b925b86..bd055199 100644 --- a/src/renderer/app/app.module.ts +++ b/src/renderer/app/app.module.ts @@ -5,7 +5,7 @@ import { AppComponent } from './app.component'; import { CommonModule, HashLocationStrategy, LocationStrategy } from '@angular/common'; import { HttpClientModule } from '@angular/common/http'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { NzConfig, NZ_CONFIG } from 'ng-zorro-antd/core/config'; +import { NZ_CONFIG, NzConfig } from 'ng-zorro-antd/core/config'; const ngZorroConfig: NzConfig = { card: { @@ -13,6 +13,12 @@ const ngZorroConfig: NzConfig = { }, button: { nzSize: 'small' + }, + table: { + nzSize: 'small' + }, + modal: { + nzMaskClosable: false } }; @@ -32,8 +38,8 @@ const ngZorroConfig: NzConfig = { provide: LocationStrategy, useClass: HashLocationStrategy }, - { provide: NZ_CONFIG, useValue: ngZorroConfig } -], + {provide: NZ_CONFIG, useValue: ngZorroConfig} + ], bootstrap: [AppComponent] }) export class AppModule { diff --git a/src/renderer/app/common-share.module.ts b/src/renderer/app/common-share.module.ts index d9d63005..19e0b6f8 100644 --- a/src/renderer/app/common-share.module.ts +++ b/src/renderer/app/common-share.module.ts @@ -3,7 +3,7 @@ import { DdlQueryComponent } from '@renderer/components/query/ddl/ddl.query.comp import { NgZorroAntdModule } from '@renderer/app/ng-zorro-antd.module'; import { TranslateModule } from '@ngx-translate/core'; import { CodemirrorModule } from '@ctrl/ngx-codemirror'; -import { FormsModule } from '@angular/forms'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { ClipboardComService } from '@renderer/services/other/clipboard.service'; import { BasicTableComponent } from '@renderer/components/table/basic/basic.table.component'; import { CommonModule } from '@angular/common'; @@ -13,6 +13,8 @@ import { ChartModule } from 'angular-highcharts'; import { EmptyAntdComponent } from '@renderer/components/antd/empty/empty.antd.component'; import { DrividerAntdComponent } from '@renderer/components/antd/drivider/drivider.antd.component'; import { TableModule } from 'ngx-easy-table'; +import { MomentModule } from 'ngx-moment'; +import { CreateSnippetComponent } from '@renderer/components/snippet/create/create.snippet.component'; @NgModule({ imports: [ @@ -23,14 +25,17 @@ import { TableModule } from 'ngx-easy-table'; CommonModule, ServiceModule, ChartModule, - TableModule + TableModule, + MomentModule, + ReactiveFormsModule ], declarations: [ DdlQueryComponent, BasicTableComponent, LineChartsComponent, EmptyAntdComponent, - DrividerAntdComponent + DrividerAntdComponent, + CreateSnippetComponent ], providers: [ ClipboardComService @@ -40,7 +45,8 @@ import { TableModule } from 'ngx-easy-table'; BasicTableComponent, LineChartsComponent, EmptyAntdComponent, - DrividerAntdComponent + DrividerAntdComponent, + CreateSnippetComponent ] }) export class CommonShareModule { diff --git a/src/renderer/app/layout/header/header.component.html b/src/renderer/app/layout/header/header.component.html index 837e3cab..5e3c8b65 100644 --- a/src/renderer/app/layout/header/header.component.html +++ b/src/renderer/app/layout/header/header.component.html @@ -18,6 +18,11 @@ {{ 'common.history' | translate }} +
  • + + {{ 'common.snippet' | translate }} + +
  • @@ -110,9 +115,8 @@ {{version}} - + (nzOnCancel)="handlerUpdate(false)" [nzMaskClosable]="false" [nzClosable]="false" nzWidth="80%"> {{'common.update'|translate}}
    @@ -183,6 +187,6 @@ + [disabled]="!disabled.button">{{'common.cancel'|translate}} - \ No newline at end of file + diff --git a/src/renderer/app/layout/layout.component.html b/src/renderer/app/layout/layout.component.html index 2fc6ae8b..31276e62 100644 --- a/src/renderer/app/layout/layout.component.html +++ b/src/renderer/app/layout/layout.component.html @@ -7,8 +7,29 @@ App
    + + + {{'alert.migrate_datasource'|translate}}  + + +
    - + Design ©2021 Implement By EdurtIO + + + +
    +

    {{migrateConfirmMessage}}

    +
    +
    + +
    +
    + diff --git a/src/renderer/app/layout/layout.component.ts b/src/renderer/app/layout/layout.component.ts index 42b3b01c..2cc68545 100644 --- a/src/renderer/app/layout/layout.component.ts +++ b/src/renderer/app/layout/layout.component.ts @@ -3,6 +3,11 @@ import { TranslateService } from '@ngx-translate/core'; import { BasicService } from '@renderer/services/system/basic.service'; import { SystemBasicModel } from '@renderer/model/system.model'; import { TranslateUtils } from '@renderer/utils/translate.utils'; +import { StringUtils } from '@renderer/utils/string.utils'; +import { DatasourceService } from '@renderer/services/management/datasource.service'; +import { RequestUtils } from '@renderer/utils/request.utils'; +import { DatasourceModel } from '@renderer/model/datasource.model'; +import { NzMessageService } from 'ng-zorro-antd/message'; @Component({ selector: 'app-layout', @@ -37,13 +42,48 @@ import { TranslateUtils } from '@renderer/utils/translate.utils'; ] }) export class LayoutComponent implements OnInit { + visible: boolean = false; + migrateConfirmMessage: string; + migrateLoading: boolean = false; + dataSources: DatasourceModel[] = new Array(); + constructor(private translate: TranslateService, - private basicService: BasicService) { + private basicService: BasicService, + private messageService: NzMessageService, + private dataSourceService: DatasourceService) { const basicConfig = this.basicService.get() === null ? new SystemBasicModel() : this.basicService.get(); this.translate.setDefaultLang(basicConfig.language); TranslateUtils.init(translate); + this.initDataSources(); } ngOnInit() { } + + initDataSources() { + this.dataSources = JSON.parse(localStorage.getItem(RequestUtils.KEY_DATASOURCE)); + } + + handlerMigrateShow(value: boolean) { + this.visible = value; + if (value) { + this.migrateConfirmMessage = StringUtils.format(this.translate.instant('formatter.migrate_data'), + [this.dataSources.length]); + } + } + + handlerMigrate() { + this.migrateLoading = true; + this.dataSources.forEach(dataSource => { + this.dataSourceService.save(dataSource).then(() => { + }).catch(error => { + this.messageService.error(error); + }); + }); + this.migrateLoading = false; + this.visible = false; + localStorage.removeItem(RequestUtils.KEY_DATASOURCE); + this.initDataSources(); + this.messageService.success(this.translate.instant('common.success')); + } } diff --git a/src/renderer/app/layout/layout.module.ts b/src/renderer/app/layout/layout.module.ts index 1b81543a..993d4f44 100644 --- a/src/renderer/app/layout/layout.module.ts +++ b/src/renderer/app/layout/layout.module.ts @@ -10,6 +10,8 @@ import { TranslateHttpLoader } from '@ngx-translate/http-loader'; import { NgZorroAntdModule } from '@renderer/app/ng-zorro-antd.module'; import { BasicService } from '@renderer/services/system/basic.service'; import { MarkdownModule } from 'ngx-markdown'; +import { DatasourceService } from '@renderer/services/management/datasource.service'; +import { HttpService } from '@renderer/services/http.service'; const httpLoaderFactory = (http: HttpClient): TranslateHttpLoader => new TranslateHttpLoader(http, './renderer/assets/i18n/', '.json'); @@ -34,7 +36,9 @@ const httpLoaderFactory = (http: HttpClient): TranslateHttpLoader => }) ], providers: [ - BasicService + BasicService, + DatasourceService, + HttpService ] }) export class LayoutModule { diff --git a/src/renderer/app/layout/layout.routing.ts b/src/renderer/app/layout/layout.routing.ts index 2755c895..1432df8f 100644 --- a/src/renderer/app/layout/layout.routing.ts +++ b/src/renderer/app/layout/layout.routing.ts @@ -20,6 +20,10 @@ const LAYOUT_ROUTES: Routes = [ path: 'query', loadChildren: () => import('../pages/query/query/query.module').then(m => m.QueryModule) }, + { + path: 'snippet', + loadChildren: () => import('../pages/query/snippet/snippet.module').then(m => m.SnippetModule) + }, { path: 'history', loadChildren: () => import('../pages/query/history/history.module').then(m => m.HistoryModule) diff --git a/src/renderer/app/ng-zorro-antd.module.ts b/src/renderer/app/ng-zorro-antd.module.ts index e1953371..cc962f07 100644 --- a/src/renderer/app/ng-zorro-antd.module.ts +++ b/src/renderer/app/ng-zorro-antd.module.ts @@ -35,6 +35,8 @@ import { NzResultModule } from 'ng-zorro-antd/result'; import { NzCollapseModule } from 'ng-zorro-antd/collapse'; import { NzBadgeModule } from 'ng-zorro-antd/badge'; import { NzPaginationModule } from 'ng-zorro-antd/pagination'; +import { NzDrawerModule } from 'ng-zorro-antd/drawer'; +import { NzTypographyModule } from 'ng-zorro-antd/typography'; @NgModule({ declarations: [], @@ -74,7 +76,9 @@ import { NzPaginationModule } from 'ng-zorro-antd/pagination'; NzResultModule, NzCollapseModule, NzBadgeModule, - NzPaginationModule + NzPaginationModule, + NzDrawerModule, + NzTypographyModule ] }) export class NgZorroAntdModule { diff --git a/src/renderer/app/pages/home/home.component.ts b/src/renderer/app/pages/home/home.component.ts index 83647aee..9dd11624 100644 --- a/src/renderer/app/pages/home/home.component.ts +++ b/src/renderer/app/pages/home/home.component.ts @@ -5,6 +5,7 @@ import { DatasourceService } from '@renderer/services/management/datasource.serv import { QueryService } from '@renderer/services/query/query.service'; import { RequestModel } from '@renderer/model/request.model'; import { ClickhousePluginService } from '@renderer/services/plugin/clickhouse.plugin.service'; +import { DatasourceModel } from '@renderer/model/datasource.model'; @Component({ selector: 'app-home', @@ -12,21 +13,23 @@ import { ClickhousePluginService } from '@renderer/services/plugin/clickhouse.pl }) export class HomeComponent implements OnInit { version: string = PackageUtils.get('version'); - dataSources: any[]; + dataSources: DatasourceModel[] = new Array(); chartsConfig: ChartsModel[] = new Array(); chartsSkeleton: boolean[] = new Array(); constructor(private datasourceService: DatasourceService, private queryService: QueryService, private clickhousePluginService: ClickhousePluginService) { - this.dataSources = this.datasourceService.getAll()?.data?.columns; for (let i = 0; i < this.chartsConfig.length; i++) { this.chartsSkeleton[i] = true; } } ngOnInit() { - this.handlerInitChart(); + this.datasourceService.getAll().then(response => { + this.dataSources = response; + this.handlerInitChart(); + }); } handlerInitChart() { diff --git a/src/renderer/app/pages/management/datasource/datasource.component.html b/src/renderer/app/pages/management/datasource/datasource.component.html index 1011bf31..bd8858c9 100644 --- a/src/renderer/app/pages/management/datasource/datasource.component.html +++ b/src/renderer/app/pages/management/datasource/datasource.component.html @@ -1,5 +1,5 @@ - @@ -11,7 +11,7 @@ - + {{'common.alias' | translate}} @@ -45,7 +45,7 @@ nz-tooltip nzTooltipTitle="{{'common.delete' | translate}}" [nzCancelText]="'common.cancel'|translate" [nzOkText]="'common.ok'|translate" - (nzOnConfirm)="handlerDelete(data.alias)"> + (nzOnConfirm)="handlerDelete(data.id)"> + +
      +
    • + {{command.name}} +
    • +
    +
    - - + +
      -
    • - {{command.name}} +
    • +  {{'common.quick' | translate}}{{'common.query' | translate}} +
    • +
    • +  {{'common.code' | translate}}{{'common.snippet' | translate}}
    @@ -103,3 +121,11 @@ (emitter)="handlerQuickQuery(true)" (emitterValue)="handlerQuickQueryProcessor($event)"> + + + + diff --git a/src/renderer/app/pages/query/query/query.component.ts b/src/renderer/app/pages/query/query/query.component.ts index b3dcd230..996983bf 100644 --- a/src/renderer/app/pages/query/query/query.component.ts +++ b/src/renderer/app/pages/query/query/query.component.ts @@ -7,7 +7,6 @@ import { QueryService } from '@renderer/services/query/query.service'; import { RequestModel } from '@renderer/model/request.model'; import { StringUtils } from '@renderer/utils/string.utils'; import { QueryHistoryModel } from '@renderer/model/query.history.model'; -import { Md5 } from 'ts-md5'; import { QueryHistoryService } from '@renderer/services/query/query.history.service'; import { NzMessageService } from 'ng-zorro-antd/message'; import { StateEnum } from '@renderer/enum/state.enum'; @@ -15,6 +14,8 @@ import { SqlUtils } from '@renderer/utils/sql.utils'; import { ResponseDataModel } from '@renderer/model/response.model'; import { SystemEditorModel } from '@renderer/model/system.model'; import { CommandModel } from '@renderer/model/command.model'; +import { SnippetModel } from '@renderer/model/snippet.model'; +import { ActionEnum } from '@renderer/enum/action.enum'; @Component({ selector: 'app-query', @@ -37,6 +38,13 @@ export class QueryComponent extends BaseComponent implements AfterViewInit { loadingContainers = []; processorContainers = []; containerSelected = 0; + codeSnippet = { + disabled: false, + value: SnippetModel + }; + action: ActionEnum; + actionComponent = ActionEnum; + snippetValue: string; constructor(private editorService: EditorService, private datasourceService: DatasourceService, @@ -46,7 +54,9 @@ export class QueryComponent extends BaseComponent implements AfterViewInit { super(); const cache = this.editorService.get() === null ? new SystemEditorModel() : this.editorService.get(); this.editorConfig = Object.assign(this.editorService.getDefault(), cache); - this.dataSources = this.datasourceService.getAll()?.data?.columns; + this.datasourceService.getAll().then(response => { + this.dataSources = response; + }); this.editorContainers.push('Editor ' + 1); this.resultContainers.push('Editor ' + 1 + ' Result'); this.loadingContainers.push({loading: false}); @@ -98,35 +108,37 @@ export class QueryComponent extends BaseComponent implements AfterViewInit { } queryHistory.startTime = Date.parse(new Date().toString()); const request = new RequestModel(); - request.config = this.datasourceService.getAll(this.datasource)?.data?.columns[0]; - queryHistory.server = this.datasource; - queryHistory.query = sql; - this.processorContainers[this.containerSelected].icon = 'spinner fa-spin'; - this.processorContainers[this.containerSelected].color = 'cyan'; - this.queryService.getResponse(request, sql).then(response => { - if (response.status) { - queryHistory.state = StateEnum.success; - this.processorContainers[this.containerSelected].icon = 'check-circle'; - this.processorContainers[this.containerSelected].color = '#87d068'; - if (response.data) { - this.responseTableData[this.containerSelected] = response.data; + this.datasourceService.findByAlias(this.datasource).then(response => { + request.config = response; + queryHistory.server = this.datasource; + queryHistory.query = sql; + this.processorContainers[this.containerSelected].icon = 'spinner fa-spin'; + this.processorContainers[this.containerSelected].color = 'cyan'; + this.queryService.getResponse(request, sql).then(response => { + if (response.status) { + queryHistory.state = StateEnum.success; + this.processorContainers[this.containerSelected].icon = 'check-circle'; + this.processorContainers[this.containerSelected].color = '#87d068'; + if (response.data) { + this.responseTableData[this.containerSelected] = response.data; + } else { + this.messageService.success('Operation is successful!'); + } } else { - this.messageService.success('Operation is successful!'); + this.messageService.error(response.message); + queryHistory.message = response.message; + queryHistory.state = StateEnum.failure; + this.processorContainers[this.containerSelected].icon = 'times-circle'; + this.processorContainers[this.containerSelected].color = '#f50'; } - } else { - this.messageService.error(response.message); - queryHistory.message = response.message; - queryHistory.state = StateEnum.failure; - this.processorContainers[this.containerSelected].icon = 'times-circle'; - this.processorContainers[this.containerSelected].color = '#f50'; - } - this.disabledButton.execute = false; - this.loadingContainers[this.containerSelected].loading = false; - this.loading.button = false; - this.disabledButton.cancel = true; - queryHistory.endTime = Date.parse(new Date().toString()); - queryHistory.elapsedTime = queryHistory.endTime - queryHistory.startTime; - this.queryHistoryService.save(queryHistory); + this.disabledButton.execute = false; + this.loadingContainers[this.containerSelected].loading = false; + this.loading.button = false; + this.disabledButton.cancel = true; + queryHistory.endTime = Date.parse(new Date().toString()); + queryHistory.elapsedTime = queryHistory.endTime - queryHistory.startTime; + this.queryHistoryService.save(queryHistory); + }); }); } @@ -178,4 +190,27 @@ export class QueryComponent extends BaseComponent implements AfterViewInit { handlerExecuteCommand(command: CommandModel) { this.handlerExecute(command); } + + handlerCodeSnippet(close?: boolean) { + if (close) { + this.codeSnippet.disabled = false; + } else { + this.codeSnippet.disabled = true; + } + } + + handlerCodeSnippetProcessor(sql?: string) { + const codeMirror = this.codeEditors.get(this.containerSelected)['codeMirror']; + codeMirror.setValue(sql); + } + + handlerShowCreateSnippet(type: ActionEnum): void { + this.dialog.create = true; + this.action = type; + this.snippetValue = this.codeEditors.get(this.containerSelected)['codeMirror'].getValue(); + } + + handlerCloseCreateSnippet(event: boolean) { + this.dialog.create = false; + } } diff --git a/src/renderer/app/pages/query/query/query.module.ts b/src/renderer/app/pages/query/query/query.module.ts index d252aa85..8cb592fb 100644 --- a/src/renderer/app/pages/query/query/query.module.ts +++ b/src/renderer/app/pages/query/query/query.module.ts @@ -14,6 +14,9 @@ import { QuickQueryComponent } from '@renderer/components/query/quick/quick.quer import { QueryQuickService } from '@renderer/services/query/query.quick.service'; import { ServiceModule } from '@renderer/app/service.module'; import { CommonShareModule } from '@renderer/app/common-share.module'; +import { QuoteSnippetComponent } from '@renderer/components/snippet/quote/quote.snippet.component'; +import { SnippetService } from '@renderer/services/snippet/snippet.service'; +import { TableModule } from 'ngx-easy-table'; const QUERY_ROUTES: Routes = [ {path: '', component: QueryComponent} @@ -28,19 +31,22 @@ const QUERY_ROUTES: Routes = [ NgZorroAntdModule, ServiceModule, RouterModule.forChild(QUERY_ROUTES), - CommonShareModule + CommonShareModule, + TableModule ], exports: [], declarations: [ QueryComponent, - QuickQueryComponent + QuickQueryComponent, + QuoteSnippetComponent ], providers: [ EditorService, DatasourceService, QueryService, QueryHistoryService, - QueryQuickService + QueryQuickService, + SnippetService ] }) export class QueryModule { diff --git a/src/renderer/app/pages/query/snippet/snippet.component.html b/src/renderer/app/pages/query/snippet/snippet.component.html new file mode 100644 index 00000000..dc430929 --- /dev/null +++ b/src/renderer/app/pages/query/snippet/snippet.component.html @@ -0,0 +1,77 @@ + + + + + + + + + + + + + {{'common.id'|translate}} + {{'common.name'|translate}} + {{'common.description'|translate}} + {{'common.code'|translate}} + {{'common.created'|translate}} + {{'common.updated'|translate}} + {{'common.action'|translate}} + + + + + + {{data.id}} + + {{data.name}} + + + {{data.description}} + + + + + {{data.created|amDateFormat:'YYYY-MM-DD HH:mm:ss'}} + {{data.updated|amDateFormat:'YYYY-MM-DD HH:mm:ss'}} + + + + + + + + + + + + + + + + + + diff --git a/src/renderer/app/pages/query/snippet/snippet.component.ts b/src/renderer/app/pages/query/snippet/snippet.component.ts new file mode 100644 index 00000000..1787d910 --- /dev/null +++ b/src/renderer/app/pages/query/snippet/snippet.component.ts @@ -0,0 +1,85 @@ +import { Component } from '@angular/core'; +import { BaseComponent } from '@renderer/app/base.component'; +import { NzModalService } from 'ng-zorro-antd/modal'; +import { NzMessageService } from 'ng-zorro-antd/message'; +import { TranslateService } from '@ngx-translate/core'; +import { Config, DefaultConfig } from 'ngx-easy-table'; +import { ActionEnum } from '@renderer/enum/action.enum'; +import { SnippetModel } from '@renderer/model/snippet.model'; +import { SystemEditorModel } from '@renderer/model/system.model'; +import { EditorService } from '@renderer/services/editor/editor.service'; +import { FormBuilder } from '@angular/forms'; +import { SnippetService } from '@renderer/services/snippet/snippet.service'; + +@Component({ + selector: 'app-query-snippet', + templateUrl: 'snippet.component.html' +}) +export class SnippetComponent extends BaseComponent { + configuration: Config; + columns: any[] = new Array(); + action: ActionEnum; + actionComponent = ActionEnum; + editorConfig: any; + selectRow: SnippetModel; + + constructor(private editorService: EditorService, + private modal: NzModalService, + private formBuilder: FormBuilder, + private snippetService: SnippetService, + private messageService: NzMessageService, + private translateService: TranslateService) { + super(); + this.configuration = {...DefaultConfig}; + this.configuration.horizontalScroll = true; + this.configuration.orderEnabled = false; + this.configuration.paginationRangeEnabled = false; + this.configuration.fixedColumnWidth = true; + const cache = this.editorService.get() === null ? new SystemEditorModel() : this.editorService.get(); + this.editorConfig = Object.assign(this.editorService.getDefault(), cache); + this.initialize(); + } + + initialize() { + this.snippetService.getAll() + .then(response => { + this.columns = response; + }) + .catch(() => { + this.messageService.error(this.translateService.instant('common.error')); + }); + } + + handlerShowCreateSnippet(type: ActionEnum, data?: SnippetModel): void { + this.dialog.create = true; + this.action = type; + this.selectRow = data; + } + + handlerCloseCreateSnippet(close?: boolean): void { + this.dialog.create = false; + if (close) { + this.initialize(); + } + } + + handlerShowModal(row: SnippetModel): void { + this.dialog.select = true; + this.selectRow = row; + } + + handlerCloseModal(): void { + this.dialog.select = false; + } + + handlerDelete(id: number) { + this.snippetService.delete(id) + .then(() => { + this.messageService.success(this.translateService.instant('common.success')); + this.initialize(); + }) + .catch(() => { + this.messageService.error(this.translateService.instant('common.error')); + }); + } +} diff --git a/src/renderer/app/pages/query/snippet/snippet.module.ts b/src/renderer/app/pages/query/snippet/snippet.module.ts new file mode 100644 index 00000000..c9875cfe --- /dev/null +++ b/src/renderer/app/pages/query/snippet/snippet.module.ts @@ -0,0 +1,47 @@ +import { NgModule } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { RouterModule, Routes } from '@angular/router'; +import { TranslateModule, TranslateService } from '@ngx-translate/core'; +import { CommonModule } from '@angular/common'; +import { QueryHistoryService } from '@renderer/services/query/query.history.service'; +import { NgZorroAntdModule } from '@renderer/app/ng-zorro-antd.module'; +import { NzModalService } from 'ng-zorro-antd/modal'; +import { CommonShareModule } from '@renderer/app/common-share.module'; +import { EditorService } from '@renderer/services/editor/editor.service'; +import { SnippetComponent } from '@renderer/app/pages/query/snippet/snippet.component'; +import { TableModule } from 'ngx-easy-table'; +import { CodemirrorModule } from '@ctrl/ngx-codemirror'; +import { SnippetService } from '@renderer/services/snippet/snippet.service'; +import { MomentModule } from 'ngx-moment'; + +const QUERY_ROUTES: Routes = [ + {path: '', component: SnippetComponent} +]; + +@NgModule({ + imports: [ + FormsModule, + TranslateModule, + CommonModule, + NgZorroAntdModule, + RouterModule.forChild(QUERY_ROUTES), + CommonShareModule, + TableModule, + CodemirrorModule, + ReactiveFormsModule, + MomentModule + ], + exports: [], + declarations: [ + SnippetComponent + ], + providers: [ + TranslateService, + QueryHistoryService, + NzModalService, + EditorService, + SnippetService + ] +}) +export class SnippetModule { +} diff --git a/src/renderer/app/pages/tools/migrte/migrte.component.ts b/src/renderer/app/pages/tools/migrte/migrte.component.ts index 403993da..a4c7981d 100644 --- a/src/renderer/app/pages/tools/migrte/migrte.component.ts +++ b/src/renderer/app/pages/tools/migrte/migrte.component.ts @@ -10,108 +10,110 @@ import { StringUtils } from '@renderer/utils/string.utils'; import { NzMessageService } from 'ng-zorro-antd/message'; @Component({ - selector: 'app-tools-migrte', - templateUrl: 'migrte.component.html' + selector: 'app-tools-migrte', + templateUrl: 'migrte.component.html' }) export class MigrteComponent extends BaseComponent { - dataSources: DatasourceModel[]; - source = { datasource: null, databases: [], database: null, tables: [], table: null }; - target = { datasource: null, databases: [], database: null, tables: [], table: null }; - tableSizeInfo: any; + dataSources: DatasourceModel[]; + source = {datasource: null, databases: [], database: null, tables: [], table: null}; + target = {datasource: null, databases: [], database: null, tables: [], table: null}; + tableSizeInfo: any; - constructor(private datasourceService: DatasourceService, - private databaseService: DatabaseService, - private messageService: NzMessageService, - private tableService: TableService, - private migrateService: MigrateService) { - super(); - this.dataSources = this.datasourceService.getAll()?.data?.columns; - } - - handlerSwitchSource(type: boolean) { - this.databaseService.getAll(this.handlerRequest(type)).then(response => { - if (response.status) { - if (type) { - this.source.databases = response.data.columns; - } else { - this.target.databases = response.data.columns; - } - } else { - this.messageService.error(response.message); - } - }); - this.handlerValidate(); - } + constructor(private datasourceService: DatasourceService, + private databaseService: DatabaseService, + private messageService: NzMessageService, + private tableService: TableService, + private migrateService: MigrateService) { + super(); + this.datasourceService.getAll().then(response => { + this.dataSources = response; + }); + } - handlerSwitchDatabase(type: boolean) { - let database; + async handlerSwitchSource(type: boolean) { + this.databaseService.getAll(await this.handlerRequest(type)).then(response => { + if (response.status) { if (type) { - database = this.source.database; + this.source.databases = response.data.columns; } else { - database = this.target.database; + this.target.databases = response.data.columns; } - this.tableService.getAll(this.handlerRequest(type), database).then(response => { - if (response.status) { - if (type) { - this.source.tables = response.data.columns; - } else { - this.target.tables = response.data.columns; - } - } else { - this.messageService.error(response.message); - } - }); - this.handlerValidate(); - } + } else { + this.messageService.error(response.message); + } + }); + this.handlerValidate(); + } - handlerRequest(type: boolean): RequestModel { - const request = new RequestModel(); + async handlerSwitchDatabase(type: boolean) { + let database; + if (type) { + database = this.source.database; + } else { + database = this.target.database; + } + this.tableService.getAll(await this.handlerRequest(type), database).then(response => { + if (response.status) { if (type) { - request.config = this.datasourceService.getAll(this.source.datasource)?.data?.columns[0]; + this.source.tables = response.data.columns; } else { - request.config = this.datasourceService.getAll(this.target.datasource)?.data?.columns[0]; + this.target.tables = response.data.columns; } - return request; - } + } else { + this.messageService.error(response.message); + } + }); + this.handlerValidate(); + } - handlerCheckTable() { - const request = new RequestModel(); - request.config = this.datasourceService.getAll(this.source.datasource)?.data?.columns[0]; - this.tableService.getSize(request, this.source.database, this.source.table).then(response => { - if (response.status) { - if (response?.data?.columns.length > 0) { - this.tableSizeInfo = response?.data?.columns[0]; - } else { - this.tableSizeInfo = { flag: 0 }; - } - } else { - this.messageService.error(response.message); - } - }) + async handlerRequest(type: boolean) { + const request = new RequestModel(); + if (type) { + request.config = await this.datasourceService.getByAliasAsync(this.source.datasource); + } else { + request.config = await this.datasourceService.getByAliasAsync(this.target.datasource); } + return request; + } - handlerValidate(): boolean { - if (StringUtils.isNotEmpty(this.source.datasource) - && StringUtils.isNotEmpty(this.source.database) - && StringUtils.isNotEmpty(this.source.table) - && StringUtils.isNotEmpty(this.target.datasource) - && StringUtils.isNotEmpty(this.target.database) - && this.tableSizeInfo?.flag === 0 - ) { - return false; + async handlerCheckTable() { + const request = new RequestModel(); + request.config = await this.datasourceService.getByAliasAsync(this.source.datasource); + this.tableService.getSize(request, this.source.database, this.source.table).then(response => { + if (response.status) { + if (response?.data?.columns.length > 0) { + this.tableSizeInfo = response?.data?.columns[0]; + } else { + this.tableSizeInfo = {flag: 0}; } - return true; + } else { + this.messageService.error(response.message); + } + }); + } + + handlerValidate(): boolean { + if (StringUtils.isNotEmpty(this.source.datasource) + && StringUtils.isNotEmpty(this.source.database) + && StringUtils.isNotEmpty(this.source.table) + && StringUtils.isNotEmpty(this.target.datasource) + && StringUtils.isNotEmpty(this.target.database) + && this.tableSizeInfo?.flag === 0 + ) { + return false; } + return true; + } - async handlerMigrate() { - this.loading.button = true - const response = await this.migrateService.migrate(this.source, this.target) - if (response?.status) { - this.loading.button = false; - this.messageService.success(response?.message); - } else { - this.loading.button = false; - this.messageService.error(response?.message); - } + async handlerMigrate() { + this.loading.button = true; + const response = await this.migrateService.migrate(this.source, this.target); + if (response?.status) { + this.loading.button = false; + this.messageService.success(response?.message); + } else { + this.loading.button = false; + this.messageService.error(response?.message); } + } } diff --git a/src/renderer/app/pages/tools/track/track.component.ts b/src/renderer/app/pages/tools/track/track.component.ts index f4d8077b..f3d651a1 100644 --- a/src/renderer/app/pages/tools/track/track.component.ts +++ b/src/renderer/app/pages/tools/track/track.component.ts @@ -25,7 +25,9 @@ export class TrackComponent extends BaseComponent { private messageService: NzMessageService, private modal: NzModalService) { super(); - this.dataSources = this.datasourceService.getAll()?.data?.columns; + this.datasourceService.getAll().then(response => { + this.dataSources = response; + }); } handlerSearch(value: string) { diff --git a/src/renderer/assets/i18n/en.json b/src/renderer/assets/i18n/en.json index ad6fd5c0..e46bc20d 100644 --- a/src/renderer/assets/i18n/en.json +++ b/src/renderer/assets/i18n/en.json @@ -139,7 +139,16 @@ "remove": "Remove", "status": "Status", "success": "Success", - "description": "Description" + "description": "Description", + "comment": "Comment", + "snippet": "Snippet", + "id": "ID", + "name": "Name", + "description": "Description", + "code": "Code", + "created": "Created", + "updated": "Updated", + "quote": "Quote" }, "language": { "english": "English", @@ -170,7 +179,8 @@ "commitEveryBatch": "Commit Every Batch", "threadPerConsumer": "Thread Per Consumer", "maxTotal": "The maximum number of rows is displayed. If you manually enter limit, the configuration is overwritten. If 0 is set, the configuration does not take effect", - "collection": "Please input collection" + "collection": "Please input collection", + "required": "This value cannot be empty, please enter" }, "tooltip": { "network": "Duration of accessing the remote server (in seconds)", @@ -251,8 +261,15 @@ "noversion": "This is the latest version!", "not_support_online": "Currently, online updates are not supported", "table_grate_50": "Data tables larger than 50GB cannot be migrated", + "table_delete_grate_50": "Data tables larger than 50GB cannot be deleted", "ttl": "When the time reaches, the system deletes data in the entire table based on the configured TTL", "ttl_remove": "After the TTL configuration is removed, the system will not delete data", - "only_one_column": "You cannot delete all columns in a data table, the table must contain at least one column" + "only_one_column": "You cannot delete all columns in a data table, the table must contain at least one column", + "delete_it": "We don't recommend that you delete it? This operation produces the following?", + "migrate_datasource": "The storage method of the data source has been modified. Please continue to use the original storage content after migrating the data.", + "migrate_data_success": "After the migration is successful, the source data will be cleaned up!" + }, + "formatter": { + "migrate_data": "Need to migrate {0} data, please confirm whether to migrate?" } } diff --git a/src/renderer/assets/i18n/zh.json b/src/renderer/assets/i18n/zh.json index d89b5591..31a0fec7 100644 --- a/src/renderer/assets/i18n/zh.json +++ b/src/renderer/assets/i18n/zh.json @@ -138,7 +138,16 @@ "remove": "移除", "status": "状态", "success": "成功", - "description": "描述" + "description": "描述", + "comment": "评论", + "snippet": "片段", + "id": "标记", + "name": "名称", + "description": "描述", + "code": "代码", + "created": "创建", + "updated": "更新", + "quote": "引用" }, "language": { "english": "英语", @@ -171,7 +180,8 @@ "maxTotal": "返回查询最大行数,用户手动填写limit将覆盖该配置,如果设置0则该配置不生效", "collection": "Please input collection", "options": "Options", - "ttl": "TTL" + "ttl": "TTL", + "required": "该值不能为空, 请输入" }, "tooltip": { "network": "访问远程服务器的时间(以秒为单位)", @@ -252,8 +262,15 @@ "noversion": "当前已经是最新版本", "not_support_online": "当前暂不支持在线更新", "table_grate_50": "暂不支持迁移大于50GB数据表", + "table_delete_grate_50": "暂不支持删除大于50GB数据表", "ttl": "达到时间后,系统将根据配置的TTL值,删除整个表中的数据", "ttl_remove": "TTL配置移除后, 系统将不会在对数据进行删除操作", - "only_one_column": "不能删除数据表中的所有列, 该数据表必须至少包含一列" + "only_one_column": "不能删除数据表中的所有列, 该数据表必须至少包含一列", + "delete_it": "我们不建议你删除它?这个操作会产生以下结果?", + "migrate_datasource": "数据源存储方式已经修改请迁移数据后继续使用原有存储内容", + "migrate_data_success": "迁移成功后源数据将被清理!" + }, + "formatter": { + "migrate_data": "需要迁移{0}条数据, 请确认是否迁移?" } } diff --git a/src/renderer/components/column/comment/column.comment.component.html b/src/renderer/components/column/comment/column.comment.component.html new file mode 100644 index 00000000..123d55e7 --- /dev/null +++ b/src/renderer/components/column/comment/column.comment.component.html @@ -0,0 +1,22 @@ +
    + + + + + + + +
    + diff --git a/src/renderer/components/column/comment/column.comment.component.ts b/src/renderer/components/column/comment/column.comment.component.ts new file mode 100644 index 00000000..b648acc1 --- /dev/null +++ b/src/renderer/components/column/comment/column.comment.component.ts @@ -0,0 +1,64 @@ +import { AfterViewInit, Component, EventEmitter, Input, Output } from '@angular/core'; +import { BaseComponent } from '@renderer/app/base.component'; +import { ConfigModel } from '@renderer/model/config.model'; +import { DatabaseModel } from '@renderer/model/database.model'; +import { RequestModel } from '@renderer/model/request.model'; +import { ColumnService } from '@renderer/services/management/column.service'; +import { DatasourceService } from '@renderer/services/management/datasource.service'; +import { NzMessageService } from 'ng-zorro-antd/message'; +import { StringUtils } from '@renderer/utils/string.utils'; + +@Component({ + selector: 'app-component-comment-column', + templateUrl: './column.comment.component.html' +}) +export class CommentColumnComponent extends BaseComponent implements AfterViewInit { + @Input() + config: ConfigModel; + @Input() + value: string; + @Input() + database: string; + @Input() + table: string; + @Output() + emitter = new EventEmitter(); + inputValue: string; + + constructor(private dataSourceService: DatasourceService, + private columnService: ColumnService, + private messageService: NzMessageService) { + super(); + } + + handlerValidate() { + if (StringUtils.isNotEmpty(this.inputValue)) { + this.disabled.button = false; + } else { + this.disabled.button = true; + } + } + + async handlerAddComment() { + this.loading.button = true; + const request = new RequestModel(); + request.config = await this.dataSourceService.getByAliasAsync(this.config.value); + const _value = new DatabaseModel(); + _value.database = this.database; + _value.table = this.table; + _value.name = this.value; + this.columnService.comment(request, _value, this.inputValue).then(response => { + if (response.status) { + this.messageService.success(response.message); + this.config.status = false; + this.emitter.emit(this.config); + } else { + this.messageService.error(response.message); + } + this.loading.button = false; + }); + } + + ngAfterViewInit(): void { + } +} diff --git a/src/renderer/components/column/common/common.column.component.html b/src/renderer/components/column/common/common.column.component.html index 77e162e6..6ba9f2c5 100644 --- a/src/renderer/components/column/common/common.column.component.html +++ b/src/renderer/components/column/common/common.column.component.html @@ -16,5 +16,9 @@ [value]="value?.origin?.key" [database]="database" [table]="table" (emitter)="handlerEmitter($event)"> + +
    diff --git a/src/renderer/components/column/create/column.create.component.ts b/src/renderer/components/column/create/column.create.component.ts index 84e3ce8d..3580c882 100644 --- a/src/renderer/components/column/create/column.create.component.ts +++ b/src/renderer/components/column/create/column.create.component.ts @@ -108,10 +108,10 @@ export class ColumnCreateComponent extends BaseComponent { } } - handlerSave() { + async handlerSave() { this.loading.button = true; const request = new RequestModel(); - request.config = this.dataSourceService.getAll(this.config.value)?.data?.columns[0]; + request.config = await this.dataSourceService.getByAliasAsync(this.config.value); const _value = new DatabaseModel(); _value.database = this.database; _value.table = this.table; diff --git a/src/renderer/components/column/delete/column.delete.component.ts b/src/renderer/components/column/delete/column.delete.component.ts index 9fbb7142..a18f8966 100644 --- a/src/renderer/components/column/delete/column.delete.component.ts +++ b/src/renderer/components/column/delete/column.delete.component.ts @@ -39,10 +39,10 @@ export class DeleteColumnComponent extends BaseComponent implements AfterViewIni } } - handlerDelete() { + async handlerDelete() { this.loading.button = true; const request = new RequestModel(); - request.config = this.dataSourceService.getAll(this.config.value)?.data?.columns[0]; + request.config = await this.dataSourceService.getByAliasAsync(this.config.value); const _value = new DatabaseModel(); _value.database = this.database; _value.table = this.table; @@ -64,9 +64,9 @@ export class DeleteColumnComponent extends BaseComponent implements AfterViewIni this.handlerValidate(); } - ngAfterViewInit(): void { + async ngAfterViewInit() { const request = new RequestModel(); - request.config = this.dataSourceService.getAll(this.config.value)?.data?.columns[0]; + request.config = await this.dataSourceService.getByAliasAsync(this.config.value); const _value = new DatabaseModel(); _value.database = this.database; _value.table = this.table; diff --git a/src/renderer/components/column/preview/column.preview.component.html b/src/renderer/components/column/preview/column.preview.component.html index 79e43dba..97b28416 100644 --- a/src/renderer/components/column/preview/column.preview.component.html +++ b/src/renderer/components/column/preview/column.preview.component.html @@ -1,17 +1,17 @@
    -
    - - {{'common.database'|translate}} - - {{database}} - - - - {{'common.table'|translate}} - - {{table}} - - -
    - -
    \ No newline at end of file +
    + + {{'common.database'|translate}} + + {{database}} + + + + {{'common.table'|translate}} + + {{table}} + + +
    + + diff --git a/src/renderer/components/column/preview/column.preview.component.ts b/src/renderer/components/column/preview/column.preview.component.ts index 33e24b35..f24503f9 100644 --- a/src/renderer/components/column/preview/column.preview.component.ts +++ b/src/renderer/components/column/preview/column.preview.component.ts @@ -9,39 +9,39 @@ import { DatasourceService } from '@renderer/services/management/datasource.serv import { NzMessageService } from 'ng-zorro-antd/message'; @Component({ - selector: 'app-component-preview-column', - templateUrl: './column.preview.component.html' + selector: 'app-component-preview-column', + templateUrl: './column.preview.component.html' }) export class PreviewColumnComponent extends BaseComponent implements AfterViewInit { - @Input() - config: ConfigModel; - @Input() - value: string; - @Input() - database: string; - @Input() - table: string; - tableData: ResponseDataModel; + @Input() + config: ConfigModel; + @Input() + value: string; + @Input() + database: string; + @Input() + table: string; + tableData: ResponseDataModel; - constructor(private dataSourceService: DatasourceService, - private columnService: ColumnService, - private messageService: NzMessageService) { - super(); - } + constructor(private dataSourceService: DatasourceService, + private columnService: ColumnService, + private messageService: NzMessageService) { + super(); + } - ngAfterViewInit(): void { - const request = new RequestModel(); - request.config = this.dataSourceService.getAll(this.config.value)?.data?.columns[0]; - const _value = new DatabaseModel(); - _value.database = this.database; - _value.table = this.table; - _value.name = this.value; - this.columnService.getPreview(request, _value).then(response => { - if (response.status) { - this.tableData = response.data; - } else { - this.messageService.error(response.message); - } - }); - } + async ngAfterViewInit() { + const request = new RequestModel(); + request.config = await this.dataSourceService.getByAliasAsync(this.config.value); + const _value = new DatabaseModel(); + _value.database = this.database; + _value.table = this.table; + _value.name = this.value; + this.columnService.getPreview(request, _value).then(response => { + if (response.status) { + this.tableData = response.data; + } else { + this.messageService.error(response.message); + } + }); + } } diff --git a/src/renderer/components/column/rename/column.rename.component.ts b/src/renderer/components/column/rename/column.rename.component.ts index 08082475..2f86c4f4 100644 --- a/src/renderer/components/column/rename/column.rename.component.ts +++ b/src/renderer/components/column/rename/column.rename.component.ts @@ -39,10 +39,10 @@ export class RenameColumnComponent extends BaseComponent { } } - handlerRename() { + async handlerRename() { this.loading.button = true; const request = new RequestModel(); - request.config = this.dataSourceService.getAll(this.config.value)?.data?.columns[0]; + request.config = await this.dataSourceService.getByAliasAsync(this.config.value); const _value = new DatabaseModel(); _value.database = this.database; _value.table = this.table; diff --git a/src/renderer/components/database/basic/database.basic.component.ts b/src/renderer/components/database/basic/database.basic.component.ts index 1314818c..f6874af6 100644 --- a/src/renderer/components/database/basic/database.basic.component.ts +++ b/src/renderer/components/database/basic/database.basic.component.ts @@ -84,9 +84,9 @@ export class DatabaseBasicComponent extends BaseComponent { this.handlerValidate(); } - handlerComplete(): void { + async handlerComplete() { const request = new RequestModel(); - request.config = this.dataSourceService.getAll(this.config.value)?.data?.columns[0]; + request.config = await this.dataSourceService.getByAliasAsync(this.config.value); this.metadataService.createDatabase(request, this.configure).then(response => { if (response.status) { this.messageService.success(response.message); diff --git a/src/renderer/components/database/drop/database.drop.component.ts b/src/renderer/components/database/drop/database.drop.component.ts index fb3e98a7..dae5bb8f 100644 --- a/src/renderer/components/database/drop/database.drop.component.ts +++ b/src/renderer/components/database/drop/database.drop.component.ts @@ -48,10 +48,10 @@ export class DatabaseDropComponent extends BaseComponent implements AfterViewIni }, 0); } - handlerCheckTables() { + async handlerCheckTables() { this.getTables = true; const request = new RequestModel(); - request.config = this.dataSourceService.getAll(this.config.value)?.data?.columns[0]; + request.config = await this.dataSourceService.getByAliasAsync(this.config.value); this.databaseService.getTables(request, this.value).then(response => { if (response.status) { this.tables = response.data; @@ -76,10 +76,10 @@ export class DatabaseDropComponent extends BaseComponent implements AfterViewIni } } - handlerDelete() { + async handlerDelete() { this.loading.button = true; const request = new RequestModel(); - request.config = this.dataSourceService.getAll(this.config.value)?.data?.columns[0]; + request.config = await this.dataSourceService.getByAliasAsync(this.config.value); this.metadataService.delete(request, this.value).then(response => { if (response.status) { this.messageService.success(response.message); @@ -99,10 +99,10 @@ export class DatabaseDropComponent extends BaseComponent implements AfterViewIni this.handlerValidate(); } - handlerDeleteTable(table: any) { + async handlerDeleteTable(table: any) { this.deleteTable = true; const request = new RequestModel(); - request.config = this.dataSourceService.getAll(this.config.value)?.data?.columns[0]; + request.config = await this.dataSourceService.getByAliasAsync(this.config.value); const _value = new DatabaseModel(); _value.database = this.value; _value.name = table.name; diff --git a/src/renderer/components/database/rename/database.rename.component.ts b/src/renderer/components/database/rename/database.rename.component.ts index 0330db11..24a5b4cb 100644 --- a/src/renderer/components/database/rename/database.rename.component.ts +++ b/src/renderer/components/database/rename/database.rename.component.ts @@ -1,10 +1,8 @@ import { AfterViewInit, Component, EventEmitter, Input, Output } from '@angular/core'; import { BaseComponent } from '@renderer/app/base.component'; import { ConfigModel } from '@renderer/model/config.model'; -import { DatabaseModel } from '@renderer/model/database.model'; import { RequestModel } from '@renderer/model/request.model'; import { DatasourceService } from '@renderer/services/management/datasource.service'; -import { TableService } from '@renderer/services/management/table.service'; import { StringUtils } from '@renderer/utils/string.utils'; import { NzMessageService } from 'ng-zorro-antd/message'; import { DatabaseService } from '@renderer/services/management/database.service'; @@ -35,10 +33,10 @@ export class DatabaseRenameComponent extends BaseComponent implements AfterViewI }, 0); } - handlerCheckDatabaseStatus() { + async handlerCheckDatabaseStatus() { this.checkStatus = true; const request = new RequestModel(); - request.config = this.dataSourceService.getAll(this.config.value)?.data?.columns[0]; + request.config = await this.dataSourceService.getByAliasAsync(this.config.value); this.databaseService.getDatabase(request, this.value) .then(response => { if (response.status) { @@ -57,10 +55,10 @@ export class DatabaseRenameComponent extends BaseComponent implements AfterViewI } } - handlerRename() { + async handlerRename() { this.loading.button = true; const request = new RequestModel(); - request.config = this.dataSourceService.getAll(this.config.value)?.data?.columns[0]; + request.config = await this.dataSourceService.getByAliasAsync(this.config.value); this.databaseService.rename(request, this.value, this.inputValue) .then(response => { if (response.status) { diff --git a/src/renderer/components/database/structure/database.structure.component.ts b/src/renderer/components/database/structure/database.structure.component.ts index 1253e879..0c9ff8a8 100644 --- a/src/renderer/components/database/structure/database.structure.component.ts +++ b/src/renderer/components/database/structure/database.structure.component.ts @@ -37,7 +37,7 @@ export class DatabaseStructureComponent extends BaseComponent implements AfterVi ngAfterViewInit(): void { // eslint-disable-next-line max-len - // Fix ERROR Error: NG0100: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'false'. Current value: 'true' + // Fix Error: NG0100: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'false'. Current value: 'true' setTimeout(() => { this.handlerInitialize(); }, 0); @@ -48,10 +48,10 @@ export class DatabaseStructureComponent extends BaseComponent implements AfterVi this.emitter.emit(this.visible); } - handlerInitialize() { + async handlerInitialize() { this.loading.button = true; const request = new RequestModel(); - request.config = this.dataSourceService.getAll(this.config.value)?.data?.columns[0]; + request.config = await this.dataSourceService.getByAliasAsync(this.config.value); this.metadataService.getDatabaseDDL(request, this.value).then(response => { if (response.status) { this.structure = response?.data?.columns[0]?.statement; diff --git a/src/renderer/components/query/quick/quick.query.component.html b/src/renderer/components/query/quick/quick.query.component.html index 9532dbf2..84228150 100644 --- a/src/renderer/components/query/quick/quick.query.component.html +++ b/src/renderer/components/query/quick/quick.query.component.html @@ -9,7 +9,7 @@ - + diff --git a/src/renderer/components/query/quick/quick.query.component.ts b/src/renderer/components/query/quick/quick.query.component.ts index 382bce75..2301fab2 100644 --- a/src/renderer/components/query/quick/quick.query.component.ts +++ b/src/renderer/components/query/quick/quick.query.component.ts @@ -39,7 +39,9 @@ export class QuickQueryComponent extends BaseComponent { private queryQuickService: QueryQuickService) { super(); this.quickCommands = this.queryQuickService.getQuickAll(); - this.dataSourceSet = this.dataSourceService.getAll()?.data?.columns; + this.dataSourceService.getAll().then(response => { + this.dataSourceSet = response; + }); } handlerCancel() { @@ -50,35 +52,36 @@ export class QuickQueryComponent extends BaseComponent { handlerChangeValue(quick: QuickEnum) { this.table = null; const request = new RequestModel(); - const datasourceInfo = this.dataSourceService.getAll(this.dataSource)?.data?.columns[0]; - request.config = datasourceInfo; - switch (quick) { - case QuickEnum.database: - this.disabled.dialog = true; - this.loading.database = true; - this.databaseSet = []; - this.queryService.getResponse(request, 'SHOW DATABASES').then(response => { - if (response.status) { - this.databaseSet = response.data.columns; - } else { - this.messageService.error(response.message); - } - this.loading.database = false; - this.disabled.dialog = false; - }); - break; - case QuickEnum.table: - this.tableSet = []; - this.queryService.getResponse(request, 'SHOW TABLES FROM ' + this.database).then(response => { - if (response.status) { - this.tableSet = response.data.columns; - } else { - this.messageService.error(response.message); - } - this.loading.table = false; - }); - break; - } + this.dataSourceService.findByAlias(this.dataSource).then(response => { + request.config = response; + switch (quick) { + case QuickEnum.database: + this.disabled.dialog = true; + this.loading.database = true; + this.databaseSet = []; + this.queryService.getResponse(request, 'SHOW DATABASES').then(response => { + if (response.status) { + this.databaseSet = response.data.columns; + } else { + this.messageService.error(response.message); + } + this.loading.database = false; + this.disabled.dialog = false; + }); + break; + case QuickEnum.table: + this.tableSet = []; + this.queryService.getResponse(request, 'SHOW TABLES FROM ' + this.database).then(response => { + if (response.status) { + this.tableSet = response.data.columns; + } else { + this.messageService.error(response.message); + } + this.loading.table = false; + }); + break; + } + }); } handlerQuickCommand(command: { name: string, value: string }) { diff --git a/src/renderer/components/server/info/info.server.component.html b/src/renderer/components/server/info/info.server.component.html index 2881c0c5..6abac4c0 100644 --- a/src/renderer/components/server/info/info.server.component.html +++ b/src/renderer/components/server/info/info.server.component.html @@ -1,5 +1,5 @@
    diff --git a/src/renderer/components/server/info/info.server.component.ts b/src/renderer/components/server/info/info.server.component.ts index 9b1f1242..9829cf35 100644 --- a/src/renderer/components/server/info/info.server.component.ts +++ b/src/renderer/components/server/info/info.server.component.ts @@ -30,17 +30,19 @@ export class InfoServerComponent extends BaseComponent implements AfterViewInit this.emitter.emit(this.visible); } - ngAfterViewInit(): void { - const request = new RequestModel(); - request.config = this.dataSourceService.getAll(this.config.value)?.data?.columns[0]; - this.disabled.dialog = true; - this.metadataService.getInfo(request).then(response => { - if (response.status) { - this.items = response.data; - } else { - this.messageService.error(response.message); - } - this.disabled.dialog = false; - }); + async ngAfterViewInit() { + setTimeout(async () => { + const request = new RequestModel(); + request.config = await this.dataSourceService.getByAliasAsync(this.config.value); + this.disabled.dialog = true; + this.metadataService.getInfo(request).then(response => { + if (response.status) { + this.items = response.data; + } else { + this.messageService.error(response.message); + } + this.disabled.dialog = false; + }); + }, 0); } } diff --git a/src/renderer/components/snippet/create/create.snippet.component.html b/src/renderer/components/snippet/create/create.snippet.component.html new file mode 100644 index 00000000..2260c70a --- /dev/null +++ b/src/renderer/components/snippet/create/create.snippet.component.html @@ -0,0 +1,45 @@ + +
    +
    +
    + + {{'common.name'|translate}} + + + + +
    +
    + + {{'common.description'|translate}} + + + + +
    +
    + + {{'common.snippet' | translate}} + + + + + +
    +
    +
    + +
    + + +
    +
    +
    diff --git a/src/renderer/components/snippet/create/create.snippet.component.ts b/src/renderer/components/snippet/create/create.snippet.component.ts new file mode 100644 index 00000000..ea7dad49 --- /dev/null +++ b/src/renderer/components/snippet/create/create.snippet.component.ts @@ -0,0 +1,115 @@ +import { AfterViewInit, Component, EventEmitter, Input, Output } from '@angular/core'; +import { BaseComponent } from '@renderer/app/base.component'; +import { NzModalService } from 'ng-zorro-antd/modal'; +import { NzMessageService } from 'ng-zorro-antd/message'; +import { TranslateService } from '@ngx-translate/core'; +import { ActionEnum } from '@renderer/enum/action.enum'; +import { SnippetModel } from '@renderer/model/snippet.model'; +import { SystemEditorModel } from '@renderer/model/system.model'; +import { EditorService } from '@renderer/services/editor/editor.service'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { SnippetService } from '@renderer/services/snippet/snippet.service'; +import { StringUtils } from '@renderer/utils/string.utils'; + +@Component({ + selector: 'app-component-create-snippet', + templateUrl: 'create.snippet.component.html' +}) +export class CreateSnippetComponent extends BaseComponent implements AfterViewInit { + @Input() + visible: boolean; + @Input() + action: ActionEnum; + @Input() + snippetValue?: string; + @Input() + snippetComponent?: SnippetModel; + @Output() + emitter = new EventEmitter(); + snippet: SnippetModel; + editorConfig: any; + validateForm!: FormGroup; + + constructor(private editorService: EditorService, + private modal: NzModalService, + private formBuilder: FormBuilder, + private snippetService: SnippetService, + private messageService: NzMessageService, + private translateService: TranslateService) { + super(); + } + + ngAfterViewInit(): void { + setTimeout(() => { + this.initialize(); + }, 0); + } + + initialize() { + const cache = this.editorService.get() === null ? new SystemEditorModel() : this.editorService.get(); + this.editorConfig = Object.assign(this.editorService.getDefault(), cache); + this.handlerShowDrawer(this.action); + } + + handlerRestValidator(): void { + this.validateForm = this.formBuilder.group({ + name: [null, [Validators.required]], + description: [null, [Validators.required]], + code: [null, [Validators.required]] + }); + } + + handlerShowDrawer(type: ActionEnum): void { + this.handlerRestValidator(); + switch (type) { + case ActionEnum.create: + this.snippet = new SnippetModel(); + if (this.snippetValue) { + this.snippet.code = this.snippetValue; + } + break; + case ActionEnum.update: + this.snippet = this.snippetComponent; + } + } + + handlerCloseDrawer(close?: boolean): void { + this.snippet = null; + this.validateForm = null; + if (StringUtils.isEmpty(close)) { + this.emitter.emit(false); + } + this.emitter.emit(close); + } + + handlerSave(): void { + if (this.validateForm.valid) { + if (this.action === ActionEnum.create) { + this.snippetService.save(this.snippet) + .then(() => { + this.messageService.success(this.translateService.instant('common.success')); + this.handlerCloseDrawer(true); + }) + .catch(() => { + this.messageService.error(this.translateService.instant('common.error')); + }); + } else { + this.snippetService.update(this.snippet) + .then(() => { + this.messageService.success(this.translateService.instant('common.success')); + this.handlerCloseDrawer(true); + }) + .catch(error => { + this.messageService.error(error); + }); + } + } else { + Object.values(this.validateForm.controls).forEach(control => { + if (control.invalid) { + control.markAsDirty(); + control.updateValueAndValidity({onlySelf: true}); + } + }); + } + } +} diff --git a/src/renderer/components/snippet/quote/quote.snippet.component.html b/src/renderer/components/snippet/quote/quote.snippet.component.html new file mode 100644 index 00000000..9730ef07 --- /dev/null +++ b/src/renderer/components/snippet/quote/quote.snippet.component.html @@ -0,0 +1,51 @@ + + + + + + {{'common.id'|translate}} + {{'common.name'|translate}} + {{'common.description'|translate}} + {{'common.code'|translate}} + {{'common.action'|translate}} + + + + + + {{data.id}} + + {{data.name}} + + + {{data.description}} + + + + + + + + + + +
    + +
    + +
    + +
    +
    +
    diff --git a/src/renderer/components/snippet/quote/quote.snippet.component.ts b/src/renderer/components/snippet/quote/quote.snippet.component.ts new file mode 100644 index 00000000..31cd099a --- /dev/null +++ b/src/renderer/components/snippet/quote/quote.snippet.component.ts @@ -0,0 +1,65 @@ +import { BaseComponent } from '@renderer/app/base.component'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { NzMessageService } from 'ng-zorro-antd/message'; +import { SnippetService } from '@renderer/services/snippet/snippet.service'; +import { SnippetModel } from '@renderer/model/snippet.model'; +import { TranslateService } from '@ngx-translate/core'; +import { SystemEditorModel } from '@renderer/model/system.model'; +import { EditorService } from '@renderer/services/editor/editor.service'; + +@Component({ + selector: 'app-component-quote-snippet', + templateUrl: './quote.snippet.component.html' +}) +export class QuoteSnippetComponent extends BaseComponent { + @Input() + visible: boolean; + @Output() + emitter = new EventEmitter(); + @Output() + emitterValue = new EventEmitter(); + columns: SnippetModel[] = new Array(); + toggledRows = new Set(); + tableWidth = '100%'; + editorConfig: any; + + constructor(private snippetService: SnippetService, + private messageService: NzMessageService, + private editorService: EditorService, + private translateService: TranslateService) { + super(); + const cache = this.editorService.get() === null ? new SystemEditorModel() : this.editorService.get(); + this.editorConfig = Object.assign(this.editorService.getDefault(), cache); + this.editorConfig.readOnly = true; + this.initialize(); + } + + initialize() { + this.snippetService.getAll() + .then((snippets: SnippetModel[]) => { + this.columns = snippets; + }) + .catch(() => { + this.messageService.error(this.translateService.instant('common.error')); + }); + } + + handlerCancel() { + this.visible = false; + this.emitter.emit(this.visible); + } + + handlerRowToggled($event: MouseEvent, index: number): void { + if (this.toggledRows.has(index)) { + this.toggledRows.delete(index); + } else { + this.toggledRows.add(index); + } + this.tableWidth = document.getElementById('table')?.offsetWidth - 15 + 'px'; + } + + handlerRowSelectedQuote(snippet: SnippetModel): void { + this.emitterValue.emit(snippet.code); + this.handlerCancel(); + } +} diff --git a/src/renderer/components/table/basic/basic.table.component.ts b/src/renderer/components/table/basic/basic.table.component.ts index 04517dd2..a58ed174 100644 --- a/src/renderer/components/table/basic/basic.table.component.ts +++ b/src/renderer/components/table/basic/basic.table.component.ts @@ -30,7 +30,7 @@ export class BasicTableComponent extends BaseComponent implements AfterViewInit ngAfterViewInit(): void { setTimeout(() => { - this.value.headers.forEach(column => { + this.value?.headers.forEach(column => { this.headers.push({key: column.name, title: column.name}); }); }, 0); diff --git a/src/renderer/components/table/clean/table.clean.component.ts b/src/renderer/components/table/clean/table.clean.component.ts index 9a6b44d0..960dfa12 100644 --- a/src/renderer/components/table/clean/table.clean.component.ts +++ b/src/renderer/components/table/clean/table.clean.component.ts @@ -39,8 +39,8 @@ export class CleanTableComponent extends BaseComponent implements AfterViewInit super(); } - ngAfterViewInit(): void { - this.tableService.getPartitions(this.handlerGetRequest(), this.handlerGetDatabaseModel()) + async ngAfterViewInit() { + this.tableService.getPartitions(await this.handlerGetRequest(), this.handlerGetDatabaseModel()) .then(response => { if (response.status) { this.partitions = response.data.columns; @@ -50,9 +50,9 @@ export class CleanTableComponent extends BaseComponent implements AfterViewInit }); } - handlerGetRequest(): RequestModel { + async handlerGetRequest(): Promise { const request = new RequestModel(); - request.config = this.dataSourceService.getAll(this.config.value)?.data?.columns[0]; + request.config = await this.dataSourceService.getByAliasAsync(this.config.value); return request; } @@ -63,10 +63,10 @@ export class CleanTableComponent extends BaseComponent implements AfterViewInit return _value; } - handlerValidate() { + async handlerValidate() { if (ValidateUtils.validate(this.allowValue)) { this.deletePartition = true; - this.tableService.getPartitions(this.handlerGetRequest(), + this.tableService.getPartitions(await this.handlerGetRequest(), this.handlerGetDatabaseModel(), StringUtils.appendBackslash(this.allowValue.partition), this.allowValue.logic) @@ -88,9 +88,9 @@ export class CleanTableComponent extends BaseComponent implements AfterViewInit } } - handlerClean(value: string) { + async handlerClean(value: string) { this.loading.button = true; - this.tableService.clean(this.handlerGetRequest(), + this.tableService.clean(await this.handlerGetRequest(), this.handlerGetDatabaseModel(), StringUtils.appendBackslash(value)) .then(response => { diff --git a/src/renderer/components/table/create/table.create.component.ts b/src/renderer/components/table/create/table.create.component.ts index 8ab54c81..e13d05a6 100644 --- a/src/renderer/components/table/create/table.create.component.ts +++ b/src/renderer/components/table/create/table.create.component.ts @@ -105,9 +105,9 @@ export class CreateTableComponent extends BaseComponent { this.columns.length = 0; } - handlerComplete(): void { + async handlerComplete() { const request = new RequestModel(); - request.config = this.dataSourceService.getAll(this.config.value)?.data?.columns[0]; + request.config = await this.dataSourceService.getByAliasAsync(this.config.value); this.configure.database = this.value; this.tableService.createTable(request, this.configure, this.columns).then(response => { if (response.status) { diff --git a/src/renderer/components/table/delete/table.delete.component.html b/src/renderer/components/table/delete/table.delete.component.html index 6ea5bc6b..1059fd67 100644 --- a/src/renderer/components/table/delete/table.delete.component.html +++ b/src/renderer/components/table/delete/table.delete.component.html @@ -1,21 +1,26 @@
    + + + + + + - + - No rollback + {{'common.no_rollback'|translate}} The metadata will be removed from the Clickhouse metadata - No rollback + {{'common.no_rollback'|translate}} All data files generated in this table will be removed from the relevant Clickhouse server file system @@ -27,13 +32,15 @@ - + - + diff --git a/src/renderer/components/table/delete/table.delete.component.ts b/src/renderer/components/table/delete/table.delete.component.ts index bd7c06c1..a0eb090a 100644 --- a/src/renderer/components/table/delete/table.delete.component.ts +++ b/src/renderer/components/table/delete/table.delete.component.ts @@ -1,4 +1,4 @@ -import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { AfterViewInit, Component, EventEmitter, Input, Output } from '@angular/core'; import { BaseComponent } from '@renderer/app/base.component'; import { ConfigModel } from '@renderer/model/config.model'; import { DatabaseModel } from '@renderer/model/database.model'; @@ -11,7 +11,7 @@ import { NzMessageService } from 'ng-zorro-antd/message'; selector: 'app-component-delete-table', templateUrl: './table.delete.component.html' }) -export class DeleteTableComponent extends BaseComponent { +export class DeleteTableComponent extends BaseComponent implements AfterViewInit { @Input() config: ConfigModel; @Input() @@ -21,13 +21,30 @@ export class DeleteTableComponent extends BaseComponent { @Output() emitter = new EventEmitter(); inputValue: string; + tableInfo = {flag: 1}; constructor(private dataSourceService: DatasourceService, private tableService: TableService, + private datasourceService: DatasourceService, private messageService: NzMessageService) { super(); } + ngAfterViewInit() { + setTimeout(async () => { + const request = new RequestModel(); + request.config = await this.dataSourceService.getByAliasAsync(this.config.value); + this.tableService.getSize(request, this.database, this.value) + .then(response => { + if (response.status) { + this.tableInfo = response.data?.columns[0]; + } else { + this.messageService.error(response.message); + } + }); + }, 0); + } + handlerValidate() { if (this.inputValue === this.value) { this.disabled.button = false; @@ -36,10 +53,10 @@ export class DeleteTableComponent extends BaseComponent { } } - handlerDelete() { + async handlerDelete() { this.loading.button = true; const request = new RequestModel(); - request.config = this.dataSourceService.getAll(this.config.value)?.data?.columns[0]; + request.config = await this.dataSourceService.getByAliasAsync(this.config.value); const _value = new DatabaseModel(); _value.database = this.database; _value.name = this.value; diff --git a/src/renderer/components/table/optimize/table.optimize.component.ts b/src/renderer/components/table/optimize/table.optimize.component.ts index 4e8c4d66..904dfa19 100644 --- a/src/renderer/components/table/optimize/table.optimize.component.ts +++ b/src/renderer/components/table/optimize/table.optimize.component.ts @@ -1,4 +1,4 @@ -import { Component, EventEmitter, Input, Output, AfterViewInit } from '@angular/core'; +import { AfterViewInit, Component, EventEmitter, Input, Output } from '@angular/core'; import { BaseComponent } from '@renderer/app/base.component'; import { ConfigModel } from '@renderer/model/config.model'; import { DatabaseModel } from '@renderer/model/database.model'; @@ -9,66 +9,66 @@ import { StringUtils } from '@renderer/utils/string.utils'; import { NzMessageService } from 'ng-zorro-antd/message'; @Component({ - selector: 'app-component-optimize-table', - templateUrl: './table.optimize.component.html' + selector: 'app-component-optimize-table', + templateUrl: './table.optimize.component.html' }) export class OptimizeTableComponent extends BaseComponent implements AfterViewInit { - @Input() - config: ConfigModel; - @Input() - value: string; - @Input() - database: string; - @Output() - emitter = new EventEmitter(); - partitions: any[]; - partition: string; - final: boolean; + @Input() + config: ConfigModel; + @Input() + value: string; + @Input() + database: string; + @Output() + emitter = new EventEmitter(); + partitions: any[]; + partition: string; + final: boolean; - constructor(private dataSourceService: DatasourceService, - private tableService: TableService, - private messageService: NzMessageService) { - super(); - } + constructor(private dataSourceService: DatasourceService, + private tableService: TableService, + private messageService: NzMessageService) { + super(); + } - ngAfterViewInit(): void { - const request = new RequestModel(); - request.config = this.dataSourceService.getAll(this.config.value)?.data?.columns[0]; - const _value = new DatabaseModel(); - _value.database = this.database; - _value.name = this.value; - this.tableService.getPartitions(request, _value).then(response => { - if (response.status) { - this.partitions = response.data.columns; - } else { - this.messageService.error(response.message); - } - }); - } + async ngAfterViewInit() { + const request = new RequestModel(); + request.config = await this.dataSourceService.getByAliasAsync(this.config.value); + const _value = new DatabaseModel(); + _value.database = this.database; + _value.name = this.value; + this.tableService.getPartitions(request, _value).then(response => { + if (response.status) { + this.partitions = response.data.columns; + } else { + this.messageService.error(response.message); + } + }); + } - handlerValidate() { - if (StringUtils.isNotEmpty(this.partition)) { - this.disabled.button = false; - } else { - this.disabled.button = true; - } + handlerValidate() { + if (StringUtils.isNotEmpty(this.partition)) { + this.disabled.button = false; + } else { + this.disabled.button = true; } + } - handlerOptimize() { - this.loading.button = true; - const request = new RequestModel(); - request.config = this.dataSourceService.getAll(this.config.value)?.data?.columns[0]; - const _value = new DatabaseModel(); - _value.database = this.database; - _value.name = this.value; - this.tableService.optimize(request, _value, this.partition, this.final).then(response => { - if (response.status) { - this.messageService.success(response.message); - this.emitter.emit(true); - } else { - this.messageService.error(response.message); - } - this.loading.button = false; - }); - } + async handlerOptimize() { + this.loading.button = true; + const request = new RequestModel(); + request.config = await this.dataSourceService.getByAliasAsync(this.config.value); + const _value = new DatabaseModel(); + _value.database = this.database; + _value.name = this.value; + this.tableService.optimize(request, _value, this.partition, this.final).then(response => { + if (response.status) { + this.messageService.success(response.message); + this.emitter.emit(true); + } else { + this.messageService.error(response.message); + } + this.loading.button = false; + }); + } } diff --git a/src/renderer/components/table/preview/table.preview.component.html b/src/renderer/components/table/preview/table.preview.component.html index 51483ea1..aa3485a9 100644 --- a/src/renderer/components/table/preview/table.preview.component.html +++ b/src/renderer/components/table/preview/table.preview.component.html @@ -1,17 +1,17 @@
    - - - {{'common.database'|translate}} - - {{database}} - - - - {{'common.table'|translate}} - - {{value}} - - - - -
    \ No newline at end of file +
    + + {{'common.database'|translate}} + + {{database}} + + + + {{'common.table'|translate}} + + {{value}} + + +
    + +
    diff --git a/src/renderer/components/table/preview/table.preview.component.ts b/src/renderer/components/table/preview/table.preview.component.ts index 55b20b8a..d2cc7635 100644 --- a/src/renderer/components/table/preview/table.preview.component.ts +++ b/src/renderer/components/table/preview/table.preview.component.ts @@ -9,36 +9,36 @@ import { TableService } from '@renderer/services/management/table.service'; import { NzMessageService } from 'ng-zorro-antd/message'; @Component({ - selector: 'app-component-preview-table', - templateUrl: './table.preview.component.html' + selector: 'app-component-preview-table', + templateUrl: './table.preview.component.html' }) export class PreviewTableComponent extends BaseComponent implements AfterViewInit { - @Input() - config: ConfigModel; - @Input() - value: string; - @Input() - database: string; - tableData: ResponseDataModel; + @Input() + config: ConfigModel; + @Input() + value: string; + @Input() + database: string; + tableData: ResponseDataModel; - constructor(private dataSourceService: DatasourceService, - private tableService: TableService, - private messageService: NzMessageService) { - super(); - } + constructor(private dataSourceService: DatasourceService, + private tableService: TableService, + private messageService: NzMessageService) { + super(); + } - ngAfterViewInit(): void { - const request = new RequestModel(); - request.config = this.dataSourceService.getAll(this.config.value)?.data?.columns[0]; - const _value = new DatabaseModel(); - _value.database = this.database; - _value.name = this.value; - this.tableService.getPreview(request, _value).then(response => { - if (response.status) { - this.tableData = response.data; - } else { - this.messageService.error(response.message); - } - }); - } + async ngAfterViewInit() { + const request = new RequestModel(); + request.config = await this.dataSourceService.getByAliasAsync(this.config.value); + const _value = new DatabaseModel(); + _value.database = this.database; + _value.name = this.value; + this.tableService.getPreview(request, _value).then(response => { + if (response.status) { + this.tableData = response.data; + } else { + this.messageService.error(response.message); + } + }); + } } diff --git a/src/renderer/components/table/rename/table.rename.component.ts b/src/renderer/components/table/rename/table.rename.component.ts index dfcf49fa..87a79bec 100644 --- a/src/renderer/components/table/rename/table.rename.component.ts +++ b/src/renderer/components/table/rename/table.rename.component.ts @@ -9,49 +9,49 @@ import { StringUtils } from '@renderer/utils/string.utils'; import { NzMessageService } from 'ng-zorro-antd/message'; @Component({ - selector: 'app-component-rename-table', - templateUrl: './table.rename.component.html' + selector: 'app-component-rename-table', + templateUrl: './table.rename.component.html' }) export class RenameTableComponent extends BaseComponent { - @Input() - config: ConfigModel; - @Input() - value: string; - @Input() - database: string; - @Output() - emitter = new EventEmitter(); - inputValue: string; + @Input() + config: ConfigModel; + @Input() + value: string; + @Input() + database: string; + @Output() + emitter = new EventEmitter(); + inputValue: string; - constructor(private dataSourceService: DatasourceService, - private tableService: TableService, - private messageService: NzMessageService) { - super(); - } + constructor(private dataSourceService: DatasourceService, + private tableService: TableService, + private messageService: NzMessageService) { + super(); + } - handlerValidate() { - if (StringUtils.isNotEmpty(this.inputValue) && this.inputValue !== this.value) { - this.disabled.button = false; - } else { - this.disabled.button = true; - } + handlerValidate() { + if (StringUtils.isNotEmpty(this.inputValue) && this.inputValue !== this.value) { + this.disabled.button = false; + } else { + this.disabled.button = true; } + } - handlerRename() { - this.loading.button = true; - const request = new RequestModel(); - request.config = this.dataSourceService.getAll(this.config.value)?.data?.columns[0]; - const _value = new DatabaseModel(); - _value.database = this.database; - _value.name = this.value; - this.tableService.rename(request, _value, this.inputValue).then(response => { - if (response.status) { - this.messageService.success(response.message); - this.emitter.emit(true); - } else { - this.messageService.error(response.message); - } - this.loading.button = false; - }); - } + async handlerRename() { + this.loading.button = true; + const request = new RequestModel(); + request.config = await this.dataSourceService.getByAliasAsync(this.config.value); + const _value = new DatabaseModel(); + _value.database = this.database; + _value.name = this.value; + this.tableService.rename(request, _value, this.inputValue).then(response => { + if (response.status) { + this.messageService.success(response.message); + this.emitter.emit(true); + } else { + this.messageService.error(response.message); + } + this.loading.button = false; + }); + } } diff --git a/src/renderer/components/table/structure/table.structure.component.ts b/src/renderer/components/table/structure/table.structure.component.ts index 587f8300..f1f107f5 100644 --- a/src/renderer/components/table/structure/table.structure.component.ts +++ b/src/renderer/components/table/structure/table.structure.component.ts @@ -48,10 +48,10 @@ export class StructureTableComponent extends BaseComponent implements AfterViewI this.emitter.emit(true); } - handlerInitialize() { + async handlerInitialize() { this.loading.button = true; const request = new RequestModel(); - request.config = this.dataSourceService.getAll(this.config.value)?.data?.columns[0]; + request.config = await this.dataSourceService.getByAliasAsync(this.config.value); const _value = new DatabaseModel(); _value.database = this.database; _value.name = this.value; diff --git a/src/renderer/components/table/truncate/table.truncate.component.ts b/src/renderer/components/table/truncate/table.truncate.component.ts index f2106314..7af1d7cf 100644 --- a/src/renderer/components/table/truncate/table.truncate.component.ts +++ b/src/renderer/components/table/truncate/table.truncate.component.ts @@ -36,10 +36,10 @@ export class TruncateTableComponent extends BaseComponent { } } - handlerTruncate() { + async handlerTruncate() { this.loading.button = true; const request = new RequestModel(); - request.config = this.dataSourceService.getAll(this.config.value)?.data?.columns[0]; + request.config = await this.dataSourceService.getByAliasAsync(this.config.value); const _value = new DatabaseModel(); _value.database = this.database; _value.name = this.value; diff --git a/src/renderer/components/table/ttl/modify/table.ttl.modify.component.ts b/src/renderer/components/table/ttl/modify/table.ttl.modify.component.ts index 9068c854..7164abd7 100644 --- a/src/renderer/components/table/ttl/modify/table.ttl.modify.component.ts +++ b/src/renderer/components/table/ttl/modify/table.ttl.modify.component.ts @@ -33,8 +33,8 @@ export class TableTtlModifyComponent extends BaseComponent implements AfterViewI this.ttlConfig = new TableTtlModel(); } - ngAfterViewInit(): void { - this.tableService.getTimeColumns(this.handlerGetRequest(), this.handlerGetDatabaseModel()) + async ngAfterViewInit() { + this.tableService.getTimeColumns(await this.handlerGetRequest(), this.handlerGetDatabaseModel()) .then(response => { if (response.status) { this.columns = response.data.columns; @@ -44,9 +44,9 @@ export class TableTtlModifyComponent extends BaseComponent implements AfterViewI }); } - handlerGetRequest(): RequestModel { + async handlerGetRequest(): Promise { const request = new RequestModel(); - request.config = this.dataSourceService.getAll(this.config.value)?.data?.columns[0]; + request.config = await this.dataSourceService.getByAliasAsync(this.config.value); return request; } @@ -79,11 +79,11 @@ export class TableTtlModifyComponent extends BaseComponent implements AfterViewI } } - handlerSave() { + async handlerSave() { this.loading.button = true; this.ttlConfig.database = this.database; this.ttlConfig.table = this.value; - this.tableService.modifyTTL(this.handlerGetRequest(), this.ttlConfig) + this.tableService.modifyTTL(await this.handlerGetRequest(), this.ttlConfig) .then(response => { if (response.status) { this.messageService.success(response.message); diff --git a/src/renderer/components/table/ttl/remove/table.ttl.remove.component.ts b/src/renderer/components/table/ttl/remove/table.ttl.remove.component.ts index 8da54255..edbb2767 100644 --- a/src/renderer/components/table/ttl/remove/table.ttl.remove.component.ts +++ b/src/renderer/components/table/ttl/remove/table.ttl.remove.component.ts @@ -6,7 +6,6 @@ import { NzMessageService } from 'ng-zorro-antd/message'; import { TableService } from '@renderer/services/management/table.service'; import { DatabaseModel } from '@renderer/model/database.model'; import { RequestModel } from '@renderer/model/request.model'; -import { StringUtils } from '@renderer/utils/string.utils'; import { TableTtlModel } from '@renderer/model/table/table.ttl.model'; @Component({ @@ -32,10 +31,10 @@ export class TableTtlRemoveComponent extends BaseComponent implements AfterViewI this.ttlInstance = new TableTtlModel(); } - ngAfterViewInit(): void { + async ngAfterViewInit() { this.ttlInstance.database = this.database; this.ttlInstance.table = this.value; - this.tableService.getTTL(this.handlerGetRequest(), this.ttlInstance) + this.tableService.getTTL(await this.handlerGetRequest(), this.ttlInstance) .then(response => { if (response.status) { this.ttlConfig = response.data.columns[0]; @@ -45,9 +44,9 @@ export class TableTtlRemoveComponent extends BaseComponent implements AfterViewI }); } - handlerGetRequest(): RequestModel { + async handlerGetRequest(): Promise { const request = new RequestModel(); - request.config = this.dataSourceService.getAll(this.config.value)?.data?.columns[0]; + request.config = await this.dataSourceService.getByAliasAsync(this.config.value); return request; } @@ -58,9 +57,9 @@ export class TableTtlRemoveComponent extends BaseComponent implements AfterViewI return _value; } - handlerRemove() { + async handlerRemove() { this.loading.button = true; - this.tableService.removeTTL(this.handlerGetRequest(), this.ttlInstance) + this.tableService.removeTTL(await this.handlerGetRequest(), this.ttlInstance) .then(response => { if (response.status) { this.messageService.success(response.message); diff --git a/src/renderer/config/operation.config.ts b/src/renderer/config/operation.config.ts index 9bc927ce..2e4c3d33 100644 --- a/src/renderer/config/operation.config.ts +++ b/src/renderer/config/operation.config.ts @@ -51,7 +51,8 @@ export class OperationConfig { {type: TypeEnum.column, actions: [OperationEnum.preview]}, {type: TypeEnum.column, actions: [OperationEnum.create]}, {type: TypeEnum.column, actions: [OperationEnum.delete]}, - {type: TypeEnum.column, actions: [OperationEnum.rename]} + {type: TypeEnum.column, actions: [OperationEnum.rename]}, + {type: TypeEnum.column, actions: [OperationEnum.comment]} ]; opertions.push(column); return opertions; diff --git a/src/renderer/db/dexiedb.ts b/src/renderer/db/dexiedb.ts index 28484e0f..61a6ed90 100644 --- a/src/renderer/db/dexiedb.ts +++ b/src/renderer/db/dexiedb.ts @@ -1,13 +1,20 @@ import Dexie, { Table } from 'dexie'; import { QueryHistoryModel } from '@renderer/model/query.history.model'; +import { SnippetModel } from '@renderer/model/snippet.model'; +import { DatasourceModel } from '@renderer/model/datasource.model'; export class DexieDb extends Dexie { QueryHistoryTable: Table; + SnippetTable: Table; + DataSourceTable: Table; constructor() { super('dbm_db'); - this.version(1).stores({ - QueryHistoryTable: '++id,createdTime,startTime,endTime' + this.version(4) + .stores({ + QueryHistoryTable: '++id,createdTime,startTime,endTime', + SnippetTable: '++id,name,created,updated', + DataSourceTable: '++id,name,alias,host,status,created,updated' }); } } diff --git a/src/renderer/editor.theme.scss b/src/renderer/editor.theme.scss index ef5f0920..c312e720 100644 --- a/src/renderer/editor.theme.scss +++ b/src/renderer/editor.theme.scss @@ -27,5 +27,13 @@ @import "~codemirror/theme/lesser-dark.css"; @import "~codemirror/theme/liquibyte.css"; @import "~codemirror/theme/lucario.css"; -//@import "~codemirror/theme/"; +@import "~codemirror/theme/material-darker.css"; +@import "~codemirror/theme/material-ocean.css"; +@import "~codemirror/theme/material-palenight.css"; +@import "~codemirror/theme/material.css"; +@import "~codemirror/theme/mbo.css"; +@import "~codemirror/theme/mdn-like.css"; +@import "~codemirror/theme/midnight.css"; +@import "~codemirror/theme/monokai.css"; +@import "~codemirror/theme/moxer.css"; //@import "~codemirror/theme/"; diff --git a/src/renderer/enum/editor/theme.enum.ts b/src/renderer/enum/editor/theme.enum.ts index 1782a2e6..077293d4 100644 --- a/src/renderer/enum/editor/theme.enum.ts +++ b/src/renderer/enum/editor/theme.enum.ts @@ -27,5 +27,13 @@ export enum EditorThemeEnum { juejin = ('juejin'), 'lesser-dark' = ('lesser-dark'), liquibyte = ('liquibyte'), - lucario = ('lucario') + lucario = ('lucario'), + 'material-darker' = ('material-darker'), + 'material-ocean' = ('material-ocean'), + 'material-palenight' = ('material-palenight'), + material = ('material'), + mbo = ('mbo'), + 'mdn-like' = ('mdn-like'), + midnight = ('midnight'), + moxer = ('moxer') } diff --git a/src/renderer/enum/operation.enum.ts b/src/renderer/enum/operation.enum.ts index 4dd74b3f..7f80503a 100644 --- a/src/renderer/enum/operation.enum.ts +++ b/src/renderer/enum/operation.enum.ts @@ -9,6 +9,7 @@ export enum OperationEnum { clean = ('clean'), optimize = ('optimize'), structure = ('structure'), + comment = ('comment'), ttl = ('ttl'), ttl_modify = ('ttl_modify'), ttl_remove = ('ttl_remove') diff --git a/src/renderer/job/datasource.job.ts b/src/renderer/job/datasource.job.ts index 6c5b19cd..26e742d1 100644 --- a/src/renderer/job/datasource.job.ts +++ b/src/renderer/job/datasource.job.ts @@ -9,17 +9,19 @@ export class DatasourceJob { } checkHealth() { - this.datasourceService.getAll()?.data?.columns.forEach(async element => { - const request: RequestModel = new RequestModel(); - request.config = element; - const response = await this.datasourceService.getResponse(request); - element.status = response.status; - if (StringUtils.isNotEmpty(response?.data?.columns)) { - element.version = response.data.columns[0].version; - } else { - element.message = response.message; - } - this.datasourceService.update(element.alias, element); + this.datasourceService.getAll().then(response => { + response.forEach(async element => { + const request: RequestModel = new RequestModel(); + request.config = element; + const response = await this.datasourceService.getResponse(request); + element.status = response.status; + if (StringUtils.isNotEmpty(response?.data?.columns)) { + element.version = response.data.columns[0].version; + } else { + element.message = response.message; + } + this.datasourceService.update(element); + }); }); } } diff --git a/src/renderer/model/column.model.ts b/src/renderer/model/column.model.ts index 97ce2ad1..cf8bf9b3 100644 --- a/src/renderer/model/column.model.ts +++ b/src/renderer/model/column.model.ts @@ -1,6 +1,6 @@ export class ColumnModel { name: string; - type: string; + type = 'String'; description: string; empty: boolean = false; } diff --git a/src/renderer/model/config.model.ts b/src/renderer/model/config.model.ts index 9302854d..1bd99c7a 100644 --- a/src/renderer/model/config.model.ts +++ b/src/renderer/model/config.model.ts @@ -5,7 +5,7 @@ import { NzTreeNode } from 'ng-zorro-antd/core/tree/nz-tree-base-node'; export class ConfigModel extends BaseModel { title: string; - key: ConfigModel; + key: any; value: string; type: TypeEnum; database: string; diff --git a/src/renderer/model/datasource.model.ts b/src/renderer/model/datasource.model.ts index b3be5e8e..d6cafae4 100644 --- a/src/renderer/model/datasource.model.ts +++ b/src/renderer/model/datasource.model.ts @@ -13,4 +13,6 @@ export class DatasourceModel { type: string; version: string; maxTotal = 0; + created: Date; + updated: Date; } diff --git a/src/renderer/model/snippet.model.ts b/src/renderer/model/snippet.model.ts new file mode 100644 index 00000000..89d9bad0 --- /dev/null +++ b/src/renderer/model/snippet.model.ts @@ -0,0 +1,8 @@ +export class SnippetModel { + id: number; + name: string; + description: string; + code: string; + created: Date; + updated: Date; +} diff --git a/src/renderer/services/management/column.service.ts b/src/renderer/services/management/column.service.ts index a5f269d5..01b74480 100644 --- a/src/renderer/services/management/column.service.ts +++ b/src/renderer/services/management/column.service.ts @@ -29,6 +29,12 @@ export class ColumnService implements BaseService { return this.getResponse(request, sql); } + comment(request: RequestModel, value: DatabaseModel, comment: string): Promise { + const sql = StringUtils.format(`ALTER TABLE {0} COMMENT COLUMN {1} '{2}'`, + [SqlUtils.getTableName(value.database, value.table), value.name, StringUtils.appendBackslash(comment)]); + return this.getResponse(request, sql); + } + rename(request: RequestModel, value: DatabaseModel, newName: string): Promise { const sql = StringUtils.format('ALTER TABLE {0} RENAME COLUMN {1} TO {2}', [SqlUtils.getTableName(value.database, value.table), value.name, newName]); return this.getResponse(request, sql); diff --git a/src/renderer/services/management/datasource.service.ts b/src/renderer/services/management/datasource.service.ts index b5e6e345..3cda0cbe 100644 --- a/src/renderer/services/management/datasource.service.ts +++ b/src/renderer/services/management/datasource.service.ts @@ -1,16 +1,21 @@ import { BaseService } from '@renderer/services/base.service'; -import { ResponseDataModel, ResponseModel } from '@renderer/model/response.model'; +import { ResponseModel } from '@renderer/model/response.model'; import { RequestModel } from '@renderer/model/request.model'; import { UrlUtils } from '@renderer/utils/url.utils'; -import { RequestUtils } from '@renderer/utils/request.utils'; -import { StringUtils } from '@renderer/utils/string.utils'; import { DatasourceModel } from '@renderer/model/datasource.model'; import { HttpService } from '@renderer/services/http.service'; import { Injectable } from '@angular/core'; +import { PromiseExtended } from 'dexie'; +import { PersistenceService } from '@renderer/services/persistence.service'; +import { DexieDb } from '@renderer/db/dexiedb'; @Injectable() -export class DatasourceService implements BaseService { +export class DatasourceService extends PersistenceService implements BaseService { + private db: DexieDb; + constructor(private httpService: HttpService) { + super(); + this.db = new DexieDb(); } getResponse(request: RequestModel, sql?: string): Promise { @@ -18,81 +23,51 @@ export class DatasourceService implements BaseService { return this.httpService.post(UrlUtils.formatUrl(request), sql); } - save(request: RequestModel): ResponseModel { - const response = new ResponseModel(); - const dsData = this.getAll(null).data; - const dataSources = dsData.columns; - const validateResponse = dataSources.filter(item => item.alias === request.config.alias); - if (validateResponse.length > 0) { - response.status = false; - response.message = StringUtils.format('DataSource <{0}> Save Error, exists!', - [request.config.alias]); - } else { - dataSources.push(request.config); - localStorage.setItem(RequestUtils.KEY_DATASOURCE, JSON.stringify(dataSources)); - response.status = true; - response.message = StringUtils.format('DataSource <{0}> Save Success!', - [request.config.alias]); - } - return response; - } - /** * Get the local storage buffer data source * * @param uniqueName Data source name */ - getAll(uniqueName?: string): ResponseModel { - const response = new ResponseModel(); - response.status = true; - const dataSources = JSON.parse(localStorage.getItem(RequestUtils.KEY_DATASOURCE)); - const sources = dataSources === null ? [] : dataSources; - const responseData = new ResponseDataModel(); - responseData.columns = sources; - if (sources.length > 0) { - const headers = []; - Object.keys(sources[0]).forEach(key => { - headers.push({ - name: key, - type: 'String' - }); - }); - responseData.headers = headers; - if (StringUtils.isNotEmpty(uniqueName)) { - responseData.columns = sources.filter(item => item.alias === uniqueName); - } - } - response.data = responseData; - return response; + getAll(): PromiseExtended { + return this.db.DataSourceTable + .orderBy('created') + .reverse() + .toArray(); + } + + delete(id: number): PromiseExtended { + return this.db.DataSourceTable.delete(id); + } + + update(model: DatasourceModel): PromiseExtended { + model.updated = new Date(); + return this.db.DataSourceTable.update(model.id, model); + } + + clear(): boolean { + return false; + } + + deleteById(id: number): boolean { + return false; + } + + save(model: DatasourceModel): PromiseExtended { + model.created = new Date(); + model.updated = new Date(); + model.id = undefined; + return this.db.DataSourceTable.add(model); } - delete(unique: string): ResponseModel { - const response = new ResponseModel(); - response.status = true; - const dataSources = JSON.parse(localStorage.getItem(RequestUtils.KEY_DATASOURCE)) - .filter(item => item.alias !== unique); - localStorage.setItem(RequestUtils.KEY_DATASOURCE, JSON.stringify(dataSources)); - response.message = StringUtils.format('Delete <{0}> success!', - [unique]); - return response; + findByAlias(alias: string): PromiseExtended { + return this.db.DataSourceTable.where('alias').equals(alias).first(); } - update(unique: string, source: DatasourceModel) { - const response = new ResponseModel(); - const dataSources = JSON.parse(localStorage.getItem(RequestUtils.KEY_DATASOURCE)) - .filter(item => item.alias !== unique); - const validateResponse = dataSources.filter(item => item.alias === source.alias); - if (validateResponse.length > 0) { - response.message = StringUtils.format('DataSource <{0}> update error, exists!', - [source.alias]); - response.status = false; - } else { - dataSources.push(source); - localStorage.setItem(RequestUtils.KEY_DATASOURCE, JSON.stringify(dataSources)); - response.message = StringUtils.format('Update <{0}> success!', - [unique]); - response.status = true; - } - return response; + async getByAliasAsync(alias: string): Promise { + let dataSource; + dataSource = await this.db.DataSourceTable.where('alias') + .equals(alias) + .toArray(); + return dataSource.length > 0 ? dataSource[0] : new DatasourceModel(); } } diff --git a/src/renderer/services/management/table.service.ts b/src/renderer/services/management/table.service.ts index 7d06127d..ecd15ae0 100644 --- a/src/renderer/services/management/table.service.ts +++ b/src/renderer/services/management/table.service.ts @@ -236,6 +236,7 @@ export class TableService implements BaseService { break; case PropertyEnum.name: const substr = configure.properties + .filter(element => StringUtils.isNotEmpty(element.value)) .flatMap(element => StringUtils.format('\'{0}\'', [element.value])) .join(', '); sql = StringUtils.format('{0} {1}({2})', [prefix, configure.type, substr]); diff --git a/src/renderer/services/persistence.service.ts b/src/renderer/services/persistence.service.ts index 9d04663d..d2541a88 100644 --- a/src/renderer/services/persistence.service.ts +++ b/src/renderer/services/persistence.service.ts @@ -1,6 +1,6 @@ export abstract class PersistenceService { public abstract save(model: any): any; - public abstract getAll(): any[]; + public abstract getAll(): any; public abstract clear(): boolean; public abstract deleteById(id: number): boolean; } diff --git a/src/renderer/services/snippet/snippet.service.ts b/src/renderer/services/snippet/snippet.service.ts new file mode 100644 index 00000000..6e82e372 --- /dev/null +++ b/src/renderer/services/snippet/snippet.service.ts @@ -0,0 +1,51 @@ +import { BaseService } from '@renderer/services/base.service'; +import { RequestModel } from '@renderer/model/request.model'; +import { ResponseModel } from '@renderer/model/response.model'; +import { PersistenceService } from '@renderer/services/persistence.service'; +import { DexieDb } from '@renderer/db/dexiedb'; +import { SnippetModel } from '@renderer/model/snippet.model'; +import { PromiseExtended } from 'dexie'; +import { Injectable } from '@angular/core'; + +@Injectable() +export class SnippetService extends PersistenceService implements BaseService { + private db: DexieDb; + + constructor() { + super(); + this.db = new DexieDb(); + } + + getResponse(request: RequestModel, sql?: string): Promise { + return Promise.resolve(undefined); + } + + save(model: SnippetModel): PromiseExtended { + model.created = new Date(); + model.updated = new Date(); + return this.db.SnippetTable.add(model); + } + + update(model: SnippetModel): PromiseExtended { + return this.db.SnippetTable.update(model.id, model); + } + + getAll(): PromiseExtended { + return this.db.SnippetTable + .orderBy('id') + .reverse() + .toArray(); + } + + clear(): boolean { + return false; + } + + delete(id: number): PromiseExtended { + return this.db.SnippetTable.delete(id); + } + + deleteById(id: number): boolean { + return false; + } +} diff --git a/src/renderer/services/tools/migrate.service.ts b/src/renderer/services/tools/migrate.service.ts index 9de825c2..e36bc03a 100644 --- a/src/renderer/services/tools/migrate.service.ts +++ b/src/renderer/services/tools/migrate.service.ts @@ -10,104 +10,97 @@ import { TableService } from '../management/table.service'; @Injectable() export class MigrateService implements BaseService { - constructor(private httpService: HttpService, - private tableService: TableService, - private datasourceService: DatasourceService) { - } - - getResponse(request: RequestModel, sql?: string): Promise { - return this.httpService.post(UrlUtils.formatUrl(request), sql); - } - - async migrate(source, target): Promise { - let response - let targetDatabase = target.database - let targetTable = target.table - if (StringUtils.isEmpty(targetDatabase)) { - targetDatabase = source.database - } - if (StringUtils.isEmpty(targetTable)) { - targetTable = source.table - } - - const sourceRequest = new RequestModel() - sourceRequest.config = this.datasourceService.getAll(source.datasource)?.data?.columns[0]; - const targetRequest = new RequestModel() - targetRequest.config = this.datasourceService.getAll(target.datasource)?.data?.columns[0]; - - // step 1: check table from target server - let tableExists = false - const cr = await this.tableService.check(targetRequest, targetDatabase, source.table) - if (cr?.status) { - if (cr.data?.columns.length > 0) { - tableExists = true - } else { - response = cr; - } - } - - // step 2: get table ddl to source server - let tableDdl - const sql = StringUtils.format('SHOW CREATE TABLE `{0}`.`{1}`', [source.database, source.table]) - const gr = await this.getResponse(sourceRequest, sql) - if (gr?.status) { - if (gr.data?.columns.length > 0) { - tableDdl = gr.data.columns[0].statement - } else { - response = gr; - } - } - - // step 3: replace table name - if (StringUtils.isNotEmpty(tableDdl)) { - tableDdl = tableDdl.replace(StringUtils.format('{0}.{1}', [source.database, source.table]), - StringUtils.format('`{0}`.`{1}`', [targetDatabase, targetTable])) - } + constructor(private httpService: HttpService, + private tableService: TableService, + private datasourceService: DatasourceService) { + } - // step 4: create table on target server - let tableCreate = false - if (!tableExists) { - const gqr = await this.getResponse(targetRequest, tableDdl) - if (gqr?.status) { - tableCreate = true - } else { - response = gqr; - } - } + getResponse(request: RequestModel, sql?: string): Promise { + return this.httpService.post(UrlUtils.formatUrl(request), sql); + } - // step 5: migrate data - if ((tableExists && !tableCreate) || (!tableExists && tableCreate)) { - const sql = this.builderDDL(source, target, targetDatabase, targetTable, sourceRequest) - response = await this.getResponse(targetRequest, sql) - } - return response; + async migrate(source, target): Promise { + let response; + let targetDatabase = target.database; + let targetTable = target.table; + if (StringUtils.isEmpty(targetDatabase)) { + targetDatabase = source.database; } + if (StringUtils.isEmpty(targetTable)) { + targetTable = source.table; + } + const sourceRequest = new RequestModel(); + sourceRequest.config = await this.datasourceService.getByAliasAsync(source.datasource); + const targetRequest = new RequestModel(); + targetRequest.config = await this.datasourceService.getByAliasAsync(target.datasource); + // step 1: check table from target server + let tableExists = false; + const cr = await this.tableService.check(targetRequest, targetDatabase, source.table); + if (cr?.status) { + if (cr.data?.columns.length > 0) { + tableExists = true; + } else { + response = cr; + } + } + // step 2: get table ddl to source server + let tableDdl; + const sql = StringUtils.format('SHOW CREATE TABLE `{0}`.`{1}`', [source.database, source.table]); + const gr = await this.getResponse(sourceRequest, sql); + if (gr?.status) { + if (gr.data?.columns.length > 0) { + tableDdl = gr.data.columns[0].statement; + } else { + response = gr; + } + } + // step 3: replace table name + if (StringUtils.isNotEmpty(tableDdl)) { + tableDdl = tableDdl.replace(StringUtils.format('{0}.{1}', [source.database, source.table]), + StringUtils.format('`{0}`.`{1}`', [targetDatabase, targetTable])); + } + // step 4: create table on target server + let tableCreate = false; + if (!tableExists) { + const gqr = await this.getResponse(targetRequest, tableDdl); + if (gqr?.status) { + tableCreate = true; + } else { + response = gqr; + } + } + // step 5: migrate data + if ((tableExists && !tableCreate) || (!tableExists && tableCreate)) { + const sql = this.builderDDL(source, target, targetDatabase, targetTable, sourceRequest); + response = await this.getResponse(targetRequest, sql); + } + return response; + } - builderDDL(source, target, targetDatabase, targetTable, sourceRequest: RequestModel): string { - let sql - if (source.datasource === target.datasource) { - sql = StringUtils.format(` + builderDDL(source, target, targetDatabase, targetTable, sourceRequest: RequestModel): string { + let sql; + if (source.datasource === target.datasource) { + sql = StringUtils.format(` INSERT INTO {0} SELECT * FROM {1} `, [ - StringUtils.format('`{0}`.`{1}`', [targetDatabase, targetTable]), - StringUtils.format('`{0}`.`{1}`', [source.database, source.table]) - ]) - } else { - const username = StringUtils.isEmpty(sourceRequest.config.username) ? '' : sourceRequest.config.username; - const password = StringUtils.isEmpty(sourceRequest.config.password) ? '' : sourceRequest.config.password; - sql = StringUtils.format(` + StringUtils.format('`{0}`.`{1}`', [targetDatabase, targetTable]), + StringUtils.format('`{0}`.`{1}`', [source.database, source.table]) + ]); + } else { + const username = StringUtils.isEmpty(sourceRequest.config.username) ? '' : sourceRequest.config.username; + const password = StringUtils.isEmpty(sourceRequest.config.password) ? '' : sourceRequest.config.password; + sql = StringUtils.format(` INSERT INTO {0} SELECT * FROM remote('{1}', {2}, {3}, '{4}', '{5}') `, [ - StringUtils.format('{0}.{1}', [targetDatabase, targetTable]), - sourceRequest.config.host, - source.database, - source.table, - username, - password]) - } - return sql + StringUtils.format('{0}.{1}', [targetDatabase, targetTable]), + sourceRequest.config.host, + source.database, + source.table, + username, + password]); } - -} \ No newline at end of file + return sql; + } +} diff --git a/src/renderer/services/tools/track.service.ts b/src/renderer/services/tools/track.service.ts index 2ed0c608..3e1281d9 100644 --- a/src/renderer/services/tools/track.service.ts +++ b/src/renderer/services/tools/track.service.ts @@ -17,7 +17,7 @@ export class TrackService implements BaseService { return this.httpService.post(UrlUtils.formatUrl(request), sql); } - getTrackInfo(aliasServerName: string, trackId: string) { + async getTrackInfo(aliasServerName: string, trackId: string) { const sql = StringUtils.format(` SELECT query_id AS id, @@ -45,11 +45,11 @@ ORDER BY type DESC `, [trackId]); const request = new RequestModel(); - request.config = this.datasourceService.getAll(aliasServerName)?.data?.columns[0]; + request.config = await this.datasourceService.getByAliasAsync(aliasServerName); return this.getResponse(request, sql); } - getTrackTop(aliasServerName: string, top?: number) { + async getTrackTop(aliasServerName: string, top?: number) { if (StringUtils.isEmpty(top)) { top = 100; } @@ -65,7 +65,7 @@ LIMIT {0} `, [top]); const request = new RequestModel(); - request.config = this.datasourceService.getAll(aliasServerName)?.data?.columns[0]; + request.config = await this.datasourceService.getByAliasAsync(aliasServerName); return this.getResponse(request, sql); } }