Skip to content

Commit e517f05

Browse files
Merge branch 'main' into s3-widget-secure-paths-upload-fix
2 parents d861d1c + 6b50dec commit e517f05

File tree

16 files changed

+1161
-166
lines changed

16 files changed

+1161
-166
lines changed

backend/src/entities/agent/repository/custom-agent-repository-extension.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ import { AgentEntity } from '../agent.entity.js';
44
import { ConnectionTypeTestEnum } from '@rocketadmin/shared-code/dist/src/shared/enums/connection-types-enum.js';
55

66
export const customAgentRepositoryExtension = {
7+
async saveNewAgent(agent: AgentEntity): Promise<AgentEntity> {
8+
return await this.save(agent);
9+
},
10+
711
async createNewAgentForConnectionAndReturnToken(connection: ConnectionEntity): Promise<string> {
812
const newAgent = await this.createNewAgentForConnection(connection);
913
return newAgent.token;
@@ -59,14 +63,8 @@ export const customAgentRepositoryExtension = {
5963
return 'IBMDB2-TEST-AGENT-TOKEN';
6064
case ConnectionTypeTestEnum.agent_mongodb:
6165
return 'MONGODB-TEST-AGENT-TOKEN';
62-
case ConnectionTypeTestEnum.elasticsearch:
63-
return 'ELASTICSEARCH-TEST-AGENT-TOKEN';
64-
case ConnectionTypeTestEnum.agent_cassandra:
65-
return 'CASSANDRA-TEST-AGENT-TOKEN';
66-
case ConnectionTypeTestEnum.agent_redis:
67-
return 'REDIS-TEST-AGENT-TOKEN';
68-
case ConnectionTypeTestEnum.agent_clickhouse:
69-
return 'CLICKHOUSE-TEST-AGENT-TOKEN';
66+
default:
67+
throw new Error(`Unsupported connection type for test agent token: ${connectionType}`);
7068
}
7169
},
7270
};

frontend/src/app/components/dashboard/db-table-view/db-table-filters-dialog/db-table-filters-dialog.component.html

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ <h1 mat-dialog-title class="filters-header">
3434
label: tableWidgets[value.key].name || value.key,
3535
value: tableRowFieldsShown[value.key],
3636
widgetStructure: tableWidgets[value.key],
37-
relations: tableTypes[value.key] === 'foreign key' ? tableForeignKeys[value.key] : undefined
37+
relations: tableTypes[value.key] === 'foreign key' ? tableForeignKeys[value.key] : undefined,
38+
autofocus: autofocusField === value.key
3839
}"
3940
[ndcDynamicOutputs]="{
4041
onFieldChange: { handler: updateField, args: ['$event', value.key] }
@@ -49,7 +50,8 @@ <h1 mat-dialog-title class="filters-header">
4950
label: value.key,
5051
value: tableRowFieldsShown[value.key],
5152
structure: tableRowStructure[value.key],
52-
relations: tableTypes[value.key] === 'foreign key' ? tableForeignKeys[value.key] : undefined
53+
relations: tableTypes[value.key] === 'foreign key' ? tableForeignKeys[value.key] : undefined,
54+
autofocus: autofocusField === value.key
5355
}"
5456
[ndcDynamicOutputs]="{
5557
onFieldChange: { handler: updateField, args: ['$event', value.key] }
@@ -117,7 +119,8 @@ <h1 mat-dialog-title class="filters-header">
117119
value: tableRowFieldsShown[value.key],
118120
readonly: tableRowFieldsComparator[value.key] === 'empty',
119121
structure: tableRowStructure[value.key],
120-
relations: tableTypes[value.key] === 'foreign key' ? tableForeignKeys[value.key] : undefined
122+
relations: tableTypes[value.key] === 'foreign key' ? tableForeignKeys[value.key] : undefined,
123+
autofocus: autofocusField === value.key
121124
}"
122125
[ndcDynamicOutputs]="{
123126
onFieldChange: { handler: updateField, args: ['$event', value.key] }

frontend/src/app/components/dashboard/db-table-view/db-table-filters-dialog/db-table-filters-dialog.component.ts

