diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts index 4430a0b03..6a03cf3a2 100644 --- a/frontend/src/app/app-routing.module.ts +++ b/frontend/src/app/app-routing.module.ts @@ -160,6 +160,15 @@ const routes: Routes = [ loadComponent: () => import('./components/connect-db/connect-db.component').then((m) => m.ConnectDBComponent), canActivate: [AuthGuard], }, + { + path: 'edit-database-schema/:connection-id', + loadComponent: () => + import('./components/edit-database-schema/edit-database-schema.component').then( + (m) => m.EditDatabaseSchemaComponent, + ), + canActivate: [AuthGuard], + title: 'Edit Database Schema | Rocketadmin', + }, { path: 'connection-settings/:connection-id', loadComponent: () => 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 ed3b1a23f..2638a5434 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 @@ -320,6 +320,8 @@ .connectionInfo { display: flex; flex-direction: column; + min-width: 0; + flex: 1; } .connectionInfo .connectionInfo__connectionTitle { @@ -331,6 +333,18 @@ width: 100%; } +/* ── Schema button inside card ── */ + +.connectionSchemaButton { + margin-left: auto; + flex-shrink: 0; + color: rgba(255, 255, 255, 0.7); +} + +.connectionSchemaButton:hover { + color: #fff; +} + /* ── Show more / less ── */ .showAllButton { 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 6a16db4a8..e446491f0 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 @@ -30,6 +30,15 @@

Create your first connection

{{ $any(connectionItem).displayTitle }}

{{ supportedDatabasesTitles[connectionItem.connection.type] }} + @if (connectionItem.accessLevel === 'edit') { + + schema + + } 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 c098ffffc..93ed11313 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 @@ -3,6 +3,7 @@ import { Component, Input, OnChanges, OnInit, SimpleChanges, signal } from '@ang import { MatButtonModule } from '@angular/material/button'; import { MatDialog } from '@angular/material/dialog'; import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; import { Router, RouterModule } from '@angular/router'; import posthog from 'posthog-js'; import { firstValueFrom } from 'rxjs'; @@ -33,7 +34,7 @@ import { @Component({ selector: 'app-own-connections', - imports: [CommonModule, RouterModule, MatIconModule, MatButtonModule], + imports: [CommonModule, RouterModule, MatIconModule, MatButtonModule, MatTooltipModule], templateUrl: './own-connections.component.html', styleUrl: './own-connections.component.css', }) @@ -240,11 +241,15 @@ export class OwnConnectionsComponent implements OnInit, OnChanges { } private _openRenameDialog(data: HostedDatabaseRenameDialogData): void { - this._dialog.open(HostedDatabaseRenameDialogComponent, { + const dialogRef = this._dialog.open(HostedDatabaseRenameDialogComponent, { width: '28em', maxWidth: '95vw', data, }); + + dialogRef.afterClosed().subscribe(() => { + this._router.navigate(['/dashboard', data.connectionId]); + }); } private _getErrorMessage(error: unknown): string { diff --git a/frontend/src/app/components/dashboard/dashboard.component.css b/frontend/src/app/components/dashboard/dashboard.component.css index 082580985..85b80f884 100644 --- a/frontend/src/app/components/dashboard/dashboard.component.css +++ b/frontend/src/app/components/dashboard/dashboard.component.css @@ -315,31 +315,3 @@ display: none !important; } -.schema-editor-panel { - position: fixed; - bottom: 0; - left: 0; - right: 0; - height: 0; - background: var(--mat-sidenav-content-background-color); - border-top: 1px solid rgba(0, 0, 0, 0.12); - box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.12); - overflow: hidden; - transition: height 0.3s ease; - z-index: 100; -} - -.schema-editor-panel--open { - height: 380px; -} - -.table-preview-content--panel-open { - padding-bottom: 380px; -} - -@media (prefers-color-scheme: dark) { - .schema-editor-panel { - border-top-color: rgba(255, 255, 255, 0.12); - box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.4); - } -} diff --git a/frontend/src/app/components/dashboard/dashboard.component.html b/frontend/src/app/components/dashboard/dashboard.component.html index 1db0ed844..ce14e4441 100644 --- a/frontend/src/app/components/dashboard/dashboard.component.html +++ b/frontend/src/app/components/dashboard/dashboard.component.html @@ -21,12 +21,12 @@ - - + @@ -87,12 +87,11 @@ [connectionID]="connectionID" [selectedTable]="selectedTableName" [uiSettings]="uiSettings" - (expandSidebar)="toggleSideBar()" - (editStructure)="onEditStructure()"> + (expandSidebar)="toggleSideBar()"> -
+
@@ -129,24 +128,14 @@ (applyFilter)="applyFilter($event)">
- - -
- - -
diff --git a/frontend/src/app/components/dashboard/dashboard.component.ts b/frontend/src/app/components/dashboard/dashboard.component.ts index cb63df8f9..0523da15a 100644 --- a/frontend/src/app/components/dashboard/dashboard.component.ts +++ b/frontend/src/app/components/dashboard/dashboard.component.ts @@ -37,7 +37,7 @@ import { DbTableFiltersDialogComponent } from './db-table-view/db-table-filters- import { DbTableRowViewComponent } from './db-table-view/db-table-row-view/db-table-row-view.component'; import { DbTableViewComponent } from './db-table-view/db-table-view.component'; import { TablesDataSource } from './db-tables-data-source'; -import { DbGenerateSchemaComponent } from './db-generate-schema/db-generate-schema.component'; +import { EditDatabaseSchemaComponent } from '../edit-database-schema/edit-database-schema.component'; import { DbTablesListComponent } from './db-tables-list/db-tables-list.component'; interface DataToActivateActions { @@ -56,7 +56,7 @@ interface DataToActivateActions { MatIconModule, MatDialogModule, MatSidenavModule, - DbGenerateSchemaComponent, + EditDatabaseSchemaComponent, DbTablesListComponent, DbTableViewComponent, DbTableAiPanelComponent, @@ -103,7 +103,6 @@ export class DashboardComponent implements OnInit, OnDestroy { public uiSettings: ConnectionSettingsUI; public tableFolders: any[] = []; public isConfiguring: boolean = false; - public showSchemaEditor: boolean = false; constructor( private _connections: ConnectionsService, @@ -451,14 +450,9 @@ export class DashboardComponent implements OnInit, OnDestroy { this._uiSettings.updateConnectionSetting(this.connectionID, 'shownTableTitles', this.shownTableTitles); } - onEditStructure() { - this.showSchemaEditor = true; - } - onSchemaApplied() { setTimeout(() => { this.noTablesError = false; - this.showSchemaEditor = false; this.loading = true; this.getData(); }, 1500); diff --git a/frontend/src/app/components/dashboard/db-tables-list/db-tables-list.component.css b/frontend/src/app/components/dashboard/db-tables-list/db-tables-list.component.css index d96a7a8ff..c0d0821fe 100644 --- a/frontend/src/app/components/dashboard/db-tables-list/db-tables-list.component.css +++ b/frontend/src/app/components/dashboard/db-tables-list/db-tables-list.component.css @@ -445,7 +445,7 @@ .expanded-container.has-custom-folders .add-folder-button-container { order: 4; /* After folders section */ position: sticky; - bottom: 40px; + bottom: 0; background-color: #ffffff; padding: 8px 16px; z-index: 10; @@ -459,50 +459,6 @@ } } -/* Edit structure button container */ -.edit-structure-button-container { - order: 5; /* Always at the very bottom */ - position: sticky; - bottom: 0; - background-color: #ffffff; - padding: 8px 16px; - z-index: 10; - margin-left: 16px; - margin-right: 16px; - margin-top: 4px; - margin-bottom: 8px; - width: calc(100% - 32px); - box-sizing: border-box; -} - -.expanded-container.has-custom-folders .edit-structure-button-container { - padding: 0 16px 8px; - margin-top: 0; - margin-left: 0; - margin-right: 0; - width: 100%; -} - -.edit-structure-button { - width: 100%; -} - -.edit-structure-button mat-icon { - font-size: 18px; - width: 18px; - height: 18px; -} - -@media (prefers-color-scheme: dark) { - .edit-structure-button-container { - background-color: #303030; - } - - .expanded-container.has-custom-folders .edit-structure-button-container { - background-color: #303030; - } -} - .search-input ::ng-deep * { background-color: transparent !important; } diff --git a/frontend/src/app/components/dashboard/db-tables-list/db-tables-list.component.html b/frontend/src/app/components/dashboard/db-tables-list/db-tables-list.component.html index b5b5a6c4d..c9270f948 100644 --- a/frontend/src/app/components/dashboard/db-tables-list/db-tables-list.component.html +++ b/frontend/src/app/components/dashboard/db-tables-list/db-tables-list.component.html @@ -61,13 +61,6 @@
- -
- construction -
- -
- -
-
diff --git a/frontend/src/app/components/dashboard/db-tables-list/db-tables-list.component.ts b/frontend/src/app/components/dashboard/db-tables-list/db-tables-list.component.ts index 2a34b892c..214853121 100644 --- a/frontend/src/app/components/dashboard/db-tables-list/db-tables-list.component.ts +++ b/frontend/src/app/components/dashboard/db-tables-list/db-tables-list.component.ts @@ -75,7 +75,6 @@ export class DbTablesListComponent implements OnInit, OnChanges { @Input() uiSettings: any; @Output() expandSidebar = new EventEmitter(); - @Output() editStructure = new EventEmitter(); private _connections = inject(ConnectionsService); protected canEditConnection = () => this._connections.canEditConnection(); diff --git a/frontend/src/app/components/dashboard/db-generate-schema/db-generate-schema.component.css b/frontend/src/app/components/edit-database-schema/edit-database-schema.component.css similarity index 76% rename from frontend/src/app/components/dashboard/db-generate-schema/db-generate-schema.component.css rename to frontend/src/app/components/edit-database-schema/edit-database-schema.component.css index 344a74b11..5241f9fa6 100644 --- a/frontend/src/app/components/dashboard/db-generate-schema/db-generate-schema.component.css +++ b/frontend/src/app/components/edit-database-schema/edit-database-schema.component.css @@ -1,6 +1,6 @@ :host { display: flex; - height: 100%; + height: calc(100vh - 44px); } .schema-chat { @@ -13,6 +13,36 @@ position: relative; } +.schema-chat--routed { + max-width: 860px; + margin: 0 auto; + padding: 0 16px; + height: calc(100vh - var(--mat-toolbar-standard-height)); +} + +/* ── Header (routed page) ── */ + +.schema-chat__header { + display: flex; + align-items: center; + gap: 8px; + padding: var(--top-margin) 0 16px; + flex-shrink: 0; + width: 100%; +} + +.schema-chat__back-button { + flex-shrink: 0; +} + +.schema-chat__title { + font-size: 20px; + font-weight: 600; + margin: 0 !important; +} + +/* ── Close button (embedded panel) ── */ + .schema-chat__close-button { position: absolute; top: 8px; @@ -27,13 +57,16 @@ flex-direction: column; align-items: center; justify-content: center; - flex: 1; + flex: 1 1 0; gap: 16px; padding: 24px; max-width: 500px; margin: 0 auto; + min-height: 0; + overflow-y: auto; } + .schema-chat__welcome-icon { width: 48px !important; height: 48px !important; @@ -188,8 +221,6 @@ flex-direction: column; gap: 10px; margin-top: 12px; - max-height: 400px; - overflow-y: auto; } .schema-chat__change-card { @@ -246,25 +277,16 @@ } } -.schema-chat__rollback { - margin-top: 6px; -} - -.schema-chat__rollback summary { - cursor: pointer; - font-size: 12px; - opacity: 0.6; - margin-bottom: 4px; -} - .schema-chat__actions { display: flex; justify-content: flex-end; gap: 10px; + margin-top: 16px; } .schema-chat__actions button mat-icon { margin-right: 4px; + margin-bottom: -4px; font-size: 18px; height: 18px; width: 18px; @@ -307,12 +329,93 @@ 30% { transform: translateY(-8px); } } +/* Diagram */ + +.schema-chat__diagram-loading { + display: flex; + align-items: center; + justify-content: center; + gap: 8px; + padding: 16px 0; +} + +.schema-chat__diagram { + width: 100%; + padding: 0 0 12px; +} + +.schema-chat__diagram-header { + display: flex; + align-items: center; + justify-content: space-between; + margin: 16px 0 8px; +} + +.schema-chat__diagram-title { + font-size: 16px; + font-weight: 600; + margin: 0; +} + +.schema-chat__diagram-zoom { + display: flex; + align-items: center; + gap: 2px; +} + +.schema-chat__diagram-zoom-label { + font-size: 12px; + min-width: 40px; + text-align: center; + color: rgba(0, 0, 0, 0.6); +} + +@media (prefers-color-scheme: dark) { + .schema-chat__diagram-zoom-label { + color: rgba(255, 255, 255, 0.6); + } +} + +.schema-chat__diagram-content { + border: 1px solid rgba(0, 0, 0, 0.12); + border-radius: 8px; + padding: 16px; + overflow: auto; + background: rgba(0, 0, 0, 0.02); + max-height: 400px; +} + +.schema-chat__diagram-inner { + transition: transform 0.2s ease; +} + +@media (prefers-color-scheme: dark) { + .schema-chat__diagram-content { + border-color: rgba(255, 255, 255, 0.12); + background: rgba(255, 255, 255, 0.04); + } +} + +.schema-chat__open-tables { + display: flex; + justify-content: center; + padding: 8px 16px 32px; +} + +.schema-chat__open-tables button mat-icon { + margin-right: 4px; + margin-bottom: -4px; + font-size: 18px; + height: 18px; + width: 18px; +} + /* Input form */ .schema-chat__form { width: 100%; max-width: 700px; - padding: 0 16px 16px; + padding: 0 16px 32px; flex-shrink: 0; } diff --git a/frontend/src/app/components/dashboard/db-generate-schema/db-generate-schema.component.html b/frontend/src/app/components/edit-database-schema/edit-database-schema.component.html similarity index 62% rename from frontend/src/app/components/dashboard/db-generate-schema/db-generate-schema.component.html rename to frontend/src/app/components/edit-database-schema/edit-database-schema.component.html index 5a85af2bf..61e30196a 100644 --- a/frontend/src/app/components/dashboard/db-generate-schema/db-generate-schema.component.html +++ b/frontend/src/app/components/edit-database-schema/edit-database-schema.component.html @@ -1,14 +1,22 @@ -
+
+ @if (isRoutedPage()) { +
+ + arrow_back + +

Edit Database Schema

+
+ } @if (showClose) { } - @if (messages().length === 0) { + @if (messages().length === 0 && !initialDiagramLoading()) {
- @if (showClose) { + @if (showClose || isRoutedPage()) {

Edit database structure with AI

Describe the changes you want to make and AI will generate the SQL for you.

} @else { @@ -17,7 +25,7 @@ }
- @if (showClose) { + @if (showClose || isRoutedPage()) {
} + + @if (messages().length === 0 && initialDiagramLoading()) { +
+ Loading diagram +
+ + + +
+
+ } + @if (messages().length) {
@@ -70,18 +90,37 @@ {{ change.targetTableName }}
{{ change.forwardSql }}
- @if (change.rollbackSql) { -
- Rollback SQL -
{{ change.rollbackSql }}
-
- }
}
}
} + @if (message.role === 'diagram') { +
+
+

{{ message.text }}

+
+ + {{ (diagramZoom() * 100).toFixed(0) }}% + + +
+
+
+
+ +
+
+
+ } @if (message.role === 'error') {
error_outline @@ -100,6 +139,27 @@
} + @if (initialDiagramLoading() && messages().length > 0) { +
+ Loading diagram +
+ + + +
+
+ } +
+ } + + @if (applied() && !initialDiagramLoading()) { + } @@ -125,7 +185,7 @@ } @else {
- {{showClose ? 'Describe the changes you need...' : 'Describe the database you need...'}} + {{showClose || isRoutedPage() ? 'Describe the changes you need...' : 'Describe the database you need...'}}