diff --git a/frontend/src/app/components/dashboard/dashboard.component.html b/frontend/src/app/components/dashboard/dashboard.component.html index a90321bf9..27a029e73 100644 --- a/frontend/src/app/components/dashboard/dashboard.component.html +++ b/frontend/src/app/components/dashboard/dashboard.component.html @@ -93,11 +93,6 @@

Rocketadmin can not find any tables

Preview

- - Preview

-
- {{column.normalizedTitle}} - - {{getForeignKeyValue(column.title)}} - - -
-
- Image + +
+ {{column.normalizedTitle}} + + {{getForeignKeyValue(column.title)}} + + +
+
+ Image +
+ {{selectedRow.record[column.title] || '—'}}
- {{selectedRow.record[column.title] || '—'}} -
- - {{selectedRow.record[column.title] || '—'}} + + {{selectedRow.record[column.title] || '—'}} + - +
+ -
+ + +
diff --git a/frontend/src/app/components/dashboard/db-table-row-view/db-table-row-view.component.ts b/frontend/src/app/components/dashboard/db-table-row-view/db-table-row-view.component.ts index 789e78b3f..9b05366e3 100644 --- a/frontend/src/app/components/dashboard/db-table-row-view/db-table-row-view.component.ts +++ b/frontend/src/app/components/dashboard/db-table-row-view/db-table-row-view.component.ts @@ -6,9 +6,11 @@ import { ClipboardModule } from '@angular/cdk/clipboard'; import { CommonModule } from '@angular/common'; import { MatButtonModule } from '@angular/material/button'; import { MatIconModule } from '@angular/material/icon'; +import { MatTooltipModule } from '@angular/material/tooltip'; import { NotificationsService } from 'src/app/services/notifications.service'; import { TableStateService } from 'src/app/services/table-state.service'; -import { MatTooltipModule } from '@angular/material/tooltip'; +import { normalizeFieldName } from 'src/app/lib/normalize'; +import { PlaceholderRecordViewComponent } from '../../skeletons/placeholder-record-view/placeholder-record-view.component'; @Component({ selector: 'app-db-table-row-view', @@ -20,18 +22,18 @@ import { MatTooltipModule } from '@angular/material/tooltip'; ClipboardModule, MatTooltipModule, RouterModule, - CommonModule + CommonModule, + PlaceholderRecordViewComponent ] }) export class DbTableRowViewComponent implements OnInit { - @Input() columns: object[]; - @Input() foreignKeys: object; - @Input() foreignKeysList: string[]; - @Input() widgets: { string: Widget }; - @Input() widgetsList: string[]; @Input() activeFilters: object; public selectedRow: TableRow; + public columns: { + title: string; + normalizedTitle: string; + }[] = []; constructor( private _tableState: TableStateService, @@ -42,28 +44,37 @@ export class DbTableRowViewComponent implements OnInit { ngOnInit(): void { this._tableState.cast.subscribe((row) => { this.selectedRow = row; + if (row.columnsOrder) { + const columnsOrder = this.selectedRow.columnsOrder.length ? this.selectedRow.columnsOrder : Object.keys(this.selectedRow.record); + this.columns = columnsOrder.map(column => { + return { + title: column, + normalizedTitle: normalizeFieldName(column) + } + }) + } }); } isForeignKey(columnName: string) { - return this.foreignKeysList.includes(columnName); + return this.selectedRow.foreignKeysList.includes(columnName); } getForeignKeyValue(field: string) { if (this.selectedRow) { - const identityColumnName = Object.keys(this.selectedRow.record[field]).find(key => key !== this.foreignKeys[field].referenced_column_name); + const identityColumnName = Object.keys(this.selectedRow.record[field]).find(key => key !== this.selectedRow.foreignKeys[field].referenced_column_name); if (identityColumnName) { return this.selectedRow.record[field][identityColumnName]; } else { - const referencedColumnName = this.foreignKeys[field].referenced_column_name; - return this.selectedRow.record[field][referencedColumnName]; + // const referencedColumnName = this.selectedRow.foreignKeys[field].referenced_column_name; + return this.selectedRow.record[field]; } }; return ''; } isWidget(columnName: string) { - return this.widgetsList.includes(columnName); + return this.selectedRow.widgetsList.includes(columnName); } getDedicatedPageLink() { diff --git a/frontend/src/app/components/dashboard/db-table/db-table.component.css b/frontend/src/app/components/dashboard/db-table/db-table.component.css index ec5441173..bca082cda 100644 --- a/frontend/src/app/components/dashboard/db-table/db-table.component.css +++ b/frontend/src/app/components/dashboard/db-table/db-table.component.css @@ -533,8 +533,17 @@ tr.mat-row:hover { top: 40px; } -.foreign-key-link { +.foreign-key-button { + background: transparent; + border: none; color: var(--color-accentedPalette-500); + text-decoration: underline; + font-size: inherit; +} + +.foreign-key-button_selected { + color: var(--color-accentedPalette-700); + font-weight: 600; } .empty-table { diff --git a/frontend/src/app/components/dashboard/db-table/db-table.component.html b/frontend/src/app/components/dashboard/db-table/db-table.component.html index 40f99a763..58db7b6e1 100644 --- a/frontend/src/app/components/dashboard/db-table/db-table.component.html +++ b/frontend/src/app/components/dashboard/db-table/db-table.component.html @@ -217,11 +217,16 @@

{{ displayName }}

- {{ getCellValue(tableData.foreignKeys[column], element[column]) }} - + --> +
diff --git a/frontend/src/app/components/dashboard/db-table/db-table.component.ts b/frontend/src/app/components/dashboard/db-table/db-table.component.ts index 15ff77f5f..c7bcbb41f 100644 --- a/frontend/src/app/components/dashboard/db-table/db-table.component.ts +++ b/frontend/src/app/components/dashboard/db-table/db-table.component.ts @@ -1,6 +1,8 @@ +import * as JSON5 from 'json5'; + import { ActivatedRoute, Router } from '@angular/router'; import { Component, EventEmitter, Input, OnInit, Output, SimpleChanges, ViewChild } from '@angular/core'; -import { CustomAction, TableForeignKey, TablePermissions, TableProperties, TableRow } from 'src/app/models/table'; +import { CustomAction, TableForeignKey, TablePermissions, TableProperties, TableRow, Widget } from 'src/app/models/table'; import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms'; import { Observable, merge, of } from 'rxjs'; import { map, startWith, tap } from 'rxjs/operators'; @@ -33,6 +35,7 @@ import { NotificationsService } from 'src/app/services/notifications.service'; import { PlaceholderTableDataComponent } from '../../skeletons/placeholder-table-data/placeholder-table-data.component'; import { RouterModule } from '@angular/router'; import { SelectionModel } from '@angular/cdk/collections'; +import { TableRowService } from 'src/app/services/table-row.service'; import { TableStateService } from 'src/app/services/table-state.service'; import { normalizeTableName } from '../../../lib/normalize' @@ -112,6 +115,7 @@ export class DbTableComponent implements OnInit { lte: "<=" } public selectedRow: TableRow = null; + public selectedRowType: 'record' | 'foreignKey'; @Input() set table(value){ if (value) this.tableData = value; @@ -123,6 +127,7 @@ export class DbTableComponent implements OnInit { constructor( private _tableState: TableStateService, private _notifications: NotificationsService, + private _tableRow: TableRowService, private route: ActivatedRoute, public router: Router, public dialog: MatDialog, @@ -383,7 +388,71 @@ export class DbTableComponent implements OnInit { } handleViewRow(row: TableRow) { - this._tableState.selectRow({...row, link: `/dashboard/${this.connectionID}/${this.name}/entry`}); + this.selectedRowType = 'record'; + this._tableState.selectRow({ + tableName: this.name, + record: row, + columnsOrder: this.tableData.dataColumns, + primaryKeys: this.tableData.getQueryParams(row), + foreignKeys: this.tableData.foreignKeys, + foreignKeysList: this.tableData.foreignKeysList, + widgets: this.tableData.widgets, + widgetsList: this.tableData.widgetsList, + link: `/dashboard/${this.connectionID}/${this.name}/entry` + }); + } + + handleForeignKeyView(event, foreignKeys, row) { + event.stopPropagation(); + this.selectedRowType = 'foreignKey'; + + console.log('handleForeignKeyView', foreignKeys, row); + + this._tableState.selectRow({ + tableName: null, + record: null, + columnsOrder: null, + primaryKeys: null, + foreignKeys: null, + foreignKeysList: null, + widgets: null, + widgetsList: null, + link: null + }) + + this._tableRow.fetchTableRow(this.connectionID, foreignKeys.referenced_table_name, {[foreignKeys.referenced_column_name]: row[foreignKeys.referenced_column_name]}) + .subscribe(res => { + console.log('Fetched foreign key row:', res); + this._tableState.selectRow({ + tableName: foreignKeys.referenced_table_name, + record: res.row, + columnsOrder: res.list_fields, + primaryKeys: { + [foreignKeys.referenced_column_name]: res.row[foreignKeys.referenced_column_name] + }, + foreignKeys: Object.assign({}, ...res.foreignKeys.map((foreignKey: TableForeignKey) => ({[foreignKey.column_name]: foreignKey}))), + foreignKeysList: res.foreignKeys.map(fk => fk.column_name), + widgets: Object.assign({}, ...res.table_widgets.map((widget: Widget) => { + let parsedParams; + + try { + parsedParams = JSON5.parse(widget.widget_params); + } catch { + parsedParams = {}; + } + + return { + [widget.field_name]: { + ...widget, + widget_params: parsedParams, + }, + }; + }) + ), + widgetsList: res.table_widgets.map(widget => widget.field_name), + link: `/dashboard/${this.connectionID}/${foreignKeys.referenced_table_name}/entry` + }); + }) } handleViewAIpanel() { @@ -391,7 +460,18 @@ export class DbTableComponent implements OnInit { } isRowSelected(primaryKeys) { - return this.selectedRow && Object.keys(this.selectedRow.primaryKeys).length && JSON.stringify(this.selectedRow.primaryKeys) === JSON.stringify(primaryKeys); + if (this.selectedRowType === 'record' && this.selectedRow.primaryKeys !== null) return this.selectedRow && Object.keys(this.selectedRow.primaryKeys).length && JSON.stringify(this.selectedRow.primaryKeys) === JSON.stringify(primaryKeys); + return false; + } + + isForeignKeySelected(record, foreignKey: TableForeignKey) { + if (this.selectedRow) console.log('isForeignKeySelected', this.selectedRow.primaryKeys, foreignKey); + const primaryKeyValue = record[foreignKey.referenced_column_name]; + + if (this.selectedRowType === 'foreignKey' && this.selectedRow && this.selectedRow.record !== null) { + return Object.values(this.selectedRow.primaryKeys)[0] === primaryKeyValue && this.selectedRow.tableName === foreignKey.referenced_table_name; + } + return false; } showCopyNotification(message: string) { diff --git a/frontend/src/app/components/skeletons/placeholder-record-view/placeholder-record-view.component.css b/frontend/src/app/components/skeletons/placeholder-record-view/placeholder-record-view.component.css new file mode 100644 index 000000000..1712923fc --- /dev/null +++ b/frontend/src/app/components/skeletons/placeholder-record-view/placeholder-record-view.component.css @@ -0,0 +1,22 @@ +.record-field { + display: flex; + flex-direction: column; + gap: 4px; + padding: 12px 16px; +} + +.record-field:not(:last-child) { + border-bottom: solid 1px rgba(0, 0, 0, 0.12); +} + +.record-field__key { + mix-blend-mode: normal !important; + height: 20px; + width: 120px; +} + +.record-field__value { + mix-blend-mode: normal !important; + height: 20px; + width: 200px +} \ No newline at end of file diff --git a/frontend/src/app/components/skeletons/placeholder-record-view/placeholder-record-view.component.html b/frontend/src/app/components/skeletons/placeholder-record-view/placeholder-record-view.component.html new file mode 100644 index 000000000..9934a7417 --- /dev/null +++ b/frontend/src/app/components/skeletons/placeholder-record-view/placeholder-record-view.component.html @@ -0,0 +1,22 @@ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/frontend/src/app/components/skeletons/placeholder-record-view/placeholder-record-view.component.spec.ts b/frontend/src/app/components/skeletons/placeholder-record-view/placeholder-record-view.component.spec.ts new file mode 100644 index 000000000..820ba7a0a --- /dev/null +++ b/frontend/src/app/components/skeletons/placeholder-record-view/placeholder-record-view.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { PlaceholderRecordViewComponent } from './placeholder-record-view.component'; + +describe('PlaceholderRecordViewComponent', () => { + let component: PlaceholderRecordViewComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [PlaceholderRecordViewComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(PlaceholderRecordViewComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/components/skeletons/placeholder-record-view/placeholder-record-view.component.ts b/frontend/src/app/components/skeletons/placeholder-record-view/placeholder-record-view.component.ts new file mode 100644 index 000000000..1f81ab2dd --- /dev/null +++ b/frontend/src/app/components/skeletons/placeholder-record-view/placeholder-record-view.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-placeholder-record-view', + imports: [], + templateUrl: './placeholder-record-view.component.html', + styleUrl: './placeholder-record-view.component.css' +}) +export class PlaceholderRecordViewComponent { + +} diff --git a/frontend/src/app/models/table.ts b/frontend/src/app/models/table.ts index 23a3f9881..1280a96c8 100644 --- a/frontend/src/app/models/table.ts +++ b/frontend/src/app/models/table.ts @@ -39,8 +39,14 @@ export interface TableSettings { } export interface TableRow { + tableName: string, record: object, - primaryKeys: object + columnsOrder: string[], + primaryKeys: object, + foreignKeys: TableForeignKey[], + foreignKeysList: string[], + widgets: Widget[], + widgetsList: string[], link?: string }