Skip to content
Draft
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
111 changes: 108 additions & 3 deletions docs/contributors/default-list-settings.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
# Default List Settings (Frontend)

This page explains where to configure default list behavior in the frontend Admin Settings UI.
This page explains where to configure default list and table behavior in the
frontend.

Currently it only covers default sorting.
The datasets and proposals defaults are configured in the Admin Settings UI. The
dynamic datafiles table also supports configurable default columns through the
frontend configuration.

## Where To Find It

Open the user menu and go to **Admin Settings**.

![Admin Settings](admin_settings_menu.png)
Expand All @@ -14,24 +18,125 @@ Then open **List settings**

![List settings overview](admin_list_settings_overview.png)
_Figure 2: List settings overview._

## List Settings Structure

There are two sections:
The Admin Settings UI currently contains two list settings sections:

- **Default Datasets List Settings**
- **Default Proposals List Settings**

The dynamic datafiles table is configured with `defaultDatafilesColumnsList` in
the frontend configuration, for example `src/assets/config.json` in local
development or the deployed frontend config for an environment. It is not
currently exposed as a separate **List settings** section in the Admin Settings
UI.

## Default Sorting

Default sorting is configured at column level with the `sort` property.

Accepted values:

- `asc`
- `desc`

Rules:

- Define `sort` on only one column per list section.
- If `sort` is not defined, the table falls back to `createdAt` in descending order.

![Sort field in columns list](sort_field_columns_list.png)
_Figure 3: Sort field in Default Datasets List Settings._

## Dynamic Datafiles Table

The dynamic datafiles table is the table shown in the dataset details
**Datafiles** tab when `dynamicDatafilesViewEnabled` is enabled.

Configuration keys:

- `dynamicDatafilesViewEnabled`: switches the dataset **Datafiles** tab from the
static datafiles component to the dynamic table component.
- `defaultDatafilesColumnsList`: defines the default columns shown in the
dynamic datafiles table.
- `datafilesActions`: defines the configurable action buttons shown above the
table.

The dynamic datafiles table uses the shared `dynamic-mat-table` component with
server-side pagination. By default it requests 25 rows per page and offers page
sizes of 10, 25, 50, 100, and 200.

The component also applies the same default row divider style as the datasets
table through the table settings `rowStyle`.

### Datafiles Columns

`defaultDatafilesColumnsList` is an array of column definitions. Each column
usually points to a property on the file origdatablock row. Datafile fields are

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion (typo): Consider adding a possessive to clarify "file origdatablock row".

This wording is a bit ungrammatical. Rephrase to something like “file’s origdatablock row” (or similar for your domain) to make the relationship clearer.

Suggested implementation:

### Datafiles Columns

`defaultDatafilesColumnsList` is an array of column definitions. Each column
usually points to a property on the file’s origdatablock row. Datafile fields
are available under `dataFileList`.

This page explains where to configure default list and table behavior in the
frontend.

If there are other occurrences of the phrase “file origdatablock row” elsewhere in the documentation, they should similarly be updated to “file’s origdatablock row” (or another possessive construction consistent with your domain terminology).

available under `dataFileList`.

Example:

```json
"defaultDatafilesColumnsList": [
{
"name": "dataFileList.path",
"type": "standard",
"icon": "text_snippet",
"header": "Filename",
"enabled": true
},
{
"name": "dataFileList.size",
"type": "standard",
"icon": "save",
"header": "Size",
"pipe": "filesize"
},
{
"name": "dataFileList.metadata.measurement_type",
"type": "standard",
"icon": "science",
"header": "Measurement type"
},
{
"name": "dataFileList.time",
"type": "date",
"icon": "access_time",
"header": "Created at",
"format": "yyyy-MM-dd HH:mm"
}
]
```

Common column properties:

