diff --git a/frontend/src/app/components/connections-list/connections-list.component.css b/frontend/src/app/components/connections-list/connections-list.component.css
index c0b35798c..d1a03e4f3 100644
--- a/frontend/src/app/components/connections-list/connections-list.component.css
+++ b/frontend/src/app/components/connections-list/connections-list.component.css
@@ -9,7 +9,7 @@
background-position: left 125%, right -26%;
background-size: 17%, 18%;
height: 100%;
- padding: 72px max(calc(50vw - 535px), 10%) 24px;
+ padding: 72px max(calc(50vw - 535px), 10%) 72px;
}
diff --git a/frontend/src/app/components/connections-list/connections-list.component.html b/frontend/src/app/components/connections-list/connections-list.component.html
index 08fa9c07d..2a6becd5e 100644
--- a/frontend/src/app/components/connections-list/connections-list.component.html
+++ b/frontend/src/app/components/connections-list/connections-list.component.html
@@ -17,11 +17,11 @@
{{companyN
diff --git a/frontend/src/app/components/connections-list/connections-list.component.spec.ts b/frontend/src/app/components/connections-list/connections-list.component.spec.ts
index 8e97dbf49..6c3fbeb93 100644
--- a/frontend/src/app/components/connections-list/connections-list.component.spec.ts
+++ b/frontend/src/app/components/connections-list/connections-list.component.spec.ts
@@ -40,198 +40,4 @@ describe('ConnectionsListComponent', () => {
it('should create', () => {
expect(component).toBeTruthy();
});
-
- it('should sort connections on test and own, and set object of titles', () => {
- const fakeConnections = {
- "connections": [
- {
- "connection": {
- "id": "9176a5d1-624f-48af-b5a2-f0a08e15252f",
- "title": "new test agent",
- "masterEncryption": false,
- "type": "agent_mysql",
- "host": null,
- "port": null,
- "username": null,
- "database": null,
- "schema": null,
- "sid": null,
- "createdAt": "2021-09-03T14:45:21.154Z",
- "updatedAt": "2021-09-03T14:45:21.154Z",
- "ssh": false,
- "sshHost": null,
- "sshPort": null,
- "sshUsername": null,
- "ssl": false,
- "cert": null,
- "isTestConnection": false
- },
- "accessLevel": "edit"
- },
- {
- "connection": {
- "id": "944b546a-5141-4c89-b0da-39bcc904ffea",
- "title": "Test connection to MSSQL",
- "masterEncryption": false,
- "type": "agent_mssql",
- "host": "U2FsdGVkX18Aqg8bUNwW/QQyadQRimuU6wSuerla/aM2+7902zH1PCNIuBYwnvKK88NNyjiuaxdXC44S5zApDabiqyG75Tj9jaxRntrKElU=",
- "port": 1433,
- "username": "U2FsdGVkX1/p7kOB3MpSmBvOlMcVaw2rwM1T/bd+b/c=",
- "database": "U2FsdGVkX18KzyNPZrNUi734AbAG/ON5ijxj4k3rC2A=",
- "schema": null,
- "sid": null,
- "createdAt": "2021-09-03T10:29:48.168Z",
- "updatedAt": "2021-09-03T14:50:26.085Z",
- "ssh": false,
- "sshHost": null,
- "sshPort": null,
- "sshUsername": null,
- "ssl": false,
- "cert": null,
- "isTestConnection": true
- },
- "accessLevel": "edit"
- },
- {
- "connection": {
- "id": "5f80922d-f4bf-4a91-a7d3-d3f38dfcaa4e",
- "title": "Test connection to OracleDB",
- "masterEncryption": false,
- "type": "agent_oracledb",
- "host": "U2FsdGVkX1/TdsnH5xIQaCvFXU8CpkJMKnSX1l+5JVQ6+WrFk83OeZ629tHLtVMG04Ht+H6kpstKZ01PrqZfBhM2OvLL2rw0bImen/TGFuw=",
- "port": 1521,
- "username": "U2FsdGVkX19oQClMIPyFNxEYeSPNLJIDpnYPSWKfyWU=",
- "database": "U2FsdGVkX19NJkB1M3ydah9qjZQZBcnnLU03T0Y7PeY=",
- "schema": null,
- "sid": "ORCL",
- "createdAt": "2021-09-03T10:29:48.150Z",
- "updatedAt": "2021-09-03T14:45:51.582Z",
- "ssh": false,
- "sshHost": null,
- "sshPort": null,
- "sshUsername": null,
- "ssl": false,
- "cert": null,
- "isTestConnection": true
- },
- "accessLevel": "edit"
- }
- ],
- "connectionsCount": 3
- };
-
- component.setConnections(fakeConnections);
- fixture.detectChanges();
-
- expect(component.connections).toEqual([
- {
- "connection": {
- "id": "9176a5d1-624f-48af-b5a2-f0a08e15252f",
- "title": "new test agent",
- "masterEncryption": false,
- "type": "agent_mysql",
- "host": null,
- "port": null,
- "username": null,
- "database": null,
- "schema": null,
- "sid": null,
- "createdAt": "2021-09-03T14:45:21.154Z",
- "updatedAt": "2021-09-03T14:45:21.154Z",
- "ssh": false,
- "sshHost": null,
- "sshPort": null,
- "sshUsername": null,
- "ssl": false,
- "cert": null,
- "isTestConnection": false
- },
- "accessLevel": "edit"
- }
- ] as any);
- expect(component.testConnections).toEqual([
- {
- "connection": {
- "id": "944b546a-5141-4c89-b0da-39bcc904ffea",
- "title": "Test connection to MSSQL",
- "masterEncryption": false,
- "type": "agent_mssql",
- "host": "U2FsdGVkX18Aqg8bUNwW/QQyadQRimuU6wSuerla/aM2+7902zH1PCNIuBYwnvKK88NNyjiuaxdXC44S5zApDabiqyG75Tj9jaxRntrKElU=",
- "port": 1433,
- "username": "U2FsdGVkX1/p7kOB3MpSmBvOlMcVaw2rwM1T/bd+b/c=",
- "database": "U2FsdGVkX18KzyNPZrNUi734AbAG/ON5ijxj4k3rC2A=",
- "schema": null,
- "sid": null,
- "createdAt": "2021-09-03T10:29:48.168Z",
- "updatedAt": "2021-09-03T14:50:26.085Z",
- "ssh": false,
- "sshHost": null,
- "sshPort": null,
- "sshUsername": null,
- "ssl": false,
- "cert": null,
- "isTestConnection": true
- },
- "accessLevel": "edit"
- },
- {
- "connection": {
- "id": "5f80922d-f4bf-4a91-a7d3-d3f38dfcaa4e",
- "title": "Test connection to OracleDB",
- "masterEncryption": false,
- "type": "agent_oracledb",
- "host": "U2FsdGVkX1/TdsnH5xIQaCvFXU8CpkJMKnSX1l+5JVQ6+WrFk83OeZ629tHLtVMG04Ht+H6kpstKZ01PrqZfBhM2OvLL2rw0bImen/TGFuw=",
- "port": 1521,
- "username": "U2FsdGVkX19oQClMIPyFNxEYeSPNLJIDpnYPSWKfyWU=",
- "database": "U2FsdGVkX19NJkB1M3ydah9qjZQZBcnnLU03T0Y7PeY=",
- "schema": null,
- "sid": "ORCL",
- "createdAt": "2021-09-03T10:29:48.150Z",
- "updatedAt": "2021-09-03T14:45:51.582Z",
- "ssh": false,
- "sshHost": null,
- "sshPort": null,
- "sshUsername": null,
- "ssl": false,
- "cert": null,
- "isTestConnection": true
- },
- "accessLevel": "edit"
- }
- ] as any);
- expect(component.titles).toEqual({
- "9176a5d1-624f-48af-b5a2-f0a08e15252f": "new test agent",
- "944b546a-5141-4c89-b0da-39bcc904ffea": "Test connection to MSSQL",
- "5f80922d-f4bf-4a91-a7d3-d3f38dfcaa4e": "Test connection to OracleDB"
- })
- });
-
- it('should get connection title if it is pointed', () => {
- const connection = {
- title: 'SQL connection'
- }
-
- const connectionTitle = component.getTitle(connection as any);
- expect(connectionTitle).toEqual('SQL connection');
- });
-
- it('should get db name as connection title if it is not pointed', () => {
- const connection = {
- database: 'testDB'
- }
-
- const connectionTitle = component.getTitle(connection as any);
- expect(connectionTitle).toEqual('testDB');
- });
-
- it('should get Untitled encrypted connection as connection title if it is not pointed and connection is encriped', () => {
- const connection = {
- database: 'testDB',
- masterEncryption: true
- }
-
- const connectionTitle = component.getTitle(connection as any);
- expect(connectionTitle).toEqual('Untitled encrypted connection');
- expect(connectionTitle).not.toEqual('testDB');
- });
});
diff --git a/frontend/src/app/components/connections-list/connections-list.component.ts b/frontend/src/app/components/connections-list/connections-list.component.ts
index 7493a3612..af77e2cfa 100644
--- a/frontend/src/app/components/connections-list/connections-list.component.ts
+++ b/frontend/src/app/components/connections-list/connections-list.component.ts
@@ -6,18 +6,18 @@ import { Angulartics2Module } from 'angulartics2';
import { CommonModule } from '@angular/common';
import { CompanyService } from 'src/app/services/company.service';
import { ConnectionsService } from 'src/app/services/connections.service';
+import { DemoConnectionsComponent } from './demo-connections/demo-connections.component';
import { MatButtonModule } from '@angular/material/button';
import { MatDialog } from '@angular/material/dialog';
import { MatDividerModule } from '@angular/material/divider';
import { MatIconModule } from '@angular/material/icon';
+import { OwnConnectionsComponent } from './own-connections/own-connections.component';
import { PlaceholderConnectionsComponent } from '../skeletons/placeholder-connections/placeholder-connections.component';
import { RouterModule } from '@angular/router';
import { Title } from '@angular/platform-browser';
import { User } from 'src/app/models/user';
import { UserService } from 'src/app/services/user.service';
import { take } from 'rxjs/operators';
-import { OwnConnectionsComponent } from './own-connections/own-connections.component';
-import { DemoConnectionsComponent } from './demo-connections/demo-connections.component';
@Component({
selector: 'app-connections-list',
@@ -38,15 +38,14 @@ import { DemoConnectionsComponent } from './demo-connections/demo-connections.co
})
export class ConnectionsListComponent implements OnInit {
- public connections: ConnectionItem[] = null;
- public testConnections: ConnectionItem[] = null;
+ public connections: Connection[] = null;
+ // public testConnections: Connection[] = null;
public titles: Object;
public displayedCardCount: number = 3;
public connectionsListCollapsed: boolean = true;
public companyName: string;
public currentUser: User;
-
constructor(
private _connectionsServise: ConnectionsService,
public deleteDialog: MatDialog,
@@ -59,6 +58,14 @@ export class ConnectionsListComponent implements OnInit {
return this._userService.isDemo;
}
+ get ownConnections() {
+ return this._connectionsServise.ownConnectionsList;
+ }
+
+ get testConnections() {
+ return this._connectionsServise.testConnectionsList;
+ }
+
ngOnInit(): void {
this._companyService.getCurrentTabTitle()
.pipe(take(1))
@@ -73,20 +80,5 @@ export class ConnectionsListComponent implements OnInit {
this.companyName = res.name;
})
});
- this._connectionsServise.fetchConnections()
- .subscribe((res: any) => {
- this.setConnections(res);
- })
- }
-
- setConnections(res) {
- this.connections = res.connections.filter(connectionItem => !connectionItem.connection.isTestConnection);
- this.testConnections = res.connections.filter(connectionItem => connectionItem.connection.isTestConnection);
- this.titles = Object.assign({}, ...res.connections.map((connectionItem) => ({[connectionItem.connection.id]: this.getTitle(connectionItem.connection)})));
- }
-
- getTitle(connection: Connection) {
- if (!connection.title && connection.masterEncryption) return 'Untitled encrypted connection'
- return connection.title || connection.database
}
}
diff --git a/frontend/src/app/components/connections-list/demo-connections/demo-connections.component.css b/frontend/src/app/components/connections-list/demo-connections/demo-connections.component.css
index fedf191a4..4ba6a028d 100644
--- a/frontend/src/app/components/connections-list/demo-connections/demo-connections.component.css
+++ b/frontend/src/app/components/connections-list/demo-connections/demo-connections.component.css
@@ -23,16 +23,15 @@
.testConnectionLink {
display: flex;
align-items: center;
- justify-content: space-between;
+ gap: 12px;
border-radius: 4px;
box-shadow:
0px 1px 3px 0px rgba(0, 0, 0, 0.2),
0px 2px 2px 0px rgba(0, 0, 0, 0.12),
0px 0px 2px 0px rgba(0, 0, 0, 0.14);
color: inherit;
- font-weight: 600;
height: 48px;
- padding: 0 16px;
+ padding: 0 12px;
text-decoration: none;
transition: box-shadow 200ms, background 200ms, border 200ms;
}
@@ -88,22 +87,20 @@
background: rgba(0, 0, 0, 0.16);
}
-.testConnectionLink__iconBox {
+.testConnectionLink__icon {
flex-shrink: 0;
- display: flex;
- align-items: center;
- justify-content: center;
- background-image: radial-gradient(#fff 1em, var(--color-accentedPalette-500) 1em);
- border-radius: 4px;
- height: 36px;
- margin-right: 12px;
- width: 36px;
+ height: 28px;
+ width: 28px;
}
-.testConnectionLink__icon {
- flex-shrink: 0;
- height: 20px;
- width: 20px;
+@media(prefers-color-scheme: dark) {
+ .testConnectionLink__icon {
+ filter: brightness(0) invert(1);
+ }
+}
+
+.connection__goIcon {
+ margin-left: auto;
}
@media (width <= 600px) {
@@ -115,4 +112,14 @@
.testConnectionLink:hover .connection__goIcon,
.connection:hover .connection__goIcon{
opacity: 1;
+}
+
+.testConnectionLink__info {
+ display: flex;
+ flex-direction: column;
+}
+
+.testConnectionLink__type {
+ font-size: 12px;
+ margin-top: -2px;
}
\ No newline at end of file
diff --git a/frontend/src/app/components/connections-list/demo-connections/demo-connections.component.html b/frontend/src/app/components/connections-list/demo-connections/demo-connections.component.html
index 07bd802a3..dfe3867d4 100644
--- a/frontend/src/app/components/connections-list/demo-connections/demo-connections.component.html
+++ b/frontend/src/app/components/connections-list/demo-connections/demo-connections.component.html
@@ -8,10 +8,14 @@
Try out a demo admin panel
angulartics2On="click"
angularticsAction="Connections: open test db is clicked"
[angularticsProperties]="{'dbType': testConnectionItem.connection.type}">
-
-
+
+
+ {{ testConnectionItem.displayTitle }}
+ {{ testDatabasesNames[testConnectionItem.connection.type] }}
- {{ testConnectionItem.connection.title }}
+
arrow_forward
diff --git a/frontend/src/app/components/connections-list/demo-connections/demo-connections.component.spec.ts b/frontend/src/app/components/connections-list/demo-connections/demo-connections.component.spec.ts
index b15e5029c..53d22a18f 100644
--- a/frontend/src/app/components/connections-list/demo-connections/demo-connections.component.spec.ts
+++ b/frontend/src/app/components/connections-list/demo-connections/demo-connections.component.spec.ts
@@ -1,23 +1,114 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { DemoConnectionsComponent } from './demo-connections.component';
+import { ConnectionItem, DBtype, ConnectionType } from 'src/app/models/connection';
+import { AccessLevel } from 'src/app/models/user';
+import { provideRouter } from '@angular/router';
+import { Angulartics2Module } from 'angulartics2';
describe('DemoConnectionsComponent', () => {
let component: DemoConnectionsComponent;
let fixture: ComponentFixture
;
+ const mockTestConnections: ConnectionItem[] = [
+ {
+ connection: {
+ id: '1',
+ title: 'MySQL Test DB',
+ type: DBtype.MySQL,
+ database: 'test_db',
+ host: 'localhost',
+ port: '3306',
+ username: 'root',
+ password: 'password',
+ schema: null,
+ sid: null,
+ ssl: false,
+ ssh: false,
+ connectionType: ConnectionType.Direct,
+ masterEncryption: false,
+ azure_encryption: false,
+ isTestConnection: true,
+ cert: ''
+ },
+ accessLevel: AccessLevel.None
+ },
+ {
+ connection: {
+ id: '2',
+ title: 'PostgreSQL Test DB',
+ type: DBtype.Postgres,
+ database: 'test_db',
+ host: 'localhost',
+ port: '5432',
+ username: 'postgres',
+ password: 'password',
+ schema: null,
+ sid: null,
+ ssl: false,
+ ssh: false,
+ connectionType: ConnectionType.Direct,
+ masterEncryption: false,
+ azure_encryption: false,
+ isTestConnection: true,
+ cert: ''
+ },
+ accessLevel: AccessLevel.None
+ }
+ ];
+
beforeEach(async () => {
await TestBed.configureTestingModule({
- imports: [DemoConnectionsComponent]
+ imports: [
+ Angulartics2Module.forRoot({}),
+ DemoConnectionsComponent
+ ],
+ providers: [provideRouter([])]
})
.compileComponents();
fixture = TestBed.createComponent(DemoConnectionsComponent);
component = fixture.componentInstance;
+ component.testConnections = mockTestConnections;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
+
+ it('should order test databases according to supportedOrderedDatabases', () => {
+ // Call the method directly
+ const orderedConnections = component.orderTestDatabases();
+
+ // Verify the result is an array
+ expect(Array.isArray(orderedConnections)).toBe(true);
+
+ // Verify the connections are in the right order
+ expect(orderedConnections.length).toBe(2);
+ expect(orderedConnections[0].connection.type).toBe(DBtype.MySQL);
+ expect(orderedConnections[1].connection.type).toBe(DBtype.Postgres);
+ });
+
+ it('should handle empty or null testConnections', () => {
+ // Set testConnections to null
+ component.testConnections = null;
+ fixture.detectChanges();
+
+ // Call the method
+ const result = component.orderTestDatabases();
+
+ // Verify it returns an empty array
+ expect(result).toEqual([]);
+
+ // Set testConnections to empty array
+ component.testConnections = [];
+ fixture.detectChanges();
+
+ // Call the method again
+ const resultForEmpty = component.orderTestDatabases();
+
+ // Verify it returns an empty array
+ expect(resultForEmpty).toEqual([]);
+ });
});
diff --git a/frontend/src/app/components/connections-list/demo-connections/demo-connections.component.ts b/frontend/src/app/components/connections-list/demo-connections/demo-connections.component.ts
index 7fb5e8540..250c65e57 100644
--- a/frontend/src/app/components/connections-list/demo-connections/demo-connections.component.ts
+++ b/frontend/src/app/components/connections-list/demo-connections/demo-connections.component.ts
@@ -1,9 +1,11 @@
+import { Component, Input, OnInit } from '@angular/core';
+import { supportedDatabasesTitles, supportedOrderedDatabases } from 'src/app/consts/databases';
+
+import { Angulartics2Module } from 'angulartics2';
import { CommonModule } from '@angular/common';
-import { Component, Input } from '@angular/core';
+import { ConnectionItem } from 'src/app/models/connection';
import { MatIconModule } from '@angular/material/icon';
import { RouterModule } from '@angular/router';
-import { Angulartics2Module } from 'angulartics2';
-import { ConnectionItem } from 'src/app/models/connection';
@Component({
selector: 'app-demo-connections',
@@ -16,7 +18,46 @@ import { ConnectionItem } from 'src/app/models/connection';
templateUrl: './demo-connections.component.html',
styleUrl: './demo-connections.component.css'
})
-export class DemoConnectionsComponent {
- @Input() testConnections: ConnectionItem[] = null;
+export class DemoConnectionsComponent implements OnInit {
+ @Input() testConnections: ConnectionItem[] = [];
@Input() isDemo: boolean = false;
+
+ public testDatabasesNames = supportedDatabasesTitles;
+
+ public testDatabasesIcons = {
+ mysql: "/assets/icons/test-connections-icons/diversity_2.svg",
+ postgres: "/assets/icons/test-connections-icons/set_meal.svg",
+ mongodb: "/assets/icons/test-connections-icons/cinematic_blur.svg",
+ dynamodb: "/assets/icons/test-connections-icons/box.svg",
+ oracledb: "/assets/icons/test-connections-icons/shopping_bag_speed.svg",
+ mssql: "/assets/icons/test-connections-icons/add_shopping_cart.svg",
+ }
+
+ ngOnInit() {
+ if (this.testConnections && this.testConnections.length > 0) {
+ this.testConnections = this.orderTestDatabases();
+ }
+ }
+
+ orderTestDatabases() {
+ if (!this.testConnections || !Array.isArray(this.testConnections) || this.testConnections.length === 0) {
+ return [];
+ }
+
+ const orderMap = new Map(supportedOrderedDatabases.map((db, index) => [db, index]));
+
+ return [...this.testConnections].sort((a, b) => {
+ const typeA = a.connection?.type;
+ const typeB = b.connection?.type;
+
+ if (!typeA || !typeB) {
+ return 0;
+ }
+
+ const indexA = orderMap.has(typeA) ? orderMap.get(typeA) : Infinity;
+ const indexB = orderMap.has(typeB) ? orderMap.get(typeB) : Infinity;
+
+ return indexA - indexB;
+ });
+}
}
diff --git a/frontend/src/app/components/connections-list/own-connections/own-connections.component.css b/frontend/src/app/components/connections-list/own-connections/own-connections.component.css
index 8d74ad32b..c048ddb25 100644
--- a/frontend/src/app/components/connections-list/own-connections/own-connections.component.css
+++ b/frontend/src/app/components/connections-list/own-connections/own-connections.component.css
@@ -9,21 +9,100 @@
display: flex;
flex-direction: column;
align-items: center;
+ width: 100%;
}
.empty-state_bottom {
margin-top: auto;
}
+@media (prefers-color-scheme: light) {
+ .empty-state_bottom {
+ color: rgba(0, 0, 0, 0.64)
+ }
+}
+
+@media (prefers-color-scheme: dark) {
+ .empty-state_bottom {
+ color: rgba(255, 255, 255, 0.64)
+ }
+}
+
.empty-state__text {
font-size: 12px !important;
font-weight: 500 !important;
- margin-top: 56px !important;
margin-bottom: 0 !important;
text-align: center;
text-transform: uppercase;
}
+.supportedDatabases {
+ list-style: none;
+ display: grid;
+ grid-template-columns: repeat(5, minmax(0, 1fr));
+ grid-gap: 20px;
+ justify-items: center;
+ margin-top: 24px;
+}
+
+.addConnectionLink {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ border-radius: 4px;
+ box-shadow:
+ 0px 1px 3px 0px rgba(0, 0, 0, 0.2),
+ 0px 2px 2px 0px rgba(0, 0, 0, 0.12),
+ 0px 0px 2px 0px rgba(0, 0, 0, 0.14);
+ color: inherit;
+ font-weight: 600;
+ height: 48px;
+ padding: 0 6px;
+ text-decoration: none;
+ transition: box-shadow 200ms, background 200ms, border 200ms;
+ min-width: 154px;
+}
+
+.addConnectionLink:hover {
+ box-shadow:
+ 0px 1px 5px 0px rgba(0, 0, 0, 0.2),
+ 0px 3px 4px 0px rgba(0, 0, 0, 0.12),
+ 0px 2px 4px 0px rgba(0, 0, 0, 0.14);
+}
+
+@media (prefers-color-scheme: dark) {
+ .addConnectionLink {
+ background: #404040;
+ border: 1px solid #404040;
+ }
+
+ .addConnectionLink:hover {
+ background: #212121;
+ border: 1px solid rgba(255, 255, 255, 0.75);
+ box-shadow:
+ 0px 1px 3px 0px rgba(255, 255, 255, 0.1),
+ 0px 2px 2px 0px rgba(255, 255, 255, 0.08),
+ 0px 0px 2px 0px rgba(255, 255, 255, 0.12);
+ }
+}
+
+.addConnectionLink__iconBox {
+ flex-shrink: 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background-color: #fff;
+ border-radius: 4px;
+ height: 36px;
+ width: 36px;
+}
+
+.addConnectionLink__icon {
+ flex-shrink: 0;
+ height: 20px;
+ width: 20px;
+}
+
.showAllButton {
margin-top: 20px;
margin-bottom: -56px;
@@ -66,6 +145,12 @@
width: 140px;
}
+@media (prefers-color-scheme: dark) {
+ .zapier-link {
+ background: #212121;
+ }
+}
+
.zapier-link__caption {
font-size: 12px;
}
@@ -120,6 +205,7 @@
.connectionItem {
flex: 0 0 calc((100% - 40px)/3);
+ max-width: calc((100% - 40px)/3);
}
@media (width <= 600px) {
@@ -134,8 +220,7 @@
border: 1px solid rgba(0, 0, 0, 0.12);
border-radius: 4px;
color: inherit;
- height: 148px;
- padding: 20px 12px;
+ padding: 12px;
text-decoration: none;
width: 100%;
transition: border 200ms, box-shadow 200ms;
@@ -165,39 +250,30 @@
.connectionLogoPreview {
flex-shrink: 0;
display: flex;
- /* flex-direction: column; */
- /* align-items: flex-start; */
align-items: center;
- /* justify-content: center; */
- gap: 4px;
+ gap: 12px;
background-color: var(--color-primaryPalette-500);
border-radius: 2px;
color: #fff;
font-size: 20px;
font-weight: 900;
- height: 52px;
- margin-bottom: 4px;
+ height: 72px;
padding: 8px;
}
.connectionLogoPreview__logo {
- height: 100%;
+ height: 85%;
object-fit: contain;
}
-.connectionLogoPreview .connectionLogoPreview__name {
- margin-bottom: 0;
- font-size: 20px;
-}
-
.connectionInfo {
- display: grid;
- grid-template-columns: auto 40px;
- align-items: center;
+ display: flex;
+ flex-direction: column;
}
.connectionInfo .connectionInfo__connectionTitle {
- margin-bottom: 0;
+ margin-top: -4px;
+ margin-bottom: -2px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
diff --git a/frontend/src/app/components/connections-list/own-connections/own-connections.component.html b/frontend/src/app/components/connections-list/own-connections/own-connections.component.html
index 429b39091..560e80c2e 100644
--- a/frontend/src/app/components/connections-list/own-connections/own-connections.component.html
+++ b/frontend/src/app/components/connections-list/own-connections/own-connections.component.html
@@ -1,129 +1,22 @@
Create you own test connection
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
Create your first connection
-
+
+
-
{{ connectionItem.connection.title }
angularticsAction="Connections: Add connection button is clicked">
add
Add database
-
+-->
- Invited to the company and don't see admin panel?
+ Invited to a company but don't see your admin panel?
-
- Request access to admin panel from your Acount owner.
+
+ Request access from your Account Owner
diff --git a/frontend/src/app/components/connections-list/own-connections/own-connections.component.ts b/frontend/src/app/components/connections-list/own-connections/own-connections.component.ts
index 1adeaf9dd..a139e4776 100644
--- a/frontend/src/app/components/connections-list/own-connections/own-connections.component.ts
+++ b/frontend/src/app/components/connections-list/own-connections/own-connections.component.ts
@@ -1,12 +1,14 @@
-import { CommonModule } from '@angular/common';
import { Component, Input } from '@angular/core';
+import { supportedDatabasesTitles, supportedOrderedDatabases } from 'src/app/consts/databases';
+
+import { CommonModule } from '@angular/common';
+import { ConnectionItem } from 'src/app/models/connection';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { RouterModule } from '@angular/router';
-import { User } from '@sentry/angular-ivy';
-import { ConnectionItem } from 'src/app/models/connection';
import { UiSettings } from 'src/app/models/ui-settings';
import { UiSettingsService } from 'src/app/services/ui-settings.service';
+import { User } from '@sentry/angular-ivy';
@Component({
selector: 'app-own-connections',
@@ -26,6 +28,8 @@ export class OwnConnectionsComponent {
public displayedCardCount: number = 3;
public connectionsListCollapsed: boolean;
+ public supportedDatabasesTitles = supportedDatabasesTitles;
+ public supportedOrderedDatabases = supportedOrderedDatabases;
constructor(private _uiSettings: UiSettingsService) {}
diff --git a/frontend/src/app/consts/databases.ts b/frontend/src/app/consts/databases.ts
new file mode 100644
index 000000000..a7c017b50
--- /dev/null
+++ b/frontend/src/app/consts/databases.ts
@@ -0,0 +1,21 @@
+export const supportedOrderedDatabases = [
+ "mysql",
+ "postgres",
+ "mongodb",
+ "dynamodb",
+ "cassandra",
+ "oracledb",
+ "mssql",
+ "ibmdb2"
+]
+
+export const supportedDatabasesTitles = {
+ mysql: "MySQL",
+ postgres: "PostgreSQL",
+ mongodb: "MongoDB",
+ dynamodb: "DynamoDB",
+ cassandra: "Cassandra",
+ oracledb: "OracleDB",
+ mssql: "MSSQL",
+ ibmdb2: "IBM DB2"
+ }
\ No newline at end of file
diff --git a/frontend/src/app/services/connections.service.spec.ts b/frontend/src/app/services/connections.service.spec.ts
index 6d731e2ab..639f78102 100644
--- a/frontend/src/app/services/connections.service.spec.ts
+++ b/frontend/src/app/services/connections.service.spec.ts
@@ -174,7 +174,7 @@ describe('ConnectionsService', () => {
})
it('should define a type of connections without agent_ prefix', () => {
- const connection = service.defineConnecrionType(connectionCredsNetwork);
+ const connection = service.defineConnectionType(connectionCredsNetwork);
expect(connection).toEqual({
"title": "Test connection via SSH tunnel to mySQL",
@@ -200,7 +200,7 @@ describe('ConnectionsService', () => {
})
it('should define a type of connections with agent_ prefix', () => {
- const connection = service.defineConnecrionType({
+ const connection = service.defineConnectionType({
"title": "Test connection via SSH tunnel to mySQL",
"masterEncryption": false,
"type": "agent_mysql",
@@ -287,7 +287,8 @@ describe('ConnectionsService', () => {
"cert": null,
"isTestConnection": true
},
- "accessLevel": "edit"
+ "accessLevel": "edit",
+ "displayTitle": "Test connection to OracleDB"
},
{
"connection": {
@@ -311,14 +312,15 @@ describe('ConnectionsService', () => {
"cert": null,
"isTestConnection": true
},
- "accessLevel": "readonly"
+ "accessLevel": "readonly",
+ "displayTitle": "Test connection via SSH tunnel to mySQL"
}
],
"connectionsCount": 2
}
service.fetchConnections().subscribe(connectionData => {
- expect(connectionData).toEqual(connectionsList);
+ expect(connectionData).toEqual(connectionsList.connections);
isSubscribeCalled = true;
});
diff --git a/frontend/src/app/services/connections.service.ts b/frontend/src/app/services/connections.service.ts
index 99eac8028..d585fabfd 100644
--- a/frontend/src/app/services/connections.service.ts
+++ b/frontend/src/app/services/connections.service.ts
@@ -58,9 +58,14 @@ export class ConnectionsService {
public companyName: string;
public isCustomAccentedColor: boolean;
public defaultDisplayTable: string;
+ public ownConnections: Connection[] = null;
+ public testConnections: Connection[] = null;
private connectionNameSubject: BehaviorSubject
= new BehaviorSubject('Rocketadmin');
private connectionSigningKeySubject: BehaviorSubject = new BehaviorSubject(null);
+ private connectionsSubject: BehaviorSubject = new BehaviorSubject([]);
+
+ public cast = this.connectionsSubject.asObservable();
constructor(
private _http: HttpClient,
@@ -95,6 +100,10 @@ export class ConnectionsService {
return this.connectionID;
}
+ get currentConnectionName() {
+ return this.defineConnectionTitle(this.connection);
+ }
+
get logo() {
return this.connectionLogo;
}
@@ -130,6 +139,14 @@ export class ConnectionsService {
return tabs;
}
+ get ownConnectionsList() {
+ return this.ownConnections;
+ }
+
+ get testConnectionsList() {
+ return this.testConnections;
+ }
+
getCurrentConnectionTitle() {
return this.connectionNameSubject.asObservable();
}
@@ -178,7 +195,7 @@ export class ConnectionsService {
return accessLevel === 'edit' || accessLevel === 'readonly'
}
- defineConnecrionType(connection) {
+ defineConnectionType(connection) {
if (connection.type && connection.type.startsWith('agent_')) {
connection.type = connection.type.slice(6);
connection.connectionType = ConnectionType.Agent;
@@ -188,15 +205,25 @@ export class ConnectionsService {
return connection;
}
+ defineConnectionTitle(connection: Connection) {
+ if (!connection.title && connection.masterEncryption) return 'Untitled encrypted connection';
+ if (!connection.title && !connection.database) return 'Untitled connection';
+ return connection.title || connection.database;
+ }
+
fetchConnections() {
return this._http.get('/connections')
.pipe(
map(res => {
const connections = res.connections.map(connectionItem => {
- const connection = this.defineConnecrionType(connectionItem.connection);
- return {...connectionItem, connection};
- })
- return {... res, connections};
+ const connection = this.defineConnectionType(connectionItem.connection);
+ const displayTitle = this.defineConnectionTitle(connectionItem.connection);
+ console.log('displayTitle', displayTitle);
+ return {...connectionItem, connection, displayTitle};
+ });
+ this.ownConnections = connections.filter(connectionItem => !connectionItem.connection.isTestConnection);
+ this.testConnections = connections.filter(connectionItem => connectionItem.connection.isTestConnection);
+ return connections;
}),
catchError((err) => {
console.log(err);
@@ -218,7 +245,7 @@ export class ConnectionsService {
return this._http.get(`/connection/one/${id}`)
.pipe(
map(res => {
- const connection = this.defineConnecrionType(res.connection);
+ const connection = this.defineConnectionType(res.connection);
if (res.connectionProperties) {
this.connectionLogo = res.connectionProperties.logo_url;
this.companyName = res.connectionProperties.company_name;
@@ -287,6 +314,7 @@ export class ConnectionsService {
})
.pipe(
map((res: any) => {
+ this.connectionsSubject.next(null);
this._masterPassword.checkMasterPassword(connection.masterEncryption, res.id, masterKey);
this._notifications.showSuccessSnackbar('Connection was added successfully.');
return res;
@@ -323,6 +351,7 @@ export class ConnectionsService {
map(res => {
this._masterPassword.checkMasterPassword(connection.masterEncryption, connection.id, masterKey);
this._notifications.showSuccessSnackbar('Connection has been updated successfully.');
+ this.connectionsSubject.next(null);
return res;
}),
catchError((err) => {
@@ -348,6 +377,7 @@ export class ConnectionsService {
return this._http.put(`/connection/delete/${id}`, metadata)
.pipe(
map(() => {
+ this.connectionsSubject.next(null);
this._notifications.showSuccessSnackbar('Connection has been deleted successfully.');
}),
catchError((err) => {
diff --git a/frontend/src/assets/icons/db2.svg b/frontend/src/assets/icons/db-logos/db2_logo.svg
similarity index 99%
rename from frontend/src/assets/icons/db2.svg
rename to frontend/src/assets/icons/db-logos/db2_logo.svg
index 950f0a73e..27df40743 100644
--- a/frontend/src/assets/icons/db2.svg
+++ b/frontend/src/assets/icons/db-logos/db2_logo.svg
@@ -633,7 +633,7 @@
style="fill:#00992c" />
\ No newline at end of file
diff --git a/frontend/src/assets/icons/test-connections-icons/add_shopping_cart.svg b/frontend/src/assets/icons/test-connections-icons/add_shopping_cart.svg
new file mode 100644
index 000000000..f53da102b
--- /dev/null
+++ b/frontend/src/assets/icons/test-connections-icons/add_shopping_cart.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/src/assets/icons/test-connections-icons/box.svg b/frontend/src/assets/icons/test-connections-icons/box.svg
new file mode 100644
index 000000000..3f789a585
--- /dev/null
+++ b/frontend/src/assets/icons/test-connections-icons/box.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/src/assets/icons/test-connections-icons/cinematic_blur.svg b/frontend/src/assets/icons/test-connections-icons/cinematic_blur.svg
new file mode 100644
index 000000000..2a8c780cd
--- /dev/null
+++ b/frontend/src/assets/icons/test-connections-icons/cinematic_blur.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/src/assets/icons/test-connections-icons/diversity_2.svg b/frontend/src/assets/icons/test-connections-icons/diversity_2.svg
new file mode 100644
index 000000000..4de9956b6
--- /dev/null
+++ b/frontend/src/assets/icons/test-connections-icons/diversity_2.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/src/assets/icons/test-connections-icons/set_meal.svg b/frontend/src/assets/icons/test-connections-icons/set_meal.svg
new file mode 100644
index 000000000..187edd2a2
--- /dev/null
+++ b/frontend/src/assets/icons/test-connections-icons/set_meal.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/src/assets/icons/test-connections-icons/shopping_bag_speed.svg b/frontend/src/assets/icons/test-connections-icons/shopping_bag_speed.svg
new file mode 100644
index 000000000..ad11660cc
--- /dev/null
+++ b/frontend/src/assets/icons/test-connections-icons/shopping_bag_speed.svg
@@ -0,0 +1 @@
+
\ No newline at end of file