Lines changed: 73 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Component, OnInit, Inject, KeyValueDiffers, KeyValueDiffer } from '@angular/core';
1+
import { Component, OnInit, AfterViewInit, Inject, KeyValueDiffers, KeyValueDiffer } from '@angular/core';
22
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
33
import { CommonModule } from '@angular/common';
44
import { ReactiveFormsModule, FormsModule } from '@angular/forms';
@@ -16,7 +16,7 @@ import { filterTypes } from 'src/app/consts/filter-types';
1616
import { ActivatedRoute } from '@angular/router';
1717
import { getComparatorsFromUrl, getFiltersFromUrl } from 'src/app/lib/parse-filter-params';
1818
import { getTableTypes } from 'src/app/lib/setup-table-row-structure';
19-
import * as JSON5 from 'json5';
19+
import JSON5 from 'json5';
2020
import { map, startWith } from 'rxjs/operators';
2121
import { Observable, } from 'rxjs';
2222
import { FormControl } from '@angular/forms';
@@ -48,7 +48,7 @@ import { Angulartics2OnModule } from 'angulartics2';
4848
ContentLoaderComponent
4949
]
5050
})
51-
export class DbTableFiltersDialogComponent implements OnInit {
51+
export class DbTableFiltersDialogComponent implements OnInit, AfterViewInit {
5252

5353
public tableFilters = [];
5454
public fieldSearchControl = new FormControl('');
@@ -67,6 +67,7 @@ export class DbTableFiltersDialogComponent implements OnInit {
6767
public tableWidgets: object;
6868
public tableWidgetsList: string[] = [];
6969
public UIwidgets = UIwidgets;
70+
public autofocusField: string | null = null;
7071

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

95+
// Set autofocus field if provided
96+
if (this.data.autofocusField) {
97+
this.autofocusField = this.data.autofocusField;
98+
}
99+
94100
const queryParams = this.route.snapshot.queryParams;
95101

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

125-
this.data.structure.widgets.length && this.setWidgets(this.data.structure.widgets);
131+
if (this.data.structure.widgets && this.data.structure.widgets.length) {
132+
this.setWidgets(this.data.structure.widgets);
133+
}
134+
135+
// If autofocusField is provided, ensure it's in the filters list
136+
if (this.autofocusField && this.tableFilters && !this.tableFilters.includes(this.autofocusField)) {
137+
this.tableFilters.push(this.autofocusField);
138+
if (!this.tableRowFieldsShown[this.autofocusField]) {
139+
this.tableRowFieldsShown[this.autofocusField] = undefined;
140+
}
141+
if (!this.tableRowFieldsComparator[this.autofocusField]) {
142+
this.tableRowFieldsComparator[this.autofocusField] = 'eq';
143+
}
144+
}
126145

127146
this.foundFields = this.fieldSearchControl.valueChanges.pipe(
128147
startWith(''),
129148
map(value => this._filter(value || '')),
130149
);
150+
151+
}
152+
153+
ngAfterViewInit(): void {
154+
// Set focus on the autofocus field after view is initialized
155+
if (this.autofocusField) {
156+
setTimeout(() => {
157+
this.focusOnField(this.autofocusField);
158+
}, 200);
159+
}
160+
}
161+
162+
focusOnField(fieldName: string) {
163+
// Try multiple selectors to find the input field
164+
const selectors = [
165+
`input[name*="${fieldName}"]`,
166+
`textarea[name*="${fieldName}"]`,
167+
`[data-field="${fieldName}"] input`,
168+
`[data-field="${fieldName}"] textarea`,
169+
`mat-form-field:has([name*="${fieldName}"]) input`,
170+
`mat-form-field:has([name*="${fieldName}"]) textarea`
171+
];
172+
173+
for (const selector of selectors) {
174+
try {
175+
const element = document.querySelector(selector) as HTMLElement;
176+
if (element) {
177+
element.focus();
178+
element.scrollIntoView({ behavior: 'smooth', block: 'center' });
179+
return;
180+
}
181+
} catch (e) {
182+
// Continue to next selector if this one fails
183+
}
184+
}
185+
186+
// Fallback: try to find by key attribute in ndc-dynamic components
187+
const allInputs = document.querySelectorAll('input, textarea');
188+
for (let i = 0; i < allInputs.length; i++) {
189+
const input = allInputs[i] as HTMLElement;
190+
const formField = input.closest('mat-form-field');
191+
if (formField) {
192+
const label = formField.querySelector('mat-label');
193+
if (label && label.textContent && label.textContent.trim() === fieldName) {
194+
input.focus();
195+
input.scrollIntoView({ behavior: 'smooth', block: 'center' });
196+
return;
197+
}
198+
}
199+
}
131200
}
132201

133202
private _filter(value: string): string[] {

frontend/src/app/components/dashboard/db-table-view/db-table-row-view/db-table-row-view.component.html

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ <h2 class="mat-heading-2 row-preview-sidebar__title">Preview</h2>
8585
<div data-hj-suppress class="row-preview-sidebar__value">
8686
<ng-container *ngIf="isForeignKey(column.title); else recordContent">
8787
<app-foreign-key-record-view
88-
[key]="i"
8988
link="/dashboard/{{selectedRow.connectionID}}/{{selectedRow.foreignKeys[column.title]?.referenced_table_name}}/entry"
9089
[primaryKeysParams]="getForeignKeyQueryParams(column.title)"
9190
[displayValue]="getForeignKeyValue(column.title)"

frontend/src/app/components/dashboard/db-table-view/db-table-view.component.css

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,37 @@
192192
display: inline-block;
193193
}
194194

195+
.active-filters {
196+
display: flex;
197+
align-items: center;
198+
flex-wrap: wrap;
199+
gap: 8px;
200+
margin-bottom: 12px;
201+
}
202+
203+
::ng-deep .active-filters .mat-mdc-chip {
204+
--mdc-chip-container-color: #E8ECEE !important;
205+
--mdc-chip-elevated-container-color: #E8ECEE !important;
206+
--mdc-chip-container-shape-radius: 16px !important;
207+
background-color: #E8ECEE !important;
208+
border-radius: 16px !important;
209+
}
210+
211+
::ng-deep .active-filters .mat-mdc-chip:hover {
212+
--mdc-chip-container-color: #E8ECEE !important;
213+
--mdc-chip-elevated-container-color: #E8ECEE !important;
214+
background-color: #E8ECEE !important;
215+
}
216+
217+
::ng-deep .active-filters .mdc-evolution-chip__cell {
218+
background-color: #E8ECEE !important;
219+
border-radius: 16px !important;
220+
}
221+
222+
::ng-deep .active-filters .mdc-evolution-chip__cell:hover {
223+
background-color: #E8ECEE !important;
224+
}
225+
195226
.db-table-manage-columns-button__count {
196227
margin-left: 2px;
197228
}

frontend/src/app/components/dashboard/db-table-view/db-table-view.component.html

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,10 +186,12 @@ <h2 class="mat-h2 table-name">{{ displayName }}</h2>
186186

187187
<div *ngIf="getFiltersCount(activeFilters) !== 0 && !hasSavedFilterActive" class="active-filters">
188188
<mat-chip-row *ngFor="let activeFilter of activeFilters | keyvalue" data-hj-suppress
189-
class="db-table-active-filter-chip"
190-
(removed)="removeFilter.emit(activeFilter.key)">
189+
class="db-table-active-filter-chip"
190+
(removed)="removeFilter.emit(activeFilter.key)"
191+
(click)="handleActiveFilterClick(activeFilter.key)">
191192
{{ getFilter(activeFilter) }}
192-
<button matChipRemove>
193+
<button matChipRemove
194+
(click)="$event.stopPropagation()">
193195
<mat-icon>cancel</mat-icon>
194196
</button>
195197
</mat-chip-row>
@@ -207,11 +209,12 @@ <h2 class="mat-h2 table-name">{{ displayName }}</h2>
207209
(filterSelected)="onFilterSelected($event)"
208210
></app-saved-filters-panel>
209211

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

214-
<div [ngClass]="{hidden: !tableData || tableData.loading$ | async}" class="mat-elevation-z4 table-surface">
217+
<div [ngClass]="{hidden: !tableData || (tableData.loading$ | async)}" class="mat-elevation-z4 table-surface">
215218
<div class="table-box">
216219
<mat-table matSort [dataSource]="tableData" NgMatTableQueryReflector
217220
class="db-table"

0 commit comments

Comments
 (0)