-
-
Notifications
You must be signed in to change notification settings - Fork 18
add clickhouse db #1480
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add clickhouse db #1480
Changes from all commits
6ebb952
8ab34d4
8a5129f
592be92
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -47,6 +47,7 @@ import { UserService } from 'src/app/services/user.service'; | |
| import { environment } from 'src/environments/environment'; | ||
| import googlIPsList from 'src/app/consts/google-IP-addresses'; | ||
| import isIP from 'validator/lib/isIP'; | ||
| import { ClickhouseCredentialsFormComponent } from './db-credentials-forms/clickhouse-credentials-form/clickhouse-credentials-form.component'; | ||
|
|
||
| @Component({ | ||
| selector: 'app-connect-db', | ||
|
|
@@ -76,6 +77,7 @@ import isIP from 'validator/lib/isIP'; | |
| PostgresCredentialsFormComponent, | ||
| RedisCredentialsFormComponent, | ||
| ElasticCredentialsFormComponent, | ||
| ClickhouseCredentialsFormComponent, | ||
|
||
| IpAddressButtonComponent, | ||
| AlertComponent, | ||
| Angulartics2Module | ||
|
|
@@ -107,6 +109,7 @@ export class ConnectDBComponent implements OnInit { | |
| [DBtype.Cassandra]: '9042', | ||
| [DBtype.Redis]: '6379', | ||
| [DBtype.Elasticsearch]: '9200', | ||
| [DBtype.ClickHouse]: '8443', | ||
| [DBtype.DB2]: '50000' | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| .connectForm__hostname, | ||
| .connectForm__port { | ||
| padding-bottom: 20px; | ||
| } | ||
|
|
||
| @media (width <= 600px) { | ||
| .connectForm__hostname { | ||
| padding-bottom: 44px; | ||
| } | ||
|
|
||
| .connectForm__port { | ||
| padding-bottom: 0; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,180 @@ | ||||||
| <mat-form-field appearance="outline" class="connectForm__hostname credentials-fieldset__1-3-columns"> | ||||||
| <mat-label>Hostname</mat-label> | ||||||
| <input matInput name="hostname" #hostname="ngModel" | ||||||
| data-testid="connection-hostname-input" | ||||||
| angulartics2On="change" | ||||||
| angularticsAction="Connection creds {{ connection.id ? 'edit' : 'add' }}: hostname is edited" | ||||||
| required hostnameValidator | ||||||
| [readonly]="readonly" | ||||||
| [disabled]="submitting" | ||||||
| [(ngModel)]="connection.host"> | ||||||
| <mat-hint> | ||||||
| E.g. <strong><code>my-test-db.eu-west-2.aws.clickhouse.cloud</code></strong> | ||||||
| <br/> | ||||||
| Connections from internal IPs (e.g. localhost) are not supported | ||||||
| </mat-hint> | ||||||
|
|
||||||
| <mat-error *ngIf="hostname.errors?.isLocalhost && hostname.invalid"> | ||||||
| To connect a database to an internal IP, use something like <strong>Pinggy</strong> | ||||||
| (<a [href]="tunnelingServiceLink" target="_blank" class="credentials-fieldset__hint-link">here's a guide</a>), | ||||||
| or <button type="button" (click)="switchToAgent.emit()" class="credentials-fieldset__hint-button">click here</button> to connect through an agent | ||||||
| </mat-error> | ||||||
| <mat-error *ngIf="hostname.errors?.isInvalidHostname && hostname.invalid">Hostname is invalid</mat-error> | ||||||
| </mat-form-field> | ||||||
|
|
||||||
| <mat-form-field appearance="outline" class="connectForm__port"> | ||||||
| <mat-label>Port</mat-label> | ||||||
| <input matInput type="number" name="port" #port="ngModel" | ||||||
| data-testid="connection-port-input" | ||||||
| angulartics2On="change" | ||||||
| angularticsAction="Connection creds {{ connection.id ? 'edit' : 'add' }}: port is edited" | ||||||
| required | ||||||
| [readonly]="readonly" | ||||||
| [disabled]="submitting" | ||||||
| [(ngModel)]="connection.port"> | ||||||
| <mat-error *ngIf="port.errors?.required && (port.invalid && port.touched)">Port should not be empty</mat-error> | ||||||
| </mat-form-field> | ||||||
|
|
||||||
| <mat-form-field appearance="outline" class="credentials-fieldset__1-2-columns"> | ||||||
| <mat-label>Username</mat-label> | ||||||
| <input matInput name="username" #username="ngModel" | ||||||
| data-testid="connection-username-input" | ||||||
| angulartics2On="change" | ||||||
| angularticsAction="Connection creds {{ connection.id ? 'edit' : 'add' }}: username is edited" | ||||||
| required | ||||||
| [readonly]="readonly" | ||||||
| [disabled]="submitting" | ||||||
| [(ngModel)]="connection.username"> | ||||||
| <mat-error *ngIf="username.errors?.required && (username.invalid && username.touched)">Username should not be empty</mat-error> | ||||||
| </mat-form-field> | ||||||
|
|
||||||
| <mat-form-field appearance="outline" class="credentials-fieldset__3-4-columns"> | ||||||
| <mat-label>Password</mat-label> | ||||||
| <input type="password" matInput name="password" #password="ngModel" | ||||||
| data-testid="connection-password-input" | ||||||
| angulartics2On="change" | ||||||
| angularticsAction="Connection creds {{ connection.id ? 'edit' : 'add' }}: password is edited" | ||||||
| [required]="!connection.id || hostname.touched || port.touched" | ||||||
| [readonly]="readonly" | ||||||
| [disabled]="submitting" | ||||||
| [(ngModel)]="connection.password"> | ||||||
| <mat-hint *ngIf="connection.id && (hostname.pristine && port.pristine)">To keep password the same keep this field blank</mat-hint> | ||||||
| <mat-hint *ngIf="connection.id && (hostname.dirty || port.dirty)">Password needed due to hostname/port change</mat-hint> | ||||||
| <!-- <mat-error *ngIf="email.errors.required && (email.invalid && email.touched)">Email should not be empty</mat-error> --> | ||||||
| </mat-form-field> | ||||||
|
|
||||||
| <mat-form-field appearance="outline" class="credentials-fieldset__1-4-columns"> | ||||||
| <mat-label>Database Name</mat-label> | ||||||
| <input matInput name="database" #database="ngModel" | ||||||
| data-testid="connection-database-input" | ||||||
| angulartics2On="change" | ||||||
| angularticsAction="Connection creds {{ connection.id ? 'edit' : 'add' }}: database name is edited" | ||||||
| required | ||||||
| [readonly]="readonly" | ||||||
| [disabled]="submitting" | ||||||
| [(ngModel)]="connection.database"> | ||||||
| <mat-error *ngIf="database.errors?.required && (database.invalid && database.touched)">Name should not be empty</mat-error> | ||||||
| </mat-form-field> | ||||||
|
|
||||||
| <mat-expansion-panel class="credentials-fieldset__1-4-columns"> | ||||||
| <mat-expansion-panel-header data-testid="connection-advanced-settings-expansion-panel-header"> | ||||||
| <mat-panel-title> | ||||||
| Advanced settings | ||||||
| </mat-panel-title> | ||||||
| </mat-expansion-panel-header> | ||||||
|
|
||||||
| <div class="advanced-settings"> | ||||||
| <app-master-encryption-password | ||||||
| class="advanced-settings__fullLine" | ||||||
| [masterKey]="masterKey" | ||||||
| [disabled]="accessLevel === 'readonly' || submitting || connection?.isTestConnection" | ||||||
| (onMasterKeyChange)="handleMasterKeyChange($event)"> | ||||||
| </app-master-encryption-password> | ||||||
|
|
||||||
| <mat-checkbox class="checkbox-line advanced-settings__fullLine" name="ssh" #ssh="ngModel" | ||||||
| data-testid="connection-ssh-checkbox" | ||||||
| labelPosition="after" | ||||||
| angulartics2On="click" | ||||||
| angularticsAction="Connection creds {{ connection.id ? 'edit' : 'add' }}: SSH is switched" | ||||||
| [angularticsProperties]="{'enable': connection.ssh}" | ||||||
| [disabled]="submitting || connection.isTestConnection" | ||||||
| [(ngModel)]="connection.ssh"> | ||||||
| Use SSH tunnel | ||||||
| </mat-checkbox> | ||||||
|
|
||||||
| <mat-form-field *ngIf="connection.ssh" appearance="outline" floatLabel="always" class="advanced-settings__fullLine"> | ||||||
| <mat-label>Private SSH key</mat-label> | ||||||
| <textarea matInput resizeToFitContent rows="8" name="privateSSHKey" #privateSSHKey="ngModel" | ||||||
| placeholder="Sensitive — write-only field" | ||||||
| data-testid="connection-ssh-key-textarea" | ||||||
| angulartics2On="change" | ||||||
| angularticsAction="Connection creds {{ connection.id ? 'edit' : 'add' }}: SSH key is edited" | ||||||
| [required]="connection.ssh && !connection.id" [readonly]="accessLevel === 'readonly' && connection.id" | ||||||
| [disabled]="submitting" | ||||||
| [(ngModel)]="connection.privateSSHKey" | ||||||
| ></textarea> | ||||||
| <mat-error *ngIf="privateSSHKey.errors?.required && (privateSSHKey.invalid && privateSSHKey.touched)">Private SSH key should not be empty</mat-error> | ||||||
| </mat-form-field> | ||||||
|
|
||||||
| <mat-form-field *ngIf="connection.ssh" appearance="outline"> | ||||||
| <mat-label>SSH host</mat-label> | ||||||
| <input matInput name="sshHost" #sshHost="ngModel" | ||||||
| data-testid="connection-ssh-host-input" | ||||||
| angulartics2On="change" | ||||||
| angularticsAction="Connection creds {{ connection.id ? 'edit' : 'add' }}: SSH host is edited" | ||||||
| [required]="connection.ssh" [readonly]="accessLevel === 'readonly' && connection.id" | ||||||
| [disabled]="submitting" | ||||||
| [(ngModel)]="connection.sshHost"> | ||||||
| <mat-error *ngIf="sshHost.errors?.required && (sshHost.invalid && sshHost.touched)">SSH host should not be empty</mat-error> | ||||||
| </mat-form-field> | ||||||
|
|
||||||
| <mat-form-field *ngIf="connection.ssh" appearance="outline"> | ||||||
| <mat-label>SSH port</mat-label> | ||||||
| <input matInput type="number" name="sshPort" #sshPort="ngModel" | ||||||
| data-testid="connection-ssh-port-input" | ||||||
| angulartics2On="change" | ||||||
| angularticsAction="Connection creds {{ connection.id ? 'edit' : 'add' }}: SSH port is edited" | ||||||
| [required]="connection.ssh" [readonly]="accessLevel === 'readonly' && connection.id" | ||||||
| [disabled]="submitting" | ||||||
| [(ngModel)]="connection.sshPort"> | ||||||
| <mat-error *ngIf="sshPort.errors?.required && (sshPort.invalid && sshPort.touched)">SSH port should not be empty</mat-error> | ||||||
| </mat-form-field> | ||||||
|
|
||||||
| <mat-form-field *ngIf="connection.ssh" appearance="outline" floatLabel="always"> | ||||||
| <mat-label>SSH username</mat-label> | ||||||
| <input matInput name="sshUsername" #sshUsername="ngModel" | ||||||
| placeholder="Sensitive — write-only field" | ||||||
| data-testid="connection-ssh-username-input" | ||||||
| angulartics2On="change" | ||||||
| angularticsAction="Connection creds {{ connection.id ? 'edit' : 'add' }}: SSH username is edited" | ||||||
| [required]="connection.ssh" [readonly]="accessLevel === 'readonly' && connection.id" | ||||||
| [disabled]="submitting" | ||||||
| [(ngModel)]="connection.sshUsername"> | ||||||
| <mat-error *ngIf="sshUsername.errors?.required && (sshUsername.invalid && sshUsername.touched)">SSH username should not be empty</mat-error> | ||||||
| </mat-form-field> | ||||||
|
|
||||||
| <mat-checkbox class="checkbox-line advanced-settings__fullLine" name="ssl" #ssh="ngModel" | ||||||
|
||||||
| <mat-checkbox class="checkbox-line advanced-settings__fullLine" name="ssl" #ssh="ngModel" | |
| <mat-checkbox class="checkbox-line advanced-settings__fullLine" name="ssl" #ssl="ngModel" |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,40 @@ | ||||||
| import { ComponentFixture, TestBed } from '@angular/core/testing'; | ||||||
|
|
||||||
| import { ClickhouseCredentialsFormComponent } from './clickhouse-credentials-form.component'; | ||||||
|
||||||
| import { FormsModule } from '@angular/forms'; | ||||||
| import { MatCheckboxModule } from '@angular/material/checkbox'; | ||||||
| import { Angulartics2Module } from 'angulartics2'; | ||||||
| import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; | ||||||
| import { provideHttpClient } from '@angular/common/http'; | ||||||
|
|
||||||
| describe('ClickhouseCredentialsFormComponent', () => { | ||||||
|
||||||
| describe('ClickhouseCredentialsFormComponent', () => { | |
| describe('ClickHouseCredentialsFormComponent', () => { |
Copilot
AI
Dec 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The component type reference should be ClickHouseCredentialsFormComponent (with capital 'H') to match the ClickHouse branding and be consistent with the component naming convention.
Copilot
AI
Dec 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The component reference should be ClickHouseCredentialsFormComponent (with capital 'H') to match the ClickHouse branding and be consistent with the component naming convention.
Copilot
AI
Dec 20, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The component type reference should be ClickHouseCredentialsFormComponent (with capital 'H') to match the ClickHouse branding and be consistent with the component naming convention.
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,32 @@ | ||||||
| import { Angulartics2Module } from 'angulartics2'; | ||||||
| import { BaseCredentialsFormComponent } from '../base-credentials-form/base-credentials-form.component'; | ||||||
| import { Component } from '@angular/core'; | ||||||
| import { FormsModule } from '@angular/forms'; | ||||||
| import { HostnameValidationDirective } from 'src/app/directives/hostnameValidator.directive'; | ||||||
| import { MasterEncryptionPasswordComponent } from '../../master-encryption-password/master-encryption-password.component'; | ||||||
| import { MatCheckboxModule } from '@angular/material/checkbox'; | ||||||
| import { MatExpansionModule } from '@angular/material/expansion'; | ||||||
| import { MatFormFieldModule } from '@angular/material/form-field'; | ||||||
| import { MatInputModule } from '@angular/material/input'; | ||||||
| import { NgIf } from '@angular/common'; | ||||||
|
|
||||||
| @Component({ | ||||||
| selector: 'app-clickhouse-credentials-form', | ||||||
| templateUrl: './clickhouse-credentials-form.component.html', | ||||||
| styleUrls: ['../base-credentials-form/base-credentials-form.component.css', './clickhouse-credentials-form.component.css'], | ||||||
| standalone: true, | ||||||
| imports: [ | ||||||
| NgIf, | ||||||
| FormsModule, | ||||||
| MatFormFieldModule, | ||||||
| MatInputModule, | ||||||
| MatCheckboxModule, | ||||||
| MatExpansionModule, | ||||||
| HostnameValidationDirective, | ||||||
| MasterEncryptionPasswordComponent, | ||||||
| Angulartics2Module | ||||||
| ] | ||||||
| }) | ||||||
| export class ClickhouseCredentialsFormComponent extends BaseCredentialsFormComponent { | ||||||
|
||||||
| export class ClickhouseCredentialsFormComponent extends BaseCredentialsFormComponent { | |
| export class ClickHouseCredentialsFormComponent extends BaseCredentialsFormComponent { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The import statement should use
ClickHouseCredentialsFormComponent(with capital 'H') to match the ClickHouse branding and be consistent with the component naming convention.