- `name`: field path used by the table. For datafiles this is usually
`dataFileList.<field>`.
- `header`: visible column label.
- `type`: table cell type, usually `standard` or `date`.
- `icon`: Material icon shown in the column settings menu.
- `enabled`: whether the column is enabled by default.
- `format`: date formatting string for date columns.
- `pipe`: display pipe. The datafiles table supports `date`, `filesize`, and
`timeDuration` through the dynamic table pipe mapping. Pipe names are matched
case-insensitively.
- `width`: optional column width.
- `sort`: optional default sort direction. Use `asc` or `desc`.

### Saved User Settings

The admin defaults are only the starting point. When a user saves table settings
from the dynamic datafiles table menu, the selected columns are stored in the
user setting `fe_datafiles_table_columns`.

At runtime, the table merges saved user columns with the current
`defaultDatafilesColumnsList`:

- saved columns keep the user's order, visibility, and width;
- new default columns are appended when they are not already saved;
- saved custom columns with `userAdded: true` are preserved.

To return to the site defaults, use the table settings menu and choose the
default settings option.
2 changes: 2 additions & 0 deletions src/app/app-config.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ export interface AppConfigInterface {
addDatasetEnabled: boolean;
archiveWorkflowEnabled: boolean;
datasetJsonScientificMetadata: boolean;
dynamicDatafilesViewEnabled?: boolean;
datasetPageSizeOptions?: number[];
datasetReduceEnabled: boolean;
datasetDetailsShowMissingProposalId: boolean;
Expand Down Expand Up @@ -156,6 +157,7 @@ export interface AppConfigInterface {
metadataEditingUnitListDisabled?: boolean;
defaultDatasetsListSettings?: ListSettings;
defaultProposalsListSettings?: ListSettings;
defaultDatafilesColumnsList?: TableColumn[];
thumbnailFetchLimitPerPage: number;
maxFileUploadSizeInMb?: string;
datasetDetailComponent?: DatasetDetailComponentConfig;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { AdminGuard } from "app-routing/admin.guard";
import { AuthGuard } from "app-routing/auth.guard";
import { ServiceGuard } from "app-routing/service.guard";
import { AdminTabComponent } from "datasets/admin-tab/admin-tab.component";
import { DatafilesComponent } from "datasets/datafiles/datafiles.component";
import { DatafilesWrapperComponent } from "datasets/datafiles/datafiles-wrapper.component";
import { JsonScientificMetadataComponent } from "datasets/jsonScientificMetadata/jsonScientificMetadata.component";
import { DatasetFileUploaderComponent } from "datasets/dataset-file-uploader/dataset-file-uploader.component";
import { DatasetLifecycleComponent } from "datasets/dataset-lifecycle/dataset-lifecycle.component";
Expand All @@ -24,7 +24,7 @@ const routes: Routes = [
},
{
path: "datafiles",
component: DatafilesComponent,
component: DatafilesWrapperComponent,
},
{
path: "relatedDatasets",
Expand Down
50 changes: 50 additions & 0 deletions src/app/datasets/datafiles/datafiles-wrapper.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { CommonModule } from "@angular/common";
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { AppConfigInterface, AppConfigService } from "app-config.service";
import { DatafilesWrapperComponent } from "./datafiles-wrapper.component";
import { DynamicDatafilesComponent } from "./dynamic-datafiles/dynamic-datafiles.component";
import { DatafilesComponent } from "./static-datafiles/datafiles.component";

describe("DatafilesWrapperComponent", () => {
let component: DatafilesWrapperComponent;
let fixture: ComponentFixture<DatafilesWrapperComponent>;
let appConfigService: jasmine.SpyObj<AppConfigService>;

beforeEach(() => {
const appConfigServiceSpy = jasmine.createSpyObj("AppConfigService", [
"getConfig",
]);

TestBed.configureTestingModule({
imports: [CommonModule],
declarations: [DatafilesWrapperComponent],
providers: [{ provide: AppConfigService, useValue: appConfigServiceSpy }],
}).compileComponents();

fixture = TestBed.createComponent(DatafilesWrapperComponent);
component = fixture.componentInstance;
appConfigService = TestBed.inject(
AppConfigService,
) as jasmine.SpyObj<AppConfigService>;
});

it("should create the component", () => {
expect(component).toBeTruthy();
});

it("should load DynamicDatafilesComponent when dynamicDatafilesViewEnabled is true", () => {
appConfigService.getConfig.and.returnValue({
dynamicDatafilesViewEnabled: true,
} as AppConfigInterface);

expect(component.getDatafilesComponent()).toBe(DynamicDatafilesComponent);
});

it("should load DatafilesComponent when dynamicDatafilesViewEnabled is false", () => {
appConfigService.getConfig.and.returnValue({
dynamicDatafilesViewEnabled: false,
} as AppConfigInterface);

expect(component.getDatafilesComponent()).toBe(DatafilesComponent);
});
});
19 changes: 19 additions & 0 deletions src/app/datasets/datafiles/datafiles-wrapper.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Component } from "@angular/core";
import { AppConfigService } from "app-config.service";
import { DynamicDatafilesComponent } from "./dynamic-datafiles/dynamic-datafiles.component";
import { DatafilesComponent } from "./static-datafiles/datafiles.component";

@Component({
selector: "app-datafiles-wrapper",
template: ` <ng-container *ngComponentOutlet="getDatafilesComponent()" /> `,
standalone: false,
})
export class DatafilesWrapperComponent {
constructor(private appConfigService: AppConfigService) {}

getDatafilesComponent() {
return this.appConfigService.getConfig().dynamicDatafilesViewEnabled
? DynamicDatafilesComponent
: DatafilesComponent;
}
}
11 changes: 0 additions & 11 deletions src/app/datasets/datafiles/datafiles.interfaces.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<ng-template [ngIf]="dataset$ | async">
<ng-template [ngIf]="maxFileSize && tooLargeFile">
<span>
<mat-icon class="warning-icon"> warning </mat-icon>
<span [innerHTML]="hasFileAboveMaxSizeWarning()"></span>
</span>
</ng-template>

<ng-template [ngIf]="maxFileSize">
<div>
<mat-icon> info </mat-icon>
Maximum allowed download size: {{ maxFileSize | filesize }}
</div>
</ng-template>

<ng-template [ngIf]="files && maxFileSize">
<div class="selected" fxLayout="row" fxLayoutAlign="space-evenly end">
<div fxFlex="auto" style="margin-bottom: 0.5em">
Selected: {{ selectedFileSize | filesize
}}{{ maxFileSize ? " / " + (maxFileSize | filesize) : "" }}
</div>
</div>
</ng-template>

<div class="datafiles-header">
<span [ngPlural]="count" class="nbr-of-files">
<ng-template ngPluralCase="=0">No datafiles.</ng-template>
<ng-template ngPluralCase="=1">1 datafile.</ng-template>
<ng-template ngPluralCase="other">{{ count }} datafiles.</ng-template>
</span>

<configurable-actions
[actionsConfig]="appConfig.datafilesActions"
[actionItems]="actionItems"
></configurable-actions>
</div>

<dynamic-mat-table
[tableName]="tableName"
[columns]="columns"
[pending]="pending"
[setting]="setting"
[pagingMode]="paginationMode"
[dataSource]="dataSource"
[pagination]="pagination"
[rowSelectionMode]="rowSelectionMode"
[rowSelectionModel]="rowSelectionModel"
[showGlobalTextSearch]="false"
(paginationChange)="onPaginationChange($event)"
(globalTextSearchChange)="onGlobalTextSearchChange($event)"
(onRowEvent)="onRowClick($event)"
(settingChange)="onSettingChange($event)"
(onTableEvent)="onTableEvent($event)"
class="mat-elevation-z2"
[emptyMessage]="'No files available'"
[emptyIcon]="'folder'"
>
</dynamic-mat-table>
</ng-template>
Loading