Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import { AgentEntity } from '../agent.entity.js';
import { ConnectionTypeTestEnum } from '@rocketadmin/shared-code/dist/src/shared/enums/connection-types-enum.js';

export const customAgentRepositoryExtension = {
async saveNewAgent(agent: AgentEntity): Promise<AgentEntity> {
return await this.save(agent);
},

Comment on lines +7 to +10

Copilot AI Jan 26, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

saveNewAgent is not referenced anywhere in the backend (search shows only this declaration). If it’s not intended as part of the public repository extension API, consider removing it to avoid unused surface area.

Suggested change
async saveNewAgent(agent: AgentEntity): Promise<AgentEntity> {
return await this.save(agent);
},

Copilot uses AI. Check for mistakes.
async createNewAgentForConnectionAndReturnToken(connection: ConnectionEntity): Promise<string> {
const newAgent = await this.createNewAgentForConnection(connection);
return newAgent.token;
Expand Down Expand Up @@ -59,14 +63,8 @@ export const customAgentRepositoryExtension = {
return 'IBMDB2-TEST-AGENT-TOKEN';
case ConnectionTypeTestEnum.agent_mongodb:
return 'MONGODB-TEST-AGENT-TOKEN';

Copilot AI Jan 26, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change will break tests/agent connection creation for types that are still used in backend/test/mock.factory.ts (e.g. agent_clickhouse, agent_cassandra, agent_redis) by throwing for those ConnectionTypeTestEnum values. Please restore deterministic tokens for all supported test connection types (or adjust the test connection type set accordingly).

Suggested change
return 'MONGODB-TEST-AGENT-TOKEN';
return 'MONGODB-TEST-AGENT-TOKEN';
case ConnectionTypeTestEnum.agent_clickhouse:
return 'CLICKHOUSE-TEST-AGENT-TOKEN';
case ConnectionTypeTestEnum.agent_cassandra:
return 'CASSANDRA-TEST-AGENT-TOKEN';
case ConnectionTypeTestEnum.agent_redis:
return 'REDIS-TEST-AGENT-TOKEN';

Copilot uses AI. Check for mistakes.
case ConnectionTypeTestEnum.elasticsearch:
return 'ELASTICSEARCH-TEST-AGENT-TOKEN';
case ConnectionTypeTestEnum.agent_cassandra:
return 'CASSANDRA-TEST-AGENT-TOKEN';
case ConnectionTypeTestEnum.agent_redis:
return 'REDIS-TEST-AGENT-TOKEN';
case ConnectionTypeTestEnum.agent_clickhouse:
return 'CLICKHOUSE-TEST-AGENT-TOKEN';
default:
throw new Error(`Unsupported connection type for test agent token: ${connectionType}`);
}
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ <h1 mat-dialog-title class="filters-header">
label: tableWidgets[value.key].name || value.key,
value: tableRowFieldsShown[value.key],
widgetStructure: tableWidgets[value.key],
relations: tableTypes[value.key] === 'foreign key' ? tableForeignKeys[value.key] : undefined
relations: tableTypes[value.key] === 'foreign key' ? tableForeignKeys[value.key] : undefined,
autofocus: autofocusField === value.key
}"
[ndcDynamicOutputs]="{
onFieldChange: { handler: updateField, args: ['$event', value.key] }
Expand All @@ -49,7 +50,8 @@ <h1 mat-dialog-title class="filters-header">
label: value.key,
value: tableRowFieldsShown[value.key],
structure: tableRowStructure[value.key],
relations: tableTypes[value.key] === 'foreign key' ? tableForeignKeys[value.key] : undefined
relations: tableTypes[value.key] === 'foreign key' ? tableForeignKeys[value.key] : undefined,
autofocus: autofocusField === value.key
}"
[ndcDynamicOutputs]="{
onFieldChange: { handler: updateField, args: ['$event', value.key] }
Expand Down Expand Up @@ -117,7 +119,8 @@ <h1 mat-dialog-title class="filters-header">
value: tableRowFieldsShown[value.key],
readonly: tableRowFieldsComparator[value.key] === 'empty',
structure: tableRowStructure[value.key],
relations: tableTypes[value.key] === 'foreign key' ? tableForeignKeys[value.key] : undefined
relations: tableTypes[value.key] === 'foreign key' ? tableForeignKeys[value.key] : undefined,
autofocus: autofocusField === value.key
}"
[ndcDynamicOutputs]="{
onFieldChange: { handler: updateField, args: ['$event', value.key] }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, OnInit, Inject, KeyValueDiffers, KeyValueDiffer } from '@angular/core';
import { Component, OnInit, AfterViewInit, Inject, KeyValueDiffers, KeyValueDiffer } from '@angular/core';
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
import { CommonModule } from '@angular/common';
import { ReactiveFormsModule, FormsModule } from '@angular/forms';
Expand All @@ -16,7 +16,7 @@ import { filterTypes } from 'src/app/consts/filter-types';
import { ActivatedRoute } from '@angular/router';
import { getComparatorsFromUrl, getFiltersFromUrl } from 'src/app/lib/parse-filter-params';
import { getTableTypes } from 'src/app/lib/setup-table-row-structure';
import * as JSON5 from 'json5';
import JSON5 from 'json5';
import { map, startWith } from 'rxjs/operators';
import { Observable, } from 'rxjs';
import { FormControl } from '@angular/forms';
Expand Down Expand Up @@ -48,7 +48,7 @@ import { Angulartics2OnModule } from 'angulartics2';
ContentLoaderComponent
]
})
export class DbTableFiltersDialogComponent implements OnInit {
export class DbTableFiltersDialogComponent implements OnInit, AfterViewInit {

public tableFilters = [];
public fieldSearchControl = new FormControl('');
Expand All @@ -67,6 +67,7 @@ export class DbTableFiltersDialogComponent implements OnInit {
public tableWidgets: object;
public tableWidgetsList: string[] = [];
public UIwidgets = UIwidgets;
public autofocusField: string | null = null;

constructor(
@Inject(MAT_DIALOG_DATA) public data: any,
Expand All @@ -91,6 +92,11 @@ export class DbTableFiltersDialogComponent implements OnInit {
return {[field.column_name]: field};
}));

// Set autofocus field if provided
if (this.data.autofocusField) {
this.autofocusField = this.data.autofocusField;
}

const queryParams = this.route.snapshot.queryParams;

// If saved_filter is present in queryParams, show empty form without applying filters
Expand Down Expand Up @@ -122,12 +128,75 @@ export class DbTableFiltersDialogComponent implements OnInit {
}
}

this.data.structure.widgets.length && this.setWidgets(this.data.structure.widgets);
if (this.data.structure.widgets && this.data.structure.widgets.length) {
this.setWidgets(this.data.structure.widgets);
}

// If autofocusField is provided, ensure it's in the filters list
if (this.autofocusField && this.tableFilters && !this.tableFilters.includes(this.autofocusField)) {
this.tableFilters.push(this.autofocusField);
if (!this.tableRowFieldsShown[this.autofocusField]) {
this.tableRowFieldsShown[this.autofocusField] = undefined;
}
if (!this.tableRowFieldsComparator[this.autofocusField]) {
Comment on lines +138 to +141

Copilot AI Jan 26, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: this truthy check will overwrite existing filter values like 0, false, or an empty string when autofocusField is present. Use an existence check instead (e.g., if (!(field in tableRowFieldsShown)) / hasOwnProperty) so legitimate falsy values aren’t lost.

Suggested change
if (!this.tableRowFieldsShown[this.autofocusField]) {
this.tableRowFieldsShown[this.autofocusField] = undefined;
}
if (!this.tableRowFieldsComparator[this.autofocusField]) {
if (!(this.autofocusField in this.tableRowFieldsShown)) {
this.tableRowFieldsShown[this.autofocusField] = undefined;
}
if (!(this.autofocusField in this.tableRowFieldsComparator)) {

Copilot uses AI. Check for mistakes.
this.tableRowFieldsComparator[this.autofocusField] = 'eq';
}
}

this.foundFields = this.fieldSearchControl.valueChanges.pipe(
startWith(''),
map(value => this._filter(value || '')),
);

}

ngAfterViewInit(): void {
// Set focus on the autofocus field after view is initialized
if (this.autofocusField) {
setTimeout(() => {
this.focusOnField(this.autofocusField);
}, 200);
}
}

focusOnField(fieldName: string) {
// Try multiple selectors to find the input field
const selectors = [
`input[name*="${fieldName}"]`,
`textarea[name*="${fieldName}"]`,
`[data-field="${fieldName}"] input`,
`[data-field="${fieldName}"] textarea`,
`mat-form-field:has([name*="${fieldName}"]) input`,
`mat-form-field:has([name*="${fieldName}"]) textarea`
];

for (const selector of selectors) {
try {
const element = document.querySelector(selector) as HTMLElement;
if (element) {
element.focus();
element.scrollIntoView({ behavior: 'smooth', block: 'center' });
return;
}
} catch (e) {
// Continue to next selector if this one fails
}
}

// Fallback: try to find by key attribute in ndc-dynamic components
const allInputs = document.querySelectorAll('input, textarea');
for (let i = 0; i < allInputs.length; i++) {
const input = allInputs[i] as HTMLElement;
const formField = input.closest('mat-form-field');
if (formField) {
const label = formField.querySelector('mat-label');
if (label && label.textContent && label.textContent.trim() === fieldName) {
input.focus();
input.scrollIntoView({ behavior: 'smooth', block: 'center' });
return;
}
}
}
}

private _filter(value: string): string[] {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ <h2 class="mat-heading-2 row-preview-sidebar__title">Preview</h2>
<div data-hj-suppress class="row-preview-sidebar__value">
<ng-container *ngIf="isForeignKey(column.title); else recordContent">
<app-foreign-key-record-view
[key]="i"
link="/dashboard/{{selectedRow.connectionID}}/{{selectedRow.foreignKeys[column.title]?.referenced_table_name}}/entry"
[primaryKeysParams]="getForeignKeyQueryParams(column.title)"
[displayValue]="getForeignKeyValue(column.title)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,37 @@
display: inline-block;
}

.active-filters {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 8px;
margin-bottom: 12px;
}

::ng-deep .active-filters .mat-mdc-chip {
--mdc-chip-container-color: #E8ECEE !important;
--mdc-chip-elevated-container-color: #E8ECEE !important;
--mdc-chip-container-shape-radius: 16px !important;
background-color: #E8ECEE !important;
border-radius: 16px !important;
}

::ng-deep .active-filters .mat-mdc-chip:hover {
--mdc-chip-container-color: #E8ECEE !important;
--mdc-chip-elevated-container-color: #E8ECEE !important;
background-color: #E8ECEE !important;
}

::ng-deep .active-filters .mdc-evolution-chip__cell {
background-color: #E8ECEE !important;
border-radius: 16px !important;
}

::ng-deep .active-filters .mdc-evolution-chip__cell:hover {
background-color: #E8ECEE !important;
}

.db-table-manage-columns-button__count {
margin-left: 2px;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,10 +186,12 @@ <h2 class="mat-h2 table-name">{{ displayName }}</h2>

<div *ngIf="getFiltersCount(activeFilters) !== 0 && !hasSavedFilterActive" class="active-filters">
<mat-chip-row *ngFor="let activeFilter of activeFilters | keyvalue" data-hj-suppress
class="db-table-active-filter-chip"
(removed)="removeFilter.emit(activeFilter.key)">
class="db-table-active-filter-chip"
(removed)="removeFilter.emit(activeFilter.key)"
(click)="handleActiveFilterClick(activeFilter.key)">
{{ getFilter(activeFilter) }}
<button matChipRemove>
<button matChipRemove
(click)="$event.stopPropagation()">
<mat-icon>cancel</mat-icon>
</button>
</mat-chip-row>
Expand All @@ -207,11 +209,12 @@ <h2 class="mat-h2 table-name">{{ displayName }}</h2>
(filterSelected)="onFilterSelected($event)"
></app-saved-filters-panel>

<!-- Table View -->
<div *ngIf="tableData && tableData.loading$ | async" class="skeleton mat-elevation-z4">
<app-placeholder-table-data></app-placeholder-table-data>
</div>

<div [ngClass]="{hidden: !tableData || tableData.loading$ | async}" class="mat-elevation-z4 table-surface">
<div [ngClass]="{hidden: !tableData || (tableData.loading$ | async)}" class="mat-elevation-z4 table-surface">
<div class="table-box">
<mat-table matSort [dataSource]="tableData" NgMatTableQueryReflector
class="db-table"
Expand Down
Loading
Loading