refactor: replace old tables with dynamic-mat-table and remove column icons#2349
refactor: replace old tables with dynamic-mat-table and remove column icons#2349abdimo101 wants to merge 42 commits into
Conversation
There was a problem hiding this comment.
Hey - I've found 2 issues, and left some high level feedback:
- In DatafilesComponent,
paginationModeis set to'server-side'but there is no(paginationChange)handler wired up, so changing pages in the dynamic-mat-table will not updatedataSource; either implement a paginationChange handler that slices/requests data and callsdataSource.next(...)or switch to'client-side'pagination if all files are already loaded. - In RelatedDatasetsComponent you are subscribing to
vm$anddatasetsPerPage$manually just to push intodataSourceand updatepagination, while also usingvm$with the async pipe in the template; consider binding the table directly tovm.relatedDatasets/vm.relatedDatasetsCountvia the async pipe and deriving pagination properties in the template to avoid extra BehaviorSubjects and explicit subscriptions.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In DatafilesComponent, `paginationMode` is set to `'server-side'` but there is no `(paginationChange)` handler wired up, so changing pages in the dynamic-mat-table will not update `dataSource`; either implement a paginationChange handler that slices/requests data and calls `dataSource.next(...)` or switch to `'client-side'` pagination if all files are already loaded.
- In RelatedDatasetsComponent you are subscribing to `vm$` and `datasetsPerPage$` manually just to push into `dataSource` and update `pagination`, while also using `vm$` with the async pipe in the template; consider binding the table directly to `vm.relatedDatasets`/`vm.relatedDatasetsCount` via the async pipe and deriving pagination properties in the template to avoid extra BehaviorSubjects and explicit subscriptions.
## Individual Comments
### Comment 1
<location path="src/app/datasets/datafiles/datafiles.component.ts" line_range="126-128" />
<code_context>
+ DataFiles_File[]
+ >([]);
+
+ paginationMode: TablePaginationMode = "server-side";
+
+ pagination: TablePagination = {
+ pageSizeOptions: [10, 25, 50],
+ pageIndex: 0,
</code_context>
<issue_to_address>
**issue (bug_risk):** Table pagination is configured as server-side but the component never handles pagination changes or slices the data.
With `paginationMode: "server-side"` and `pagination.length = files.length`, the table is configured for server-side pagination, but the component never handles `paginationChange` and always passes the full `files` array to `dataSource`. Either implement `paginationChange` handling (and update `dataSource` / fetch new pages) to match server-side behavior, or change `paginationMode` to the client-side option if pagination should be done entirely in memory.
</issue_to_address>
### Comment 2
<location path="src/app/datasets/related-datasets/related-datasets.component.ts" line_range="83" />
<code_context>
+ },
+ };
+
+ dataSource: BehaviorSubject<object[]> = new BehaviorSubject<object[]>([]);
+
+ paginationMode: TablePaginationMode = "server-side";
</code_context>
<issue_to_address>
**suggestion:** Using `object[]` for the dataSource loses type safety for related datasets.
Given the table and view model both use `OutputDatasetObsoleteDto`/`DatasetClass`-shaped data, keeping `dataSource` as `BehaviorSubject<object[]>` weakens compile-time safety (e.g. when accessing `sender.row` in `onRowEvent` or formatting rows). Please narrow this to a concrete type such as `BehaviorSubject<DatasetClass[]>` (or the relevant DTO) so the table interactions remain type-safe.
Suggested implementation:
```typescript
dataSource: BehaviorSubject<DatasetClass[]> = new BehaviorSubject<DatasetClass[]>([]);
```
1. Ensure `DatasetClass` (or the specific DTO you actually use for related datasets, e.g. `OutputDatasetObsoleteDto`) is imported at the top of `related-datasets.component.ts`:
- For example:
- `import { DatasetClass } from '...';`
- Or replace `DatasetClass` with `OutputDatasetObsoleteDto` if that is the correct model:
- `dataSource: BehaviorSubject<OutputDatasetObsoleteDto[]> = new BehaviorSubject<OutputDatasetObsoleteDto[]>([]);`
2. If the table template or other code assumes a different concrete type (e.g. `OutputDatasetObsoleteDto`), align the generic type argument here with whatever type is used in row event handlers (`sender.row`) and formatting logic, so the compiler enforces consistency across the component.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
Junjiequan
left a comment
There was a problem hiding this comment.
lgtm, please merge it after dateformat update
8d20922 to
524d5e9
Compare
Junjiequan
left a comment
There was a problem hiding this comment.
some copilot reviews need to be addressed
…m:SciCatProject/frontend into replace-old-tables-with-dynamic-mat-table
…table from client-side to server-side
…m:SciCatProject/frontend into replace-old-tables-with-dynamic-mat-table
Code Review: Branch
|
Code Review: Branch
|
| Criteria | Rating | Notes |
|---|---|---|
| Logic Correctness | Core logic works, but has critical performance issue with count query | |
| Edge Case Handling | Handles basic cases well, but missing several important edge cases | |
| Code Makes Sense | ✅ Yes | Architectural direction is sound and necessary |
| No Unreachable Code | Some dead code remains, but major unreachable code was correctly removed | |
| Production Ready | ❌ No, not yet | Performance issue and edge cases need addressing |
Decision: DO NOT MERGE YET
While the architectural direction is correct and the code is generally well-structured, there are critical issues that must be resolved:
- The performance regression from fetching all files for count makes this worse than the old implementation for large datasets
- The selection state behavior across pagination is unclear and potentially confusing
- Missing edge case handling could cause runtime errors
Path Forward:
-
Fix the count query - This is the blocker. Options:
- API change to return count with paginated results (preferred)
- Use a separate count endpoint
- Accept the workaround with clear documentation and TODO
-
Clarify and fix pagination selection behavior - Define the expected UX and implement consistently
-
Add null checks and validation - Prevent runtime errors
-
Clean up dead code - Remove unused observables and imports
-
Add comprehensive tests - Ensure robustness
Once these issues are addressed, the branch will be production-ready and represents a significant improvement over the current implementation.
Report generated by analyzing git diff between master and replace-old-tables-with-dynamic-mat-table branch
Generated with Mistral AI
Security Review: Branch
|
| Type | Status | Location | Risk | Notes |
|---|---|---|---|---|
XSS via [innerHTML] |
datafiles.component.html:5 |
Medium | [innerHTML]="hasFileAboveMaxSizeWarning()" - Template string from config is rendered as HTML. NOT introduced by this branch |
|
| Template Injection | ✅ Safe | hasFileAboveMaxSizeWarning() |
Low | String replacement of placeholders (<maxDirectDownloadSize>, <sftpHost>, <sourceFolder>) with sanitized values. Uses simple .replace() with controlled values |
| API Parameter Injection | ✅ Safe | datasets.effects.ts |
Low | Query parameters (pid, skip, limit) are properly typed and come from route params or controlled UI inputs |
| Code Injection | ✅ Safe | All components | None | No eval(), new Function(), or dynamic code execution |
Details:
The only potential injection point is the [innerHTML] binding in datafiles.component.html line 5:
<span [innerHTML]="hasFileAboveMaxSizeWarning()"></span>This method constructs HTML by replacing placeholders in a template string:
warning = warning.replace(
"<" + key + ">",
`<strong>${valueMapping[key]}</strong>`,
);Risk: If an administrator sets a malicious maxFileSizeWarning in the config, it could inject HTML/JS. However:
- This vulnerability existed in master before this branch
- It requires admin access to the config file
- The replacement values (
sftpHost,sourceFolder,maxDirectDownloadSize) are controlled by the application and are sanitized
Verdict: No new injection vulnerabilities introduced by this branch.
2. Sensitive User Data Exposure
Assessment: No NEW sensitive data exposure ✅
| Data Type | Status | Location | Risk | Notes |
|---|---|---|---|---|
| JWT Tokens | ✅ No change | datafiles.component.ts |
None | Same token handling as master (auth_token, jwt) for download forms |
| File Metadata | ✅ Same as master | datafiles.component.ts |
Low | Exposes: path, size, time, uid, gid, perm, hash - same fields as before |
| Dataset Metadata | ✅ Same as master | related-datasets.component.ts |
Low | Exposes: pid, name, sourceFolder, size, type, creationTime, owner - same fields as before |
| File Paths | ✅ No change | Both components | Low | sourceFolder paths displayed, same as master |
| Owner Information | ✅ No change | related-datasets.component.ts |
Low | owner field displayed, same as master |
Details:
The changes only affect how data is displayed (which table component is used), not what data is displayed. The same fields that were exposed in the old app-table are exposed in the new dynamic-mat-table.
- Datafiles: Same
DataFiles_Fileinterface fields (path, size, time, chk, uid, gid, perm, hash, selected) - Related Datasets: Same
OutputDatasetObsoleteDtofields (pid, datasetName, sourceFolder, size, type, creationTime, owner)
No new sensitive data is exposed through:
- Table columns
- API responses
- Error messages
- Logs
Verdict: No new sensitive user data exposure introduced by this branch.
3. Insecure API Usage
Assessment: No insecure API usage ✅
| API | Status | Location | Notes |
|---|---|---|---|
| OrigdatablocksV4Service.origDatablocksV4ControllerFindAllFilesV4() | ✅ Secure | datasets.effects.ts |
Official SciCat SDK v4 endpoint, replaces v3 endpoint |
| DatasetsService.datasetsControllerFindAllOrigDatablocksV3() | ❌ Removed | Was in master | Replaced by v4 service |
| DatasetsService.datasetsControllerFindAllDatablocksV3() | ✅ Same | datasets.effects.ts |
Still used for datablocks, unchanged |
Details:
API Changes:
- Old:
datasetsService.datasetsControllerFindAllOrigDatablocksV3(pid)- v3 endpoint - New:
origdatablocksService.origDatablocksV4ControllerFindAllFilesV4(JSON.stringify(query))- v4 endpoint
Security Analysis:
- Both are official SciCat SDK methods
- Both require the same authentication
- The new v4 endpoint accepts a JSON query string, but the query is constructed from controlled parameters (pid from route, skip/limit from pagination)
- No hardcoded credentials or API keys
- No use of insecure protocols (no http:, only https: via SDK)
- No CORS bypass attempts
- No credential transmission in URLs
Query Construction:
const paginatedQuery = {
where: { datasetId: pid }, // pid from route params
limits: {
skip: filters?.skip || 0, // from pagination
limit: filters?.limit || 5, // from pagination
},
};The query is properly structured and uses controlled values. The JSON.stringify() is safe as it only serializes objects.
Verdict: No insecure API usage. The API migration from v3 to v4 is secure and follows the same patterns as the existing code.
4. Authentication Bypass
Assessment: No authentication bypass vulnerabilities ✅
| Attack Vector | Status | Analysis |
|---|---|---|
| Token Manipulation | ❌ Not possible | Tokens come from authService.getToken() and usersService.usersControllerGetUserJWTV3() - unchanged from master |
| PID Manipulation | ❌ Not possible | Dataset PID comes from route parameters; users can only access datasets they have permission for (enforced server-side) |
| Filter Manipulation | ❌ Not possible | Pagination filters (skip, limit) only affect client-side display; server enforces authorization |
| Route-based Access | ✅ Same as master | No changes to route guards or authentication flows |
| Service Injection | ✅ Safe | New OrigdatablocksV4Service is from official SDK, injected via DI like all other services |
Details:
Authentication Flow:
- No changes to how users authenticate
- No changes to token storage or transmission
- No new ways to obtain or manipulate tokens
Authorization:
- The branch does not add or remove any authorization checks
- Server-side authorization (via SciCat API) remains the same
- Client-side, the same data access patterns are used
Data Access:
- Dataset PID comes from the route:
this.datasetPid = dataset.pid - The PID is used to fetch data:
fetchOrigDatablocksAction({ pid: this.datasetPid, ... }) - Users can only navigate to datasets they have access to (enforced by route guards, not shown in this diff)
- No way to access other users' datasets through manipulation
JWT/Token Handling:
The token handling for file downloads is identical to master:
// Same in both master and this branch:
if (this.appConfig.multipleDownloadUseAuthToken) {
this.auth_token = `Bearer ${this.authService.getToken().id}`;
this[`${form}Element`].nativeElement.auth_token.value = this.auth_token;
}
if (!this.jwt) {
this.subscriptions.push(
this.usersService.usersControllerGetUserJWTV3().subscribe((jwt) => {
this.jwt = jwt;
this[`${form}Element`].nativeElement.jwt.value = jwt.jwt;
}),
);
}Verdict: No authentication bypass vulnerabilities introduced by this branch.
Summary
| Security Concern | Introduced by Branch? | Severity | Status |
|---|---|---|---|
XSS via [innerHTML] |
❌ No (pre-existing) | Medium | Not addressed |
| Template injection | ❌ No | Low | Safe |
| Sensitive data exposure | ❌ No | None | Safe |
| Insecure API usage | ❌ No | None | Safe |
| Authentication bypass | ❌ No | None | Safe |
Overall Security Assessment: ✅ SECURE
Final Verdict: The branch introduces NO NEW security vulnerabilities.
The replace-old-tables-with-dynamic-mat-table branch maintains the same security posture as master. It is a pure refactoring that changes how tables are rendered (migrating from app-table to dynamic-mat-table) without changing:
- What data is displayed
- How data is fetched
- How authentication works
- What API endpoints are called
Pre-existing Security Issue (Not Introduced by This Branch):
- XSS vulnerability via
[innerHTML]="hasFileAboveMaxSizeWarning()"indatafiles.component.html- Requires malicious admin config
Recommendation: This branch is secure to merge from a security perspective. The pre-existing XSS issue should be addressed separately (e.g., by sanitizing the HTML or using [textContent] instead of [innerHTML]).
Security review conducted by analyzing git diff between master and replace-old-tables-with-dynamic-mat-table branch
Generated with Mistral AI
…a count dispatch for datafiles component and dataset details dashboard inside fetchDataForTab
|
UPDATE: Loading spinner has been added to datafiles & related datasets table paginators when the count request is in a pending state. Similar to how it was done in #2399 |
Junjiequan
left a comment
There was a problem hiding this comment.
Holding this PR until new SDK release
| }), | ||
| ); | ||
| this.store.dispatch( | ||
| fetchOrigDatablocksCountAction({ |
There was a problem hiding this comment.
We can avoid fetching the count at each pagination change, only needed at first time.
| break; | ||
| case TAB.datafiles: | ||
| { | ||
| this.store.dispatch( |
There was a problem hiding this comment.
fetching here without specifying the pagination parameters would result in using the default {skip: 0, limit:5} which is inconsistent with what we have in datafiles component {limit:10}. I suggest specifying these here.
Also I suggest we go for 25 for consistency through all tables
Description
This PR replaces old tables with dynamic-mat-table in
datafiles.componentandrelated-datasets.componentand removes column header icons to keep table headers consistent.Datafiles table:

Related Datasets table:

Motivation
Background on use case, changes needed
Fixes:
Please provide a list of the fixes implemented in this PR
Changes:
Please provide a list of the changes implemented by this PR
Tests included
Documentation
official documentation info
If you have updated the official documentation, please provide PR # and URL of the pages where the updates are included
Backend version
Summary by Sourcery
Refactor dataset-related tables to use dynamic-mat-table with centralized pagination and selection handling while aligning table headers and visuals.
New Features:
Bug Fixes:
Enhancements: