[#41849] added sorting to attachments list

- replaced angular trackBy with own sorting inside observable
- added file icons to attachment list items
- fixed clip icon usage
pull/10800/head
Eric Schubert 2 years ago
parent e533606265
commit bd3d627389
No known key found for this signature in database
GPG Key ID: 1D346C019BD4BAA2
  1. 3
      frontend/src/app/features/work-packages/components/wp-single-view-tabs/files-tab/op-files-tab.html
  2. 8
      frontend/src/app/shared/components/attachments/attachment-list/attachment-list-item.component.ts
  3. 3
      frontend/src/app/shared/components/attachments/attachment-list/attachment-list-item.html
  4. 20
      frontend/src/app/shared/components/attachments/attachment-list/attachment-list.component.ts
  5. 2
      frontend/src/app/shared/components/attachments/attachment-list/attachment-list.html
  6. 4
      frontend/src/app/shared/components/file-links/file-link-icons/file-link-list-item-icon.factory.ts
  7. 4
      frontend/src/app/shared/components/file-links/file-link-icons/icon-mappings.ts
  8. 4
      frontend/src/app/shared/components/file-links/file-link-list/file-link-list-item.component.ts
  9. 3
      frontend/src/global_styles/content/work_packages/tabs/_files.sass
  10. 1
      frontend/src/global_styles/content/work_packages/tabs/_tab_content.sass

@ -9,6 +9,7 @@
*ngIf="canViewFileLinks$ | async"
class="op-tab-content--header"
>
<span class="spot-icon spot-icon_attachment op-files-tab--icon_clip"></span>
<span class="op-tab-content--header-text" [textContent]="text.attachments.label"></span>
</div>
@ -23,7 +24,7 @@
class="op-tab-content--tab-section"
>
<div class=op-tab-content--header>
<span class="spot-icon spot-icon_nextcloud-circle"></span>
<span class="spot-icon spot-icon_nextcloud-circle op-files-tab--icon_nextcloud"></span>
<span class="op-tab-content--header-text" [textContent]="storage.name"></span>
</div>

@ -48,6 +48,10 @@ import { UntilDestroyedMixin } from 'core-app/shared/helpers/angular/until-destr
import { PrincipalsResourceService } from 'core-app/core/state/principals/principals.service';
import { PrincipalRendererService } from 'core-app/shared/components/principal/principal-renderer.service';
import idFromLink from 'core-app/features/hal/helpers/id-from-link';
import { IFileIcon } from 'core-app/shared/components/file-links/file-link-icons/icon-mappings';
import {
getIconForMimeType,
} from 'core-app/shared/components/file-links/file-link-icons/file-link-list-item-icon.factory';
@Component({
// eslint-disable-next-line @angular-eslint/component-selector
@ -80,6 +84,8 @@ export class AttachmentListItemComponent extends UntilDestroyedMixin implements
public timestampText:string;
public fileIcon:IFileIcon;
private viewInitialized$ = new BehaviorSubject<boolean>(false);
constructor(
@ -93,6 +99,8 @@ export class AttachmentListItemComponent extends UntilDestroyedMixin implements
}
ngOnInit():void {
this.fileIcon = getIconForMimeType(this.attachment.contentType);
const authorId = idFromLink(this.attachment._links.author.href);
if (!this.principalsResourceService.exists(authorId)) {

@ -6,7 +6,7 @@
(dragstart)="setDragData($event)"
>
<span
class="spot-icon spot-icon_attachment op-files-tab--icon_clip"
class="spot-icon spot-icon_{{fileIcon.icon}} op-files-tab--icon_{{fileIcon.clazz}}"
></span>
<span
@ -35,6 +35,7 @@
<span class="spot-icon spot-icon_user"></span>
</a>
<button
*ngIf="!!this.attachment._links.delete"
class="spot-link"
[title]="deleteIconTitle"
(click)="confirmRemoveAttachment($event)"

@ -32,14 +32,14 @@ import {
Input,
OnInit,
} from '@angular/core';
import { trackByProperty } from 'core-app/shared/helpers/angular/tracking-functions';
import { map, tap } from 'rxjs/operators';
import { Observable } from 'rxjs';
import { HalResource } from 'core-app/features/hal/resources/hal-resource';
import { IAttachment } from 'core-app/core/state/attachments/attachment.model';
import { TimezoneService } from 'core-app/core/datetime/timezone.service';
import { UntilDestroyedMixin } from 'core-app/shared/helpers/angular/until-destroyed.mixin';
import { AttachmentsResourceService } from 'core-app/core/state/attachments/attachments.service';
import { tap } from 'rxjs/operators';
import isNewResource from 'core-app/features/hal/helpers/is-new-resource';
import { Observable } from 'rxjs';
@Component({
selector: 'op-attachment-list',
@ -49,8 +49,6 @@ import { Observable } from 'rxjs';
export class AttachmentListComponent extends UntilDestroyedMixin implements OnInit {
@Input() public resource:HalResource;
trackByFileName = trackByProperty('fileName');
$attachments:Observable<IAttachment[]>;
private get attachmentsSelfLink():string {
@ -62,7 +60,10 @@ export class AttachmentListComponent extends UntilDestroyedMixin implements OnIn
return isNewResource(this.resource) ? 'new' : this.attachmentsSelfLink;
}
constructor(private readonly attachmentsResourceService:AttachmentsResourceService) {
constructor(
private readonly timezoneService:TimezoneService,
private readonly attachmentsResourceService:AttachmentsResourceService,
) {
super();
}
@ -72,11 +73,18 @@ export class AttachmentListComponent extends UntilDestroyedMixin implements OnIn
this.attachmentsResourceService.requireCollection(this.attachmentsSelfLink);
}
const compareCreatedAtTimestamps = (a:IAttachment, b:IAttachment):number => {
const rightCreatedAt = this.timezoneService.parseDatetime(b.createdAt);
const leftCreatedAt = this.timezoneService.parseDatetime(a.createdAt);
return rightCreatedAt.isBefore(leftCreatedAt) ? -1 : 1;
};
this.$attachments = this
.attachmentsResourceService
.collection(this.collectionKey)
.pipe(
this.untilDestroyed(),
map((attachments) => attachments.sort(compareCreatedAtTimestamps)),
// store attachments for new resources directly into the resource. This way, the POST request to create the
// resource embeds the attachments and the backend reroutes the anonymous attachments to the resource.
tap((attachments) => {

@ -4,7 +4,7 @@
>
<ul class="spot-list spot-list_compact op-files-tab--file-list">
<li
*ngFor="let attachment of $attachments | async; trackBy:trackByFileName; let i = index;"
*ngFor="let attachment of $attachments | async; let i = index;"
op-attachment-list-item
class="spot-list--item op-files-tab--file-list-item"
data-qa-selector="op-attachment-list-item"

@ -28,10 +28,10 @@
import {
fileIconMappings,
IFileLinkListItemIcon,
IFileIcon,
} from 'core-app/shared/components/file-links/file-link-icons/icon-mappings';
export function getIconForMimeType(mimeType?:string):IFileLinkListItemIcon {
export function getIconForMimeType(mimeType?:string):IFileIcon {
if (mimeType && fileIconMappings[mimeType]) {
return fileIconMappings[mimeType];
}

@ -26,12 +26,12 @@
// See COPYRIGHT and LICENSE files for more details.
//++
export interface IFileLinkListItemIcon {
export interface IFileIcon {
icon:'image1'|'movie'|'file-text'|'export-pdf-descr'|'file-doc'|'file-sheet'|'file-presentation'|'folder'|'ticket'
clazz:'pdf'|'img'|'txt'|'doc'|'sheet'|'presentation'|'form'|'dir'|'mov'|'default'
}
export const fileIconMappings:Record<string, IFileLinkListItemIcon> = {
export const fileIconMappings:Record<string, IFileIcon> = {
'application/pdf': { icon: 'export-pdf-descr', clazz: 'pdf' },
'image/jpeg': { icon: 'image1', clazz: 'img' },

@ -45,7 +45,7 @@ import {
import { TimezoneService } from 'core-app/core/datetime/timezone.service';
import { I18nService } from 'core-app/core/i18n/i18n.service';
import { PrincipalRendererService } from 'core-app/shared/components/principal/principal-renderer.service';
import { IFileLinkListItemIcon } from 'core-app/shared/components/file-links/file-link-icons/icon-mappings';
import { IFileIcon } from 'core-app/shared/components/file-links/file-link-icons/icon-mappings';
@Component({
// eslint-disable-next-line @angular-eslint/component-selector
@ -68,7 +68,7 @@ export class FileLinkListItemComponent implements OnInit, AfterViewInit {
public infoTimestampText:string;
public fileLinkIcon:IFileLinkListItemIcon;
public fileLinkIcon:IFileIcon;
public text = {
title: {

@ -138,3 +138,6 @@
&_clip
color: #333333
&_nextcloud
color: #1A67A3

@ -54,4 +54,3 @@
width: $spot-spacing-1_5
height: $spot-spacing-1_5
margin-right: $spot-spacing-0-5
color: #1A67A3

Loading…
Cancel
Save