Skip to content
Open
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 @@ -89,14 +89,21 @@
</div>
<div class="second-row">
@if (!showAccess || !item.ShareArchiveVO) {
<span>
{{ startDisplayTime | prDate: item.TimezoneVO : 'date' }}
@if (item.dataStatus > 0) {
<span @ngIfFadeInAnimation>{{
startDisplayTime | prDate: item.TimezoneVO : 'time'
}}</span>
}
</span>
@if (showEdtfDate) {
<pr-edtf-date-display
[displayTime]="item.displayTime"
[showTime]="item.dataStatus > 0"
/>
} @else {
<span>
{{ startDisplayTime | prDate: item.TimezoneVO : 'date' }}
@if (item.dataStatus > 0) {
<span @ngIfFadeInAnimation>{{
startDisplayTime | prDate: item.TimezoneVO : 'time'
}}</span>
}
</span>
}
}
@if (showAccess || item.ShareArchiveVO) {
<span> Shared by The {{ item.ShareArchiveVO?.fullName }} Archive </span>
Expand All @@ -110,15 +117,24 @@
}
@if (!showAccess) {
<div class="date">
@if (item.dataStatus > 0) {
<div class="date-top" @ngIfFadeInAnimation>
{{ startDisplayTime | prDate: item.TimezoneVO : 'date' }}
</div>
}
@if (item.dataStatus > 0) {
<div class="date-bottom" @ngIfFadeInAnimation>
{{ startDisplayTime | prDate: item.TimezoneVO : 'time' }}
</div>
@if (showEdtfDate) {
@if (item.dataStatus > 0) {
<pr-edtf-date-display
[displayTime]="item.displayTime"
@ngIfFadeInAnimation
/>
}
} @else {
@if (item.dataStatus > 0) {
<div class="date-top" @ngIfFadeInAnimation>
{{ startDisplayTime | prDate: item.TimezoneVO : 'date' }}
</div>
}
@if (item.dataStatus > 0) {
<div class="date-bottom" @ngIfFadeInAnimation>
{{ startDisplayTime | prDate: item.TimezoneVO : 'time' }}
</div>
}
}
</div>
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { EditService } from '@core/services/edit/edit.service';
import { DeviceService } from '@shared/services/device/device.service';
import { provideNoopAnimations } from '@angular/platform-browser/animations';
import { GetThumbnailPipe } from '@shared/pipes/get-thumbnail.pipe';
import { EdtfDateDisplayComponent } from '@shared/components/edtf-date-display/edtf-date-display.component';
import { FileListItemComponent } from './file-list-item.component';

@Pipe({ name: 'itemTypeIcon' })
Expand All @@ -38,6 +39,21 @@ export class MockPrConstantsPipe implements PipeTransform {
}
}

const buildTestItem = (): any =>
({
displayDT: new Date().toISOString(),
displayName: 'Test Item',
archiveNbr: '123',
folder_linkId: '456',
type: '',
isFolder: false,
isRecord: false,
dataStatus: 0,
isFetching: false,
update: jasmine.createSpy(),
fetched: Promise.resolve(true),
}) as any;

describe('FileListItemComponent', () => {
let component: FileListItemComponent;
let fixture: ComponentFixture<FileListItemComponent>;
Expand Down Expand Up @@ -78,7 +94,12 @@ describe('FileListItemComponent', () => {
mockFeatureFlagService.isEnabled.and.returnValue(false);

await TestBed.configureTestingModule({
imports: [MockItemTypeIconPipe, MockPrDatePipe, MockPrConstantsPipe],
imports: [
MockItemTypeIconPipe,
MockPrDatePipe,
MockPrConstantsPipe,
EdtfDateDisplayComponent,
],
declarations: [FileListItemComponent, GetThumbnailPipe],
providers: [
provideNoopAnimations(),
Expand Down Expand Up @@ -150,19 +171,7 @@ describe('FileListItemComponent', () => {
component = fixture.componentInstance;
editService = TestBed.inject(EditService);

component.item = {
displayDT: new Date().toISOString(),
displayName: 'Test Item',
archiveNbr: '123',
folder_linkId: '456',
type: '',
isFolder: false,
isRecord: false,
dataStatus: 0,
isFetching: false,
update: jasmine.createSpy(),
fetched: Promise.resolve(true),
} as any;
component.item = buildTestItem();

component.folderView = '' as any;
fixture.detectChanges();
Expand Down Expand Up @@ -581,30 +590,78 @@ describe('FileListItemComponent', () => {
mockFeatureFlagService.isEnabled.and.callFake(
(flag: string) => flag === 'edtf-date',
);
// The flag is read in the constructor, so the fixture has to be
// built again for the new value to take.
fixture = TestBed.createComponent(FileListItemComponent);
component = fixture.componentInstance;
component.item = buildTestItem();
component.folderView = '' as any;
});

it('should not fall back to displayDT when displayTime is missing', () => {
component.item.displayTime = undefined;
component.item.displayDT = '2023-01-01T00:00:00.000Z';
fixture.detectChanges();

expect(component.startDisplayTime).toBe('');
});

it('should show nothing when displayTime was explicitly cleared', () => {
component.item.displayTime = null;
component.item.displayDT = '2023-01-01T00:00:00.000Z';
fixture.detectChanges();

expect(component.startDisplayTime).toBe('');
});

it('should still show the displayTime start date', () => {
component.item.displayTime = '2020-06-10/2026-06-15';
component.item.displayDT = '2023-01-01T00:00:00.000Z';
fixture.detectChanges();

expect(component.startDisplayTime).toBe('2020-06-10');
});

it('should render the public-archive date from the EDTF value', async () => {
component.item.displayTime = '1985-04';
component.item.displayDT = '2023-01-01T00:00:00.000Z';

await component.ngOnInit();

expect(component.date).toBe('April 1985');
});

it('should leave the public-archive date empty when there is no EDTF value', async () => {
component.item.displayTime = undefined;
component.item.displayDT = '2023-01-01T00:00:00.000Z';

await component.ngOnInit();

expect(component.date).toBe('');
});

it('should never put an unreadable value in the public-archive date', async () => {
component.item.displayTime = 'XXXX-XX-XX';

await component.ngOnInit();

expect(component.date).toBe('Unknown');
expect(component.date).not.toContain('Invalid');
expect(component.date).not.toContain('NaN');
});
});

describe('with the edtf-date feature flag disabled', () => {
it('should keep falling back to displayDT', () => {
component.item.displayTime = undefined;
component.item.displayDT = '2023-01-01T00:00:00.000Z';

expect(component.startDisplayTime).toBe('2023-01-01T00:00:00.000Z');
});

it('should not print Invalid Date for an EDTF value it cannot read', async () => {
component.item.displayTime = '198X';

await component.ngOnInit();

expect(component.date).toBe('');
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {
import { DataStatus } from '@models/data-status.enum';
import { EditService } from '@core/services/edit/edit.service';
import { EdtfService } from '@shared/services/edtf-service/edtf.service';
import { EdtfDisplayService } from '@shared/services/edtf-service/edtf-display.service';
import { FeatureFlagService } from '@root/app/feature-flag/services/feature-flag.service';
import {
RecordResponse,
Expand Down Expand Up @@ -206,6 +207,7 @@ export class FileListItemComponent
public canEdit = true;
public isZip = false;
public date: string = '';
public showEdtfDate = false;
public isUnlistedShare = false;
public recordThumbnailUrl: string | undefined;

Expand Down Expand Up @@ -251,29 +253,39 @@ export class FileListItemComponent
@Inject(DOCUMENT) private document: Document,
private shareLinksService: ShareLinksService,
private edtfService: EdtfService,
private edtfDisplayService: EdtfDisplayService,
private featureFlagService: FeatureFlagService,
) {}
) {
this.showEdtfDate = this.featureFlagService.isEnabled('edtf-date');
}

get startDisplayTime(): string {
const edtfStartDate = this.edtfService.getEdtfIntervalStartDate(
this.item.displayTime,
);

// Once the edtf-date UI ships, displayTime is authoritative (a null
// value means the user cleared the date, so nothing is shown). Until
// then, items may only have displayDT populated, so keep the fallback.
if (this.featureFlagService.isEnabled('edtf-date')) {
if (this.showEdtfDate) {
return edtfStartDate;
}

return edtfStartDate || this.item.displayDT;
}

private getPublicArchiveDate(): string {
if (this.showEdtfDate) {
return this.edtfDisplayService.formatToPlainText(this.item.displayTime);
}

const legacyDate = new Date(this.startDisplayTime);
return Number.isNaN(legacyDate.getTime())
? ''
: getFormattedDate(legacyDate);
}

async ngOnInit() {
this.isInSharePreview =
this.router.routerState.snapshot.url.includes('/share/');
const date = new Date(this.startDisplayTime);
this.date = getFormattedDate(date);
this.date = this.getPublicArchiveDate();

// Only a share preview can be an unlisted share: the token that decides it
// is set by SharePreviewComponent and cleared when it is destroyed, so
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
DateQualifierFlags,
DEFAULT_DATE_QUALIFIERS,
} from '@shared/services/edtf-service/edtf.service';
import { EdtfDisplayService } from '@shared/services/edtf-service/edtf-display.service';
import { DatepickerInputComponent } from '@shared/components/datepicker-input/datepicker-input.component';
import { TimepickerInputComponent } from '@shared/components/timepicker-input/timepicker-input.component';

Expand Down Expand Up @@ -61,7 +62,10 @@ export class SidebarDatePickerComponent implements OnInit, OnChanges {
@ViewChild('sidebarDatePickerContainer')
container?: ElementRef<HTMLElement>;

constructor(private readonly edtfService: EdtfService) {}
constructor(
private readonly edtfService: EdtfService,
private readonly edtfDisplayService: EdtfDisplayService,
) {}

isDropdownOpen = signal(false);

Expand Down Expand Up @@ -94,7 +98,7 @@ export class SidebarDatePickerComponent implements OnInit, OnChanges {
formattedStartDate = computed(() => {
if (this._qualifiers().unknown) return 'Unknown';
if (this._isOpenStart()) return '..';
return this.formatDate(this._date());
return this.edtfDisplayService.formatDateForDisplay(this._date());
});

formattedStartTime = computed(() => this.formatTime(this._time()));
Expand All @@ -119,7 +123,7 @@ export class SidebarDatePickerComponent implements OnInit, OnChanges {
formattedEndDate = computed(() => {
if (this._endQualifiers().unknown) return 'Unknown';
if (this._isOpenEnd()) return '..';
return this.formatDate(this._endDate());
return this.edtfDisplayService.formatDateForDisplay(this._endDate());
});

formattedEndTime = computed(() => this.formatTime(this._endTime()));
Expand Down
2 changes: 2 additions & 0 deletions src/app/file-browser/file-browser-components.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
FaIconLibrary,
} from '@fortawesome/angular-fontawesome';
import { faFileArchive } from '@fortawesome/free-solid-svg-icons';
import { EdtfDateDisplayComponent } from '@shared/components/edtf-date-display/edtf-date-display.component';
import { FolderViewComponent } from './components/folder-view/folder-view.component';
import { PublishComponent } from './components/publish/publish.component';
import { FolderDescriptionComponent } from './components/folder-description/folder-description.component';
Expand All @@ -40,6 +41,7 @@ import { SidebarLocationComponent } from './components/sidebar-location/sidebar-
FontAwesomeModule,
SidebarDatePickerComponent,
SidebarLocationComponent,
EdtfDateDisplayComponent,
],
exports: [
FileListComponent,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<span
class="value"
[ngbTooltip]="fullValue"
[disableTooltip]="!tooltip()"
container="body"
tooltipClass="pr-tooltip edtf-date-tooltip"
>
<span class="part">
@for (segment of dateSegments(); track $index) {
<span [class.annotation]="segment.isAnnotation">{{ segment.text }}</span>
}
@if (hasTime()) {
<span class="separator">&bull;</span>
}
@if (tooltip() && !dateEndSegments().length) {
<i class="material-icons more-info">info</i>
}
</span>
@if (dateEndSegments().length) {
<span class="part">
@for (segment of dateEndSegments(); track $index) {
<span [class.annotation]="segment.isAnnotation">{{
segment.text
}}</span>
}
@if (tooltip()) {
<i class="material-icons more-info">info</i>
}
</span>
}
@if (hasTime()) {
<span class="part" @ngIfFadeInAnimation>
@for (segment of timeSegments(); track $index) {
<span [class.annotation]="segment.isAnnotation">{{
segment.text
}}</span>
}
</span>
}
</span>

<ng-template #fullValue>
@if (tooltip(); as lines) {
<div class="tooltip-line">
<span class="label">From</span>{{ lines.from }}
</div>
<div class="tooltip-line"><span class="label">To</span>{{ lines.to }}</div>
}
</ng-template>
Loading
Loading