mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-12-29 13:48:09 -06:00
Compare commits
1 Commits
1cdd8d9ba8
...
feature-co
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ea2f56925 |
1
.github/workflows/repo-maintenance.yml
vendored
1
.github/workflows/repo-maintenance.yml
vendored
@@ -241,7 +241,6 @@ jobs:
|
|||||||
) {
|
) {
|
||||||
nodes {
|
nodes {
|
||||||
id,
|
id,
|
||||||
createdAt,
|
|
||||||
number,
|
number,
|
||||||
updatedAt,
|
updatedAt,
|
||||||
upvoteCount,
|
upvoteCount,
|
||||||
|
|||||||
@@ -2,11 +2,9 @@
|
|||||||
|
|
||||||
If you feel like contributing to the project, please do! Bug fixes and improvements are always welcome.
|
If you feel like contributing to the project, please do! Bug fixes and improvements are always welcome.
|
||||||
|
|
||||||
⚠️ Please note: Pull requests that implement a new feature or enhancement _should almost always target an existing feature request_ with evidence of community interest and discussion. This is in order to balance the work of implementing and maintaining new features / enhancements. Pull requests that are opened without meeting this requirement may not be merged.
|
|
||||||
|
|
||||||
If you want to implement something big:
|
If you want to implement something big:
|
||||||
|
|
||||||
- As above, please start with a discussion! Maybe something similar is already in development and we can make it happen together.
|
- Please start a discussion about that in the issues! Maybe something similar is already in development and we can make it happen together.
|
||||||
- When making additions to the project, consider if the majority of users will benefit from your change. If not, you're probably better of forking the project.
|
- When making additions to the project, consider if the majority of users will benefit from your change. If not, you're probably better of forking the project.
|
||||||
- Also consider if your change will get in the way of other users. A good change is a change that enhances the experience of some users who want that change and does not affect users who do not care about the change.
|
- Also consider if your change will get in the way of other users. A good change is a change that enhances the experience of some users who want that change and does not affect users who do not care about the change.
|
||||||
- Please see the [paperless-ngx merge process](#merging-prs) below.
|
- Please see the [paperless-ngx merge process](#merging-prs) below.
|
||||||
@@ -135,7 +133,7 @@ community members. That said, in an effort to keep the repository organized and
|
|||||||
- Issues, pull requests and discussions that are closed will be locked after 30 days of inactivity.
|
- Issues, pull requests and discussions that are closed will be locked after 30 days of inactivity.
|
||||||
- Discussions with a marked answer will be automatically closed.
|
- Discussions with a marked answer will be automatically closed.
|
||||||
- Discussions in the 'General' or 'Support' categories will be closed after 180 days of inactivity.
|
- Discussions in the 'General' or 'Support' categories will be closed after 180 days of inactivity.
|
||||||
- Feature requests that do not meet the following thresholds will be closed: 180 days of inactivity with less than 80 "up-votes", < 5 "up-votes" after 180 days, < 20 "up-votes" after 1 year or < 40 "up-votes" at 2 years.
|
- Feature requests that do not meet the following thresholds will be closed: 180 days of inactivity, < 5 "up-votes" after 180 days, < 20 "up-votes" after 1 year or < 80 "up-votes" at 2 years.
|
||||||
|
|
||||||
In all cases, threads can be re-opened by project maintainers and, of course, users can always create a new discussion for related concerns.
|
In all cases, threads can be re-opened by project maintainers and, of course, users can always create a new discussion for related concerns.
|
||||||
Finally, remember that all information remains searchable and 'closed' feature requests can still serve as inspiration for new features.
|
Finally, remember that all information remains searchable and 'closed' feature requests can still serve as inspiration for new features.
|
||||||
|
|||||||
@@ -1759,11 +1759,6 @@ started by the container.
|
|||||||
|
|
||||||
: Path to an image file in the /media/logo directory, must include 'logo', e.g. `/logo/Atari_logo.svg`
|
: Path to an image file in the /media/logo directory, must include 'logo', e.g. `/logo/Atari_logo.svg`
|
||||||
|
|
||||||
!!! note
|
|
||||||
|
|
||||||
The logo file will be viewable by anyone with access to the Paperless instance login page,
|
|
||||||
so consider your choice of logo carefully and removing exif data from images before uploading.
|
|
||||||
|
|
||||||
#### [`PAPERLESS_ENABLE_UPDATE_CHECK=<bool>`](#PAPERLESS_ENABLE_UPDATE_CHECK) {#PAPERLESS_ENABLE_UPDATE_CHECK}
|
#### [`PAPERLESS_ENABLE_UPDATE_CHECK=<bool>`](#PAPERLESS_ENABLE_UPDATE_CHECK) {#PAPERLESS_ENABLE_UPDATE_CHECK}
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
|
|||||||
@@ -166,10 +166,13 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="nav-group mt-3 mb-1">
|
<div class="nav-group mt-3 mb-1">
|
||||||
<h6 class="sidebar-heading px-3 text-muted">
|
<h6 class="sidebar-heading px-3 text-muted d-flex align-items-center">
|
||||||
<span i18n>Manage</span>
|
<span i18n>Manage</span>
|
||||||
|
<button class="btn btn-link p-2 py-0" (click)="manageCollapse.toggle()">
|
||||||
|
<i-bs width="0.9em" height="0.9em" [name]="isManageMenuCollapsed ? 'chevron-down' : 'chevron-up'"></i-bs>
|
||||||
|
</button>
|
||||||
</h6>
|
</h6>
|
||||||
<ul class="nav flex-column mb-2">
|
<ul class="nav flex-column mb-2" #manageCollapse="ngbCollapse" [(ngbCollapse)]="isManageMenuCollapsed">
|
||||||
<li class="nav-item app-link"
|
<li class="nav-item app-link"
|
||||||
*pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.Correspondent }">
|
*pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.Correspondent }">
|
||||||
<a class="nav-link" routerLink="correspondents" routerLinkActive="active" (click)="closeMenu()"
|
<a class="nav-link" routerLink="correspondents" routerLinkActive="active" (click)="closeMenu()"
|
||||||
@@ -243,117 +246,124 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="nav-group mt-auto mb-1">
|
<div class="nav-group mt-auto mb-1">
|
||||||
<h6 class="sidebar-heading px-3 pt-4 text-muted">
|
<h6 class="sidebar-heading px-3 pt-4 text-muted d-flex align-items-center">
|
||||||
<span i18n>Administration</span>
|
<span i18n>Administration</span>
|
||||||
|
<button class="btn btn-link p-2 py-0" (click)="adminCollapse.toggle()">
|
||||||
|
<i-bs width="0.9em" height="0.9em" [name]="isAdminMenuCollapsed ? 'chevron-down' : 'chevron-up'"></i-bs>
|
||||||
|
</button>
|
||||||
</h6>
|
</h6>
|
||||||
<ul class="nav flex-column mb-2">
|
<div class="mb-2">
|
||||||
<li class="nav-item app-link" *pngxIfPermissions="{ action: PermissionAction.Change, type: PermissionType.UISettings }"
|
<ul class="nav flex-column" #adminCollapse="ngbCollapse" [(ngbCollapse)]="isAdminMenuCollapsed">
|
||||||
tourAnchor="tour.settings">
|
<li class="nav-item app-link" *pngxIfPermissions="{ action: PermissionAction.Change, type: PermissionType.UISettings }"
|
||||||
<a class="nav-link" routerLink="settings" routerLinkActive="active" (click)="closeMenu()"
|
tourAnchor="tour.settings">
|
||||||
ngbPopover="Settings" i18n-ngbPopover [disablePopover]="!slimSidebarEnabled" placement="end"
|
<a class="nav-link" routerLink="settings" routerLinkActive="active" (click)="closeMenu()"
|
||||||
container="body" triggers="mouseenter:mouseleave" popoverClass="popover-slim">
|
ngbPopover="Settings" i18n-ngbPopover [disablePopover]="!slimSidebarEnabled" placement="end"
|
||||||
<i-bs class="me-1" name="gear"></i-bs><span> <ng-container i18n>Settings</ng-container></span>
|
container="body" triggers="mouseenter:mouseleave" popoverClass="popover-slim">
|
||||||
</a>
|
<i-bs class="me-1" name="gear"></i-bs><span> <ng-container i18n>Settings</ng-container></span>
|
||||||
</li>
|
|
||||||
<li class="nav-item app-link" *pngxIfPermissions="{ action: PermissionAction.Change, type: PermissionType.AppConfig }">
|
|
||||||
<a class="nav-link" routerLink="config" routerLinkActive="active" (click)="closeMenu()"
|
|
||||||
ngbPopover="Configuration" i18n-ngbPopover [disablePopover]="!slimSidebarEnabled" placement="end"
|
|
||||||
container="body" triggers="mouseenter:mouseleave" popoverClass="popover-slim">
|
|
||||||
<i-bs class="me-1" name="sliders2-vertical"></i-bs><span> <ng-container i18n>Configuration</ng-container></span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item app-link" *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.User }">
|
|
||||||
<a class="nav-link" routerLink="usersgroups" routerLinkActive="active" (click)="closeMenu()"
|
|
||||||
ngbPopover="Users & Groups" i18n-ngbPopover [disablePopover]="!slimSidebarEnabled" placement="end"
|
|
||||||
container="body" triggers="mouseenter:mouseleave" popoverClass="popover-slim">
|
|
||||||
<i-bs class="me-1" name="people"></i-bs><span> <ng-container i18n>Users & Groups</ng-container></span>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item app-link"
|
|
||||||
*pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.PaperlessTask }"
|
|
||||||
tourAnchor="tour.file-tasks">
|
|
||||||
<a class="nav-link" routerLink="tasks" routerLinkActive="active" (click)="closeMenu()"
|
|
||||||
ngbPopover="File Tasks" i18n-ngbPopover [disablePopover]="!slimSidebarEnabled" placement="end"
|
|
||||||
container="body" triggers="mouseenter:mouseleave" popoverClass="popover-slim">
|
|
||||||
<i-bs class="me-1" name="list-task"></i-bs><span> <ng-container i18n>File Tasks</ng-container>@if (tasksService.failedFileTasks.length > 0) {
|
|
||||||
<span><span class="badge bg-danger ms-2 d-inline">{{tasksService.failedFileTasks.length}}</span></span>
|
|
||||||
}</span>
|
|
||||||
@if (tasksService.failedFileTasks.length > 0 && slimSidebarEnabled) {
|
|
||||||
<span class="badge bg-danger position-absolute top-0 end-0 d-none d-md-block">{{tasksService.failedFileTasks.length}}</span>
|
|
||||||
}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
@if (permissionsService.isAdmin()) {
|
|
||||||
<li class="nav-item app-link">
|
|
||||||
<a class="nav-link" routerLink="logs" routerLinkActive="active" (click)="closeMenu()" ngbPopover="Logs"
|
|
||||||
i18n-ngbPopover [disablePopover]="!slimSidebarEnabled" placement="end" container="body"
|
|
||||||
triggers="mouseenter:mouseleave" popoverClass="popover-slim">
|
|
||||||
<i-bs class="me-1" name="text-left"></i-bs><span> <ng-container i18n>Logs</ng-container></span>
|
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
}
|
<li class="nav-item app-link" *pngxIfPermissions="{ action: PermissionAction.Change, type: PermissionType.AppConfig }">
|
||||||
<li class="nav-item mt-2" tourAnchor="tour.outro">
|
<a class="nav-link" routerLink="config" routerLinkActive="active" (click)="closeMenu()"
|
||||||
<a class="px-3 py-2 text-muted small d-flex align-items-center flex-wrap text-decoration-none"
|
ngbPopover="Configuration" i18n-ngbPopover [disablePopover]="!slimSidebarEnabled" placement="end"
|
||||||
target="_blank" rel="noopener noreferrer" href="https://docs.paperless-ngx.com" ngbPopover="Documentation"
|
container="body" triggers="mouseenter:mouseleave" popoverClass="popover-slim">
|
||||||
i18n-ngbPopover [disablePopover]="!slimSidebarEnabled" placement="end" container="body"
|
<i-bs class="me-1" name="sliders2-vertical"></i-bs><span> <ng-container i18n>Configuration</ng-container></span>
|
||||||
triggers="mouseenter:mouseleave" popoverClass="popover-slim">
|
</a>
|
||||||
<i-bs class="d-flex" name="question-circle"></i-bs><span class="ms-1"> <ng-container i18n>Documentation</ng-container></span>
|
</li>
|
||||||
</a>
|
<li class="nav-item app-link" *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.User }">
|
||||||
</li>
|
<a class="nav-link" routerLink="usersgroups" routerLinkActive="active" (click)="closeMenu()"
|
||||||
<li class="nav-item" [class.visually-hidden]="slimSidebarEnabled">
|
ngbPopover="Users & Groups" i18n-ngbPopover [disablePopover]="!slimSidebarEnabled" placement="end"
|
||||||
<div class="px-3 py-0 text-muted small d-flex align-items-center flex-wrap">
|
container="body" triggers="mouseenter:mouseleave" popoverClass="popover-slim">
|
||||||
<div class="me-3">
|
<i-bs class="me-1" name="people"></i-bs><span> <ng-container i18n>Users & Groups</ng-container></span>
|
||||||
<a class="text-muted text-decoration-none" target="_blank" rel="noopener noreferrer"
|
</a>
|
||||||
href="https://github.com/paperless-ngx/paperless-ngx" ngbPopover="GitHub" i18n-ngbPopover
|
</li>
|
||||||
[disablePopover]="!slimSidebarEnabled" placement="end" container="body"
|
<li class="nav-item app-link"
|
||||||
|
*pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.PaperlessTask }"
|
||||||
|
tourAnchor="tour.file-tasks">
|
||||||
|
<a class="nav-link" routerLink="tasks" routerLinkActive="active" (click)="closeMenu()"
|
||||||
|
ngbPopover="File Tasks" i18n-ngbPopover [disablePopover]="!slimSidebarEnabled" placement="end"
|
||||||
|
container="body" triggers="mouseenter:mouseleave" popoverClass="popover-slim">
|
||||||
|
<i-bs class="me-1" name="list-task"></i-bs><span> <ng-container i18n>File Tasks</ng-container>@if (tasksService.failedFileTasks.length > 0) {
|
||||||
|
<span><span class="badge bg-danger ms-2 d-inline">{{tasksService.failedFileTasks.length}}</span></span>
|
||||||
|
}</span>
|
||||||
|
@if (tasksService.failedFileTasks.length > 0 && slimSidebarEnabled) {
|
||||||
|
<span class="badge bg-danger position-absolute top-0 end-0 d-none d-md-block">{{tasksService.failedFileTasks.length}}</span>
|
||||||
|
}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
@if (permissionsService.isAdmin()) {
|
||||||
|
<li class="nav-item app-link">
|
||||||
|
<a class="nav-link" routerLink="logs" routerLinkActive="active" (click)="closeMenu()" ngbPopover="Logs"
|
||||||
|
i18n-ngbPopover [disablePopover]="!slimSidebarEnabled" placement="end" container="body"
|
||||||
triggers="mouseenter:mouseleave" popoverClass="popover-slim">
|
triggers="mouseenter:mouseleave" popoverClass="popover-slim">
|
||||||
{{ versionString }}
|
<i-bs class="me-1" name="text-left"></i-bs><span> <ng-container i18n>Logs</ng-container></span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</li>
|
||||||
@if (!settingsService.updateCheckingIsSet || appRemoteVersion) {
|
}
|
||||||
<div class="version-check">
|
</ul>
|
||||||
<ng-template #updateAvailablePopContent>
|
<ul class="nav flex-column">
|
||||||
<span class="small">Paperless-ngx {{ appRemoteVersion.version }} <ng-container i18n>is
|
<li class="nav-item mt-2" tourAnchor="tour.outro">
|
||||||
available.</ng-container><br /><ng-container i18n>Click to view.</ng-container></span>
|
<a class="px-3 py-2 text-muted small d-flex align-items-center flex-wrap text-decoration-none"
|
||||||
</ng-template>
|
target="_blank" rel="noopener noreferrer" href="https://docs.paperless-ngx.com" ngbPopover="Documentation"
|
||||||
<ng-template #updateCheckingNotEnabledPopContent>
|
i18n-ngbPopover [disablePopover]="!slimSidebarEnabled" placement="end" container="body"
|
||||||
<p class="small mb-2">
|
triggers="mouseenter:mouseleave" popoverClass="popover-slim">
|
||||||
<ng-container i18n>Paperless-ngx can automatically check for updates</ng-container>
|
<i-bs class="d-flex" name="question-circle"></i-bs><span class="ms-1"> <ng-container i18n>Documentation</ng-container></span>
|
||||||
</p>
|
</a>
|
||||||
<div class="btn-group btn-group-xs flex-fill w-100">
|
</li>
|
||||||
<button class="btn btn-outline-primary" (click)="setUpdateChecking(true)">Enable</button>
|
<li class="nav-item" [class.visually-hidden]="slimSidebarEnabled">
|
||||||
<button class="btn btn-outline-secondary" (click)="setUpdateChecking(false)">Disable</button>
|
<div class="px-3 py-0 text-muted small d-flex align-items-center flex-wrap">
|
||||||
</div>
|
<div class="me-3">
|
||||||
<p class="small mb-0 mt-2">
|
<a class="text-muted text-decoration-none" target="_blank" rel="noopener noreferrer"
|
||||||
<a class="small text-decoration-none fst-italic" routerLink="/settings" fragment="update-checking" i18n>
|
href="https://github.com/paperless-ngx/paperless-ngx" ngbPopover="GitHub" i18n-ngbPopover
|
||||||
How does this work?
|
[disablePopover]="!slimSidebarEnabled" placement="end" container="body"
|
||||||
</a>
|
triggers="mouseenter:mouseleave" popoverClass="popover-slim">
|
||||||
</p>
|
{{ versionString }}
|
||||||
</ng-template>
|
</a>
|
||||||
@if (settingsService.updateCheckingIsSet) {
|
</div>
|
||||||
@if (appRemoteVersion.update_available) {
|
@if (!settingsService.updateCheckingIsSet || appRemoteVersion) {
|
||||||
<a class="small text-decoration-none" target="_blank" rel="noopener noreferrer"
|
<div class="version-check">
|
||||||
href="https://github.com/paperless-ngx/paperless-ngx/releases"
|
<ng-template #updateAvailablePopContent>
|
||||||
[ngbPopover]="updateAvailablePopContent" popoverClass="shadow" triggers="mouseenter:mouseleave"
|
<span class="small">Paperless-ngx {{ appRemoteVersion.version }} <ng-container i18n>is
|
||||||
|
available.</ng-container><br /><ng-container i18n>Click to view.</ng-container></span>
|
||||||
|
</ng-template>
|
||||||
|
<ng-template #updateCheckingNotEnabledPopContent>
|
||||||
|
<p class="small mb-2">
|
||||||
|
<ng-container i18n>Paperless-ngx can automatically check for updates</ng-container>
|
||||||
|
</p>
|
||||||
|
<div class="btn-group btn-group-xs flex-fill w-100">
|
||||||
|
<button class="btn btn-outline-primary" (click)="setUpdateChecking(true)">Enable</button>
|
||||||
|
<button class="btn btn-outline-secondary" (click)="setUpdateChecking(false)">Disable</button>
|
||||||
|
</div>
|
||||||
|
<p class="small mb-0 mt-2">
|
||||||
|
<a class="small text-decoration-none fst-italic" routerLink="/settings" fragment="update-checking" i18n>
|
||||||
|
How does this work?
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</ng-template>
|
||||||
|
@if (settingsService.updateCheckingIsSet) {
|
||||||
|
@if (appRemoteVersion.update_available) {
|
||||||
|
<a class="small text-decoration-none" target="_blank" rel="noopener noreferrer"
|
||||||
|
href="https://github.com/paperless-ngx/paperless-ngx/releases"
|
||||||
|
[ngbPopover]="updateAvailablePopContent" popoverClass="shadow" triggers="mouseenter:mouseleave"
|
||||||
|
container="body">
|
||||||
|
<i-bs width="1.2em" height="1.2em" name="info-circle"></i-bs>
|
||||||
|
@if (appRemoteVersion?.update_available) {
|
||||||
|
<ng-container i18n>Update available</ng-container>
|
||||||
|
}
|
||||||
|
</a>
|
||||||
|
}
|
||||||
|
} @else {
|
||||||
|
<a *pngxIfPermissions="{ action: PermissionAction.Change, type: PermissionType.UISettings }" class="small text-decoration-none" routerLink="/settings" fragment="update-checking"
|
||||||
|
[ngbPopover]="updateCheckingNotEnabledPopContent" popoverClass="shadow" triggers="mouseenter"
|
||||||
container="body">
|
container="body">
|
||||||
<i-bs width="1.2em" height="1.2em" name="info-circle"></i-bs>
|
<i-bs width="1.2em" height="1.2em" name="info-circle"></i-bs>
|
||||||
@if (appRemoteVersion?.update_available) {
|
|
||||||
<ng-container i18n>Update available</ng-container>
|
|
||||||
}
|
|
||||||
</a>
|
</a>
|
||||||
}
|
}
|
||||||
} @else {
|
</div>
|
||||||
<a *pngxIfPermissions="{ action: PermissionAction.Change, type: PermissionType.UISettings }" class="small text-decoration-none" routerLink="/settings" fragment="update-checking"
|
}
|
||||||
[ngbPopover]="updateCheckingNotEnabledPopContent" popoverClass="shadow" triggers="mouseenter"
|
</div>
|
||||||
container="body">
|
</li>
|
||||||
<i-bs width="1.2em" height="1.2em" name="info-circle"></i-bs>
|
</ul>
|
||||||
</a>
|
</div>
|
||||||
}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
@@ -89,6 +89,8 @@ export class AppFrameComponent
|
|||||||
appRemoteVersion: AppRemoteVersion
|
appRemoteVersion: AppRemoteVersion
|
||||||
|
|
||||||
isMenuCollapsed: boolean = true
|
isMenuCollapsed: boolean = true
|
||||||
|
isManageMenuCollapsed: boolean = false
|
||||||
|
isAdminMenuCollapsed: boolean = false
|
||||||
|
|
||||||
slimSidebarAnimating: boolean = false
|
slimSidebarAnimating: boolean = false
|
||||||
|
|
||||||
|
|||||||
@@ -71,20 +71,4 @@ describe('TagListComponent', () => {
|
|||||||
'Do you really want to delete the tag "Tag1"?'
|
'Do you really want to delete the tag "Tag1"?'
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should filter out child tags if name filter is empty, otherwise show all', () => {
|
|
||||||
const tags = [
|
|
||||||
{ id: 1, name: 'Tag1', parent: null },
|
|
||||||
{ id: 2, name: 'Tag2', parent: 1 },
|
|
||||||
{ id: 3, name: 'Tag3', parent: null },
|
|
||||||
]
|
|
||||||
component['_nameFilter'] = null // Simulate empty name filter
|
|
||||||
const filtered = component.filterData(tags as any)
|
|
||||||
expect(filtered.length).toBe(2)
|
|
||||||
expect(filtered.find((t) => t.id === 2)).toBeUndefined()
|
|
||||||
|
|
||||||
component['_nameFilter'] = 'Tag2' // Simulate non-empty name filter
|
|
||||||
const filteredWithName = component.filterData(tags as any)
|
|
||||||
expect(filteredWithName.length).toBe(3)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -62,8 +62,6 @@ export class TagListComponent extends ManagementListComponent<Tag> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
filterData(data: Tag[]) {
|
filterData(data: Tag[]) {
|
||||||
return this.nameFilter?.length
|
return data.filter((tag) => !tag.parent)
|
||||||
? [...data]
|
|
||||||
: data.filter((tag) => !tag.parent)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,7 +55,9 @@ import {
|
|||||||
checkLg,
|
checkLg,
|
||||||
chevronDoubleLeft,
|
chevronDoubleLeft,
|
||||||
chevronDoubleRight,
|
chevronDoubleRight,
|
||||||
|
chevronDown,
|
||||||
chevronRight,
|
chevronRight,
|
||||||
|
chevronUp,
|
||||||
clipboard,
|
clipboard,
|
||||||
clipboardCheck,
|
clipboardCheck,
|
||||||
clipboardCheckFill,
|
clipboardCheckFill,
|
||||||
@@ -267,7 +269,9 @@ const icons = {
|
|||||||
checkLg,
|
checkLg,
|
||||||
chevronDoubleLeft,
|
chevronDoubleLeft,
|
||||||
chevronDoubleRight,
|
chevronDoubleRight,
|
||||||
|
chevronDown,
|
||||||
chevronRight,
|
chevronRight,
|
||||||
|
chevronUp,
|
||||||
clipboard,
|
clipboard,
|
||||||
clipboardCheck,
|
clipboardCheck,
|
||||||
clipboardCheckFill,
|
clipboardCheckFill,
|
||||||
|
|||||||
@@ -82,13 +82,6 @@ def _is_ignored(filepath: Path) -> bool:
|
|||||||
|
|
||||||
|
|
||||||
def _consume(filepath: Path) -> None:
|
def _consume(filepath: Path) -> None:
|
||||||
# Check permissions early
|
|
||||||
try:
|
|
||||||
filepath.stat()
|
|
||||||
except (PermissionError, OSError):
|
|
||||||
logger.warning(f"Not consuming file {filepath}: Permission denied.")
|
|
||||||
return
|
|
||||||
|
|
||||||
if filepath.is_dir() or _is_ignored(filepath):
|
if filepath.is_dir() or _is_ignored(filepath):
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -330,12 +323,7 @@ class Command(BaseCommand):
|
|||||||
|
|
||||||
# Also make sure the file exists still, some scanners might write a
|
# Also make sure the file exists still, some scanners might write a
|
||||||
# temporary file first
|
# temporary file first
|
||||||
try:
|
file_still_exists = filepath.exists() and filepath.is_file()
|
||||||
file_still_exists = filepath.exists() and filepath.is_file()
|
|
||||||
except (PermissionError, OSError): # pragma: no cover
|
|
||||||
# If we can't check, let it fail in the _consume function
|
|
||||||
file_still_exists = True
|
|
||||||
continue
|
|
||||||
|
|
||||||
if waited_long_enough and file_still_exists:
|
if waited_long_enough and file_still_exists:
|
||||||
_consume(filepath)
|
_consume(filepath)
|
||||||
|
|||||||
@@ -209,26 +209,6 @@ class TestConsumer(DirectoriesMixin, ConsumerThreadMixin, TransactionTestCase):
|
|||||||
# assert that we have an error logged with this invalid file.
|
# assert that we have an error logged with this invalid file.
|
||||||
error_logger.assert_called_once()
|
error_logger.assert_called_once()
|
||||||
|
|
||||||
@mock.patch("documents.management.commands.document_consumer.logger.warning")
|
|
||||||
def test_permission_error_on_prechecks(self, warning_logger):
|
|
||||||
filepath = Path(self.dirs.consumption_dir) / "selinux.txt"
|
|
||||||
filepath.touch()
|
|
||||||
|
|
||||||
original_stat = Path.stat
|
|
||||||
|
|
||||||
def raising_stat(self, *args, **kwargs):
|
|
||||||
if self == filepath:
|
|
||||||
raise PermissionError("Permission denied")
|
|
||||||
return original_stat(self, *args, **kwargs)
|
|
||||||
|
|
||||||
with mock.patch("pathlib.Path.stat", new=raising_stat):
|
|
||||||
document_consumer._consume(filepath)
|
|
||||||
|
|
||||||
warning_logger.assert_called_once()
|
|
||||||
(args, _) = warning_logger.call_args
|
|
||||||
self.assertIn("Permission denied", args[0])
|
|
||||||
self.consume_file_mock.assert_not_called()
|
|
||||||
|
|
||||||
@override_settings(CONSUMPTION_DIR="does_not_exist")
|
@override_settings(CONSUMPTION_DIR="does_not_exist")
|
||||||
def test_consumption_directory_invalid(self):
|
def test_consumption_directory_invalid(self):
|
||||||
self.assertRaises(CommandError, call_command, "document_consumer", "--oneshot")
|
self.assertRaises(CommandError, call_command, "document_consumer", "--oneshot")
|
||||||
|
|||||||
@@ -922,7 +922,7 @@ CELERY_ACCEPT_CONTENT = ["application/json", "application/x-python-serialize"]
|
|||||||
CELERY_BEAT_SCHEDULE = _parse_beat_schedule()
|
CELERY_BEAT_SCHEDULE = _parse_beat_schedule()
|
||||||
|
|
||||||
# https://docs.celeryq.dev/en/stable/userguide/configuration.html#beat-schedule-filename
|
# https://docs.celeryq.dev/en/stable/userguide/configuration.html#beat-schedule-filename
|
||||||
CELERY_BEAT_SCHEDULE_FILENAME = str(DATA_DIR / "celerybeat-schedule.db")
|
CELERY_BEAT_SCHEDULE_FILENAME = DATA_DIR / "celerybeat-schedule.db"
|
||||||
|
|
||||||
|
|
||||||
# Cachalot: Database read cache.
|
# Cachalot: Database read cache.
|
||||||
|
|||||||
Reference in New Issue
Block a user