mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-09-26 01:12:43 -05:00
Fix/refactor: remove doc observables, fix username async (#8908)
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'
|
||||
import { provideHttpClientTesting } from '@angular/common/http/testing'
|
||||
import {
|
||||
ComponentFixture,
|
||||
TestBed,
|
||||
@@ -51,7 +53,11 @@ describe('FilterableDropdownComponent & FilterableDropdownSelectionModel', () =>
|
||||
|
||||
beforeEach(async () => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [FilterPipe],
|
||||
providers: [
|
||||
FilterPipe,
|
||||
provideHttpClient(withInterceptorsFromDi()),
|
||||
provideHttpClientTesting(),
|
||||
],
|
||||
imports: [NgxBootstrapIconsModule.pick(allIcons)],
|
||||
}).compileComponents()
|
||||
|
||||
|
@@ -1,3 +1,5 @@
|
||||
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'
|
||||
import { provideHttpClientTesting } from '@angular/common/http/testing'
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing'
|
||||
import { Tag } from 'src/app/data/tag'
|
||||
import { TagComponent } from '../../tag/tag.component'
|
||||
@@ -12,7 +14,10 @@ describe('ToggleableDropdownButtonComponent', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [],
|
||||
providers: [
|
||||
provideHttpClient(withInterceptorsFromDi()),
|
||||
provideHttpClientTesting(),
|
||||
],
|
||||
imports: [ToggleableDropdownButtonComponent, TagComponent],
|
||||
}).compileComponents()
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
@if (tag !== undefined) {
|
||||
@if (tag) {
|
||||
@if (!clickable) {
|
||||
<span class="badge" [style.background]="tag.color" [style.color]="tag.text_color">{{tag.name}}</span>
|
||||
}
|
||||
|
@@ -1,6 +1,11 @@
|
||||
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'
|
||||
import { provideHttpClientTesting } from '@angular/common/http/testing'
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing'
|
||||
import { By } from '@angular/platform-browser'
|
||||
import { of } from 'rxjs'
|
||||
import { Tag } from 'src/app/data/tag'
|
||||
import { PermissionsService } from 'src/app/services/permissions.service'
|
||||
import { TagService } from 'src/app/services/rest/tag.service'
|
||||
import { TagComponent } from './tag.component'
|
||||
|
||||
const tag: Tag = {
|
||||
@@ -12,13 +17,20 @@ const tag: Tag = {
|
||||
describe('TagComponent', () => {
|
||||
let component: TagComponent
|
||||
let fixture: ComponentFixture<TagComponent>
|
||||
let permissionsService: PermissionsService
|
||||
let tagService: TagService
|
||||
|
||||
beforeEach(async () => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [],
|
||||
providers: [
|
||||
provideHttpClient(withInterceptorsFromDi()),
|
||||
provideHttpClientTesting(),
|
||||
],
|
||||
imports: [TagComponent],
|
||||
}).compileComponents()
|
||||
|
||||
permissionsService = TestBed.inject(PermissionsService)
|
||||
tagService = TestBed.inject(TagService)
|
||||
fixture = TestBed.createComponent(TagComponent)
|
||||
component = fixture.componentInstance
|
||||
fixture.detectChanges()
|
||||
@@ -47,4 +59,13 @@ describe('TagComponent', () => {
|
||||
fixture.detectChanges()
|
||||
expect(fixture.debugElement.query(By.css('a.badge'))).not.toBeNull()
|
||||
})
|
||||
|
||||
it('should support retrieving tag by ID', () => {
|
||||
jest.spyOn(permissionsService, 'currentUserCan').mockReturnValue(true)
|
||||
const getCachedSpy = jest.spyOn(tagService, 'getCached')
|
||||
getCachedSpy.mockReturnValue(of(tag))
|
||||
component.tagID = 1
|
||||
expect(getCachedSpy).toHaveBeenCalledWith(1)
|
||||
expect(component.tag).toEqual(tag)
|
||||
})
|
||||
})
|
||||
|
@@ -1,5 +1,11 @@
|
||||
import { Component, Input } from '@angular/core'
|
||||
import { Tag } from 'src/app/data/tag'
|
||||
import {
|
||||
PermissionAction,
|
||||
PermissionsService,
|
||||
PermissionType,
|
||||
} from 'src/app/services/permissions.service'
|
||||
import { TagService } from 'src/app/services/rest/tag.service'
|
||||
|
||||
@Component({
|
||||
selector: 'pngx-tag',
|
||||
@@ -7,10 +13,39 @@ import { Tag } from 'src/app/data/tag'
|
||||
styleUrls: ['./tag.component.scss'],
|
||||
})
|
||||
export class TagComponent {
|
||||
constructor() {}
|
||||
private _tag: Tag
|
||||
private _tagID: number
|
||||
|
||||
constructor(
|
||||
private permissionsService: PermissionsService,
|
||||
private tagService: TagService
|
||||
) {}
|
||||
|
||||
@Input()
|
||||
tag: Tag
|
||||
public set tag(tag: Tag) {
|
||||
this._tag = tag
|
||||
}
|
||||
|
||||
public get tag(): Tag {
|
||||
return this._tag
|
||||
}
|
||||
|
||||
@Input()
|
||||
set tagID(tagID: number) {
|
||||
if (tagID !== this._tagID) {
|
||||
this._tagID = tagID
|
||||
if (
|
||||
this.permissionsService.currentUserCan(
|
||||
PermissionAction.View,
|
||||
PermissionType.Tag
|
||||
)
|
||||
) {
|
||||
this.tagService.getCached(this._tagID).subscribe((tag) => {
|
||||
this.tag = tag
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Input()
|
||||
linkTitle: string = ''
|
||||
|
@@ -50,27 +50,27 @@
|
||||
}
|
||||
@case (DisplayField.CORRESPONDENT) {
|
||||
@if (doc.correspondent) {
|
||||
<a class="btn-link text-dark text-decoration-none" type="button" (click)="clickCorrespondent(doc.correspondent, $event)" title="Filter by correspondent" i18n-title>{{(doc.correspondent$ | async)?.name}}</a>
|
||||
<a class="btn-link text-dark text-decoration-none" type="button" (click)="clickCorrespondent(doc.correspondent, $event)" title="Filter by correspondent" i18n-title>{{doc.correspondent | correspondentName | async}}</a>
|
||||
}
|
||||
}
|
||||
@case (DisplayField.TAGS) {
|
||||
@for (t of doc.tags$ | async; track t) {
|
||||
<pngx-tag [tag]="t" class="ms-1" (click)="clickTag(t.id, $event)" [clickable]="true" linkTitle="Filter by tag" i18n-title></pngx-tag>
|
||||
@for (tagID of doc.tags; track tagID) {
|
||||
<pngx-tag [tagID]="tagID" class="ms-1" (click)="clickTag(tagID, $event)" [clickable]="true" linkTitle="Filter by tag" i18n-title></pngx-tag>
|
||||
}
|
||||
}
|
||||
@case (DisplayField.DOCUMENT_TYPE) {
|
||||
@if (doc.document_type) {
|
||||
<a class="btn-link text-dark text-decoration-none" type="button" (click)="clickDocType(doc.document_type, $event)" title="Filter by document type" i18n-title>{{(doc.document_type$ | async)?.name}}</a>
|
||||
<a class="btn-link text-dark text-decoration-none" type="button" (click)="clickDocType(doc.document_type, $event)" title="Filter by document type" i18n-title>{{doc.document_type | documentTypeName | async}}</a>
|
||||
}
|
||||
}
|
||||
@case (DisplayField.STORAGE_PATH) {
|
||||
@if (doc.storage_path) {
|
||||
<a class="btn-link text-dark text-decoration-none" type="button" (click)="clickStoragePath(doc.storage_path, $event)" title="Filter by storage path" i18n-title>{{(doc.storage_path$ | async)?.name}}</a>
|
||||
<a class="btn-link text-dark text-decoration-none" type="button" (click)="clickStoragePath(doc.storage_path, $event)" title="Filter by storage path" i18n-title>{{doc.storage_path | storagePathName | async}}</a>
|
||||
}
|
||||
}
|
||||
@case (DisplayField.OWNER) {
|
||||
@if (doc.owner) {
|
||||
<a class="btn-link text-dark text-decoration-none" type="button" (click)="clickOwner(doc.owner, $event)" title="Filter by owner" i18n-title>{{doc.owner | username}}</a>
|
||||
<a class="btn-link text-dark text-decoration-none" type="button" (click)="clickOwner(doc.owner, $event)" title="Filter by owner" i18n-title>{{doc.owner | username | async}}</a>
|
||||
}
|
||||
}
|
||||
@case (DisplayField.ASN) {
|
||||
|
@@ -36,8 +36,11 @@ import {
|
||||
} from 'src/app/data/filter-rule-type'
|
||||
import { SavedView } from 'src/app/data/saved-view'
|
||||
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
||||
import { CorrespondentNamePipe } from 'src/app/pipes/correspondent-name.pipe'
|
||||
import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe'
|
||||
import { DocumentTitlePipe } from 'src/app/pipes/document-title.pipe'
|
||||
import { DocumentTypeNamePipe } from 'src/app/pipes/document-type-name.pipe'
|
||||
import { StoragePathNamePipe } from 'src/app/pipes/storage-path-name.pipe'
|
||||
import { UsernamePipe } from 'src/app/pipes/username.pipe'
|
||||
import { ConsumerStatusService } from 'src/app/services/consumer-status.service'
|
||||
import { DocumentListViewService } from 'src/app/services/document-list-view.service'
|
||||
@@ -65,6 +68,9 @@ import { WidgetFrameComponent } from '../widget-frame/widget-frame.component'
|
||||
WidgetFrameComponent,
|
||||
IfPermissionsDirective,
|
||||
UsernamePipe,
|
||||
CorrespondentNamePipe,
|
||||
DocumentTypeNamePipe,
|
||||
StoragePathNamePipe,
|
||||
AsyncPipe,
|
||||
DocumentTitlePipe,
|
||||
CustomDatePipe,
|
||||
|
@@ -22,9 +22,9 @@
|
||||
@if (document) {
|
||||
@if (displayFields.includes(DisplayField.CORRESPONDENT) && document.correspondent) {
|
||||
@if (clickCorrespondent.observers.length ) {
|
||||
<a title="Filter by correspondent" i18n-title (click)="clickCorrespondent.emit(document.correspondent);$event.stopPropagation()" class="fw-bold btn-link">{{(document.correspondent$ | async)?.name}}</a>
|
||||
<a title="Filter by correspondent" i18n-title (click)="clickCorrespondent.emit(document.correspondent);$event.stopPropagation()" class="fw-bold btn-link">{{document.correspondent | correspondentName | async}}</a>
|
||||
} @else {
|
||||
{{(document.correspondent$ | async)?.name}}
|
||||
{{document.correspondent | correspondentName | async}}
|
||||
}
|
||||
@if (displayFields.includes(DisplayField.TITLE)) {:}
|
||||
}
|
||||
@@ -32,8 +32,8 @@
|
||||
{{document.title | documentTitle}}
|
||||
}
|
||||
@if (displayFields.includes(DisplayField.TAGS)) {
|
||||
@for (t of document.tags$ | async; track t) {
|
||||
<pngx-tag [tag]="t" linkTitle="Filter by tag" i18n-linkTitle class="ms-1" (click)="clickTag.emit(t.id);$event.stopPropagation()" [clickable]="clickTag.observers.length"></pngx-tag>
|
||||
@for (tagID of document.tags; track t) {
|
||||
<pngx-tag [tagID]="tagID" linkTitle="Filter by tag" i18n-linkTitle class="ms-1" (click)="clickTag.emit(tagID);$event.stopPropagation()" [clickable]="clickTag.observers.length"></pngx-tag>
|
||||
}
|
||||
}
|
||||
} @else {
|
||||
@@ -95,13 +95,13 @@
|
||||
@if (displayFields.includes(DisplayField.DOCUMENT_TYPE) && document.document_type) {
|
||||
<button type="button" class="list-group-item btn btn-sm bg-light text-dark p-1 border-0 me-2 d-flex align-items-center" title="Filter by document type" i18n-title
|
||||
(click)="clickDocumentType.emit(document.document_type);$event.stopPropagation()">
|
||||
<i-bs width=".9em" height=".9em" class="me-2 text-muted" name="file-earmark"></i-bs><small>{{(document.document_type$ | async)?.name}}</small>
|
||||
<i-bs width=".9em" height=".9em" class="me-2 text-muted" name="file-earmark"></i-bs><small>{{document.document_type | documentTypeName | async}}</small>
|
||||
</button>
|
||||
}
|
||||
@if (displayFields.includes(DisplayField.STORAGE_PATH) && document.storage_path) {
|
||||
<button type="button" class="list-group-item btn btn-sm bg-light text-dark p-1 border-0 me-2 d-flex align-items-center" title="Filter by storage path" i18n-title
|
||||
(click)="clickStoragePath.emit(document.storage_path);$event.stopPropagation()">
|
||||
<i-bs width=".9em" height=".9em" class="me-2 text-muted" name="archive"></i-bs><small>{{(document.storage_path$ | async)?.name}}</small>
|
||||
<i-bs width=".9em" height=".9em" class="me-2 text-muted" name="archive"></i-bs><small>{{document.storage_path | storagePathName | async}}</small>
|
||||
</button>
|
||||
}
|
||||
@if (displayFields.includes(DisplayField.ASN) && document.archive_serial_number | isNumber) {
|
||||
@@ -136,7 +136,7 @@
|
||||
}
|
||||
@if (displayFields.includes(DisplayField.OWNER) && document.owner && document.owner !== settingsService.currentUser.id) {
|
||||
<div class="list-group-item bg-light text-dark p-1 border-0 d-flex align-items-center">
|
||||
<i-bs width=".9em" height=".9em" class="me-2 text-muted" name="person-fill-lock"></i-bs><small>{{document.owner | username}}</small>
|
||||
<i-bs width=".9em" height=".9em" class="me-2 text-muted" name="person-fill-lock"></i-bs><small>{{document.owner | username | async}}</small>
|
||||
</div>
|
||||
}
|
||||
@if (displayFields.includes(DisplayField.SHARED) && document.is_shared_by_requester) {
|
||||
|
@@ -21,9 +21,12 @@ import {
|
||||
} from 'src/app/data/document'
|
||||
import { SETTINGS_KEYS } from 'src/app/data/ui-settings'
|
||||
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
||||
import { CorrespondentNamePipe } from 'src/app/pipes/correspondent-name.pipe'
|
||||
import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe'
|
||||
import { DocumentTitlePipe } from 'src/app/pipes/document-title.pipe'
|
||||
import { DocumentTypeNamePipe } from 'src/app/pipes/document-type-name.pipe'
|
||||
import { IsNumberPipe } from 'src/app/pipes/is-number.pipe'
|
||||
import { StoragePathNamePipe } from 'src/app/pipes/storage-path-name.pipe'
|
||||
import { UsernamePipe } from 'src/app/pipes/username.pipe'
|
||||
import { DocumentService } from 'src/app/services/rest/document.service'
|
||||
import { SettingsService } from 'src/app/services/settings.service'
|
||||
@@ -44,6 +47,9 @@ import { LoadingComponentWithPermissions } from '../../loading-component/loading
|
||||
CustomFieldDisplayComponent,
|
||||
AsyncPipe,
|
||||
UsernamePipe,
|
||||
CorrespondentNamePipe,
|
||||
DocumentTypeNamePipe,
|
||||
StoragePathNamePipe,
|
||||
IfPermissionsDirective,
|
||||
CustomDatePipe,
|
||||
RouterModule,
|
||||
|
@@ -16,8 +16,8 @@
|
||||
|
||||
@if (document && displayFields?.includes(DisplayField.TAGS)) {
|
||||
<div class="tags d-flex flex-column text-end position-absolute me-1 fs-6">
|
||||
@for (t of getTagsLimited$() | async; track t) {
|
||||
<pngx-tag [tag]="t" (click)="clickTag.emit(t.id);$event.stopPropagation()" [clickable]="true" linkTitle="Toggle tag filter" i18n-linkTitle></pngx-tag>
|
||||
@for (tagID of tagIDs; track tagID) {
|
||||
<pngx-tag [tagID]="tagID" (click)="clickTag.emit(tagID);$event.stopPropagation()" [clickable]="true" linkTitle="Toggle tag filter" i18n-linkTitle></pngx-tag>
|
||||
}
|
||||
@if (moreTags) {
|
||||
<div>
|
||||
@@ -40,7 +40,7 @@
|
||||
<p class="card-text">
|
||||
@if (document) {
|
||||
@if (displayFields.includes(DisplayField.CORRESPONDENT) && document.correspondent) {
|
||||
<a title="Toggle correspondent filter" i18n-title (click)="clickCorrespondent.emit(document.correspondent);$event.stopPropagation()" class="fw-bold btn-link">{{(document.correspondent$ | async)?.name ?? privateName}}</a>
|
||||
<a title="Toggle correspondent filter" i18n-title (click)="clickCorrespondent.emit(document.correspondent);$event.stopPropagation()" class="fw-bold btn-link">{{document.correspondent | correspondentName | async}}</a>
|
||||
@if (displayFields.includes(DisplayField.TITLE)) {:}
|
||||
}
|
||||
@if (displayFields.includes(DisplayField.TITLE)) {
|
||||
@@ -59,14 +59,14 @@
|
||||
<button type="button" class="list-group-item list-group-item-action bg-transparent ps-0 p-1 border-0" title="Toggle document type filter" i18n-title
|
||||
(click)="clickDocumentType.emit(document.document_type);$event.stopPropagation()">
|
||||
<i-bs width="1em" height="1em" class="me-2 text-muted" name="file-earmark"></i-bs>
|
||||
<small>{{(document.document_type$ | async)?.name ?? privateName}}</small>
|
||||
<small>{{document.document_type | documentTypeName | async}}</small>
|
||||
</button>
|
||||
}
|
||||
@if (displayFields.includes(DisplayField.STORAGE_PATH) && document.storage_path) {
|
||||
<button type="button" class="list-group-item list-group-item-action bg-transparent ps-0 p-1 border-0" title="Toggle storage path filter" i18n-title
|
||||
(click)="clickStoragePath.emit(document.storage_path);$event.stopPropagation()">
|
||||
<i-bs width="1em" height="1em" class="me-2 text-muted" name="folder"></i-bs>
|
||||
<small>{{(document.storage_path$ | async)?.name ?? privateName}}</small>
|
||||
<small>{{document.storage_path | storagePathName | async}}</small>
|
||||
</button>
|
||||
}
|
||||
@if (displayFields.includes(DisplayField.CREATED)) {
|
||||
@@ -116,7 +116,7 @@
|
||||
@if (displayFields.includes(DisplayField.OWNER) && document.owner && document.owner !== settingsService.currentUser.id) {
|
||||
<div class="ps-0 p-1">
|
||||
<i-bs width="1em" height="1em" class="me-2 text-muted" name="person-fill-lock"></i-bs>
|
||||
<small>{{document.owner | username}}</small>
|
||||
<small>{{document.owner | username | async}}</small>
|
||||
</div>
|
||||
}
|
||||
@if (displayFields.includes(DisplayField.SHARED) && document.is_shared_by_requester) {
|
||||
|
@@ -5,8 +5,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'
|
||||
import { By } from '@angular/platform-browser'
|
||||
import { RouterTestingModule } from '@angular/router/testing'
|
||||
import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons'
|
||||
import { of } from 'rxjs'
|
||||
import { Tag } from 'src/app/data/tag'
|
||||
import { TagComponent } from '../../common/tag/tag.component'
|
||||
import { DocumentCardSmallComponent } from './document-card-small.component'
|
||||
|
||||
@@ -24,16 +22,6 @@ const doc = {
|
||||
note: 'This is some note content bananas',
|
||||
},
|
||||
],
|
||||
tags$: of([
|
||||
{ id: 1, name: 'Tag1' },
|
||||
{ id: 2, name: 'Tag2' },
|
||||
{ id: 3, name: 'Tag3' },
|
||||
{ id: 4, name: 'Tag4' },
|
||||
{ id: 5, name: 'Tag5' },
|
||||
{ id: 6, name: 'Tag6' },
|
||||
{ id: 7, name: 'Tag7' },
|
||||
{ id: 8, name: 'Tag8' },
|
||||
]),
|
||||
content:
|
||||
'Cupcake ipsum dolor sit amet ice cream. Donut shortbread cheesecake caramels tiramisu pastry caramels chocolate bar. Tart tootsie roll muffin icing cotton candy topping sweet roll. Pie lollipop dragée sesame snaps donut tart pudding. Oat cake apple pie danish danish candy canes. Shortbread candy canes sesame snaps muffin tiramisu marshmallow chocolate bar halvah. Cake lemon drops candy apple pie carrot cake bonbon halvah pastry gummi bears. Sweet roll candy ice cream sesame snaps marzipan cookie ice cream. Cake cheesecake apple pie muffin candy toffee lollipop. Carrot cake oat cake cookie biscuit cupcake cake marshmallow. Sweet roll jujubes carrot cake cheesecake cake candy canes sweet roll gingerbread jelly beans. Apple pie sugar plum oat cake halvah cake. Pie oat cake chocolate cake cookie gingerbread marzipan. Lemon drops cheesecake lollipop danish marzipan candy.',
|
||||
}
|
||||
@@ -80,7 +68,6 @@ describe('DocumentCardSmallComponent', () => {
|
||||
fixture.debugElement.queryAll(By.directive(TagComponent))
|
||||
).toHaveLength(5)
|
||||
component.document.tags = [1, 2]
|
||||
component.document.tags$ = of([{ id: 1 } as Tag, { id: 2 } as Tag])
|
||||
fixture.detectChanges()
|
||||
expect(
|
||||
fixture.debugElement.queryAll(By.directive(TagComponent))
|
||||
|
@@ -14,7 +14,7 @@ import {
|
||||
} from '@ng-bootstrap/ng-bootstrap'
|
||||
import { NgxBootstrapIconsModule } from 'ngx-bootstrap-icons'
|
||||
import { of } from 'rxjs'
|
||||
import { delay, map } from 'rxjs/operators'
|
||||
import { delay } from 'rxjs/operators'
|
||||
import {
|
||||
DEFAULT_DISPLAY_FIELDS,
|
||||
DisplayField,
|
||||
@@ -22,9 +22,12 @@ import {
|
||||
} from 'src/app/data/document'
|
||||
import { SETTINGS_KEYS } from 'src/app/data/ui-settings'
|
||||
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
||||
import { CorrespondentNamePipe } from 'src/app/pipes/correspondent-name.pipe'
|
||||
import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe'
|
||||
import { DocumentTitlePipe } from 'src/app/pipes/document-title.pipe'
|
||||
import { DocumentTypeNamePipe } from 'src/app/pipes/document-type-name.pipe'
|
||||
import { IsNumberPipe } from 'src/app/pipes/is-number.pipe'
|
||||
import { StoragePathNamePipe } from 'src/app/pipes/storage-path-name.pipe'
|
||||
import { UsernamePipe } from 'src/app/pipes/username.pipe'
|
||||
import { DocumentService } from 'src/app/services/rest/document.service'
|
||||
import { SettingsService } from 'src/app/services/settings.service'
|
||||
@@ -45,6 +48,9 @@ import { LoadingComponentWithPermissions } from '../../loading-component/loading
|
||||
CustomFieldDisplayComponent,
|
||||
AsyncPipe,
|
||||
UsernamePipe,
|
||||
CorrespondentNamePipe,
|
||||
DocumentTypeNamePipe,
|
||||
StoragePathNamePipe,
|
||||
IfPermissionsDirective,
|
||||
CustomDatePipe,
|
||||
RouterModule,
|
||||
@@ -117,22 +123,14 @@ export class DocumentCardSmallComponent
|
||||
return this.documentService.getDownloadUrl(this.document.id)
|
||||
}
|
||||
|
||||
get privateName() {
|
||||
return $localize`Private`
|
||||
}
|
||||
|
||||
getTagsLimited$() {
|
||||
get tagIDs() {
|
||||
const limit = this.document.notes.length > 0 ? 6 : 7
|
||||
return this.document.tags$?.pipe(
|
||||
map((tags) => {
|
||||
if (tags.length > limit) {
|
||||
this.moreTags = tags.length - (limit - 1)
|
||||
return tags.slice(0, limit - 1)
|
||||
} else {
|
||||
return tags
|
||||
}
|
||||
})
|
||||
)
|
||||
if (this.document.tags.length > limit) {
|
||||
this.moreTags = this.document.tags.length - (limit - 1)
|
||||
return this.document.tags.slice(0, limit - 1)
|
||||
} else {
|
||||
return this.document.tags
|
||||
}
|
||||
}
|
||||
|
||||
mouseLeaveCard() {
|
||||
|
@@ -295,7 +295,7 @@
|
||||
@if (activeDisplayFields.includes(DisplayField.CORRESPONDENT) && permissionService.currentUserCan(PermissionAction.View, PermissionType.Correspondent)) {
|
||||
<td class="">
|
||||
@if (d.correspondent) {
|
||||
<a (click)="clickCorrespondent(d.correspondent);$event.stopPropagation()" title="Filter by correspondent" i18n-title>{{(d.correspondent$ | async)?.name}}</a>
|
||||
<a (click)="clickCorrespondent(d.correspondent);$event.stopPropagation()" title="Filter by correspondent" i18n-title>{{d.correspondent | correspondentName | async}}</a>
|
||||
}
|
||||
</td>
|
||||
}
|
||||
@@ -310,15 +310,15 @@
|
||||
</div>
|
||||
}
|
||||
@if (activeDisplayFields.includes(DisplayField.TAGS)) {
|
||||
@for (t of d.tags$ | async; track t) {
|
||||
<pngx-tag [tag]="t" class="ms-1" clickable="true" linkTitle="Filter by tag" i18n-linkTitle (click)="clickTag(t.id);$event.stopPropagation()"></pngx-tag>
|
||||
@for (tagID of d.tags; track t) {
|
||||
<pngx-tag [tagID]="tagID" class="ms-1" clickable="true" linkTitle="Filter by tag" i18n-linkTitle (click)="clickTag(tagID);$event.stopPropagation()"></pngx-tag>
|
||||
}
|
||||
}
|
||||
</td>
|
||||
}
|
||||
@if (activeDisplayFields.includes(DisplayField.OWNER) && permissionService.currentUserCan(PermissionAction.View, PermissionType.User)) {
|
||||
<td>
|
||||
{{d.owner | username}}
|
||||
{{d.owner | username | async}}
|
||||
</td>
|
||||
}
|
||||
@if (activeDisplayFields.includes(DisplayField.NOTES) && notesEnabled) {
|
||||
@@ -335,14 +335,14 @@
|
||||
@if (activeDisplayFields.includes(DisplayField.DOCUMENT_TYPE) && permissionService.currentUserCan(PermissionAction.View, PermissionType.DocumentType)) {
|
||||
<td class="">
|
||||
@if (d.document_type) {
|
||||
<a (click)="clickDocumentType(d.document_type);$event.stopPropagation()" title="Filter by document type" i18n-title>{{(d.document_type$ | async)?.name}}</a>
|
||||
<a (click)="clickDocumentType(d.document_type);$event.stopPropagation()" title="Filter by document type" i18n-title>{{d.document_type | documentTypeName | async}}</a>
|
||||
}
|
||||
</td>
|
||||
}
|
||||
@if (activeDisplayFields.includes(DisplayField.STORAGE_PATH) && permissionService.currentUserCan(PermissionAction.View, PermissionType.StoragePath)) {
|
||||
<td class="">
|
||||
@if (d.storage_path) {
|
||||
<a (click)="clickStoragePath(d.storage_path);$event.stopPropagation()" title="Filter by storage path" i18n-title>{{(d.storage_path$ | async)?.name}}</a>
|
||||
<a (click)="clickStoragePath(d.storage_path);$event.stopPropagation()" title="Filter by storage path" i18n-title>{{d.storage_path | storagePathName | async}}</a>
|
||||
}
|
||||
</td>
|
||||
}
|
||||
|
@@ -57,21 +57,21 @@ const docs: Document[] = [
|
||||
id: 1,
|
||||
title: 'Doc1',
|
||||
notes: [],
|
||||
tags$: new Subject(),
|
||||
tags: [],
|
||||
content: 'document content 1',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: 'Doc2',
|
||||
notes: [],
|
||||
tags$: new Subject(),
|
||||
tags: [],
|
||||
content: 'document content 2',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: 'Doc3',
|
||||
notes: [],
|
||||
tags$: new Subject(),
|
||||
tags: [],
|
||||
content: 'document content 3',
|
||||
},
|
||||
]
|
||||
@@ -650,7 +650,6 @@ describe('DocumentListComponent', () => {
|
||||
id: i + 1,
|
||||
title: `Doc${i + 1}`,
|
||||
notes: [],
|
||||
tags$: new Subject(),
|
||||
content: `document content ${i + 1}`,
|
||||
}))
|
||||
jest
|
||||
|
@@ -37,8 +37,11 @@ import {
|
||||
SortableDirective,
|
||||
SortEvent,
|
||||
} from 'src/app/directives/sortable.directive'
|
||||
import { CorrespondentNamePipe } from 'src/app/pipes/correspondent-name.pipe'
|
||||
import { CustomDatePipe } from 'src/app/pipes/custom-date.pipe'
|
||||
import { DocumentTitlePipe } from 'src/app/pipes/document-title.pipe'
|
||||
import { DocumentTypeNamePipe } from 'src/app/pipes/document-type-name.pipe'
|
||||
import { StoragePathNamePipe } from 'src/app/pipes/storage-path-name.pipe'
|
||||
import { UsernamePipe } from 'src/app/pipes/username.pipe'
|
||||
import { ConsumerStatusService } from 'src/app/services/consumer-status.service'
|
||||
import { DocumentListViewService } from 'src/app/services/document-list-view.service'
|
||||
@@ -81,6 +84,9 @@ import { SaveViewConfigDialogComponent } from './save-view-config-dialog/save-vi
|
||||
IfPermissionsDirective,
|
||||
SortableDirective,
|
||||
UsernamePipe,
|
||||
CorrespondentNamePipe,
|
||||
DocumentTypeNamePipe,
|
||||
StoragePathNamePipe,
|
||||
NgxBootstrapIconsModule,
|
||||
AsyncPipe,
|
||||
FormsModule,
|
||||
|
Reference in New Issue
Block a user