Compare commits

..

No commits in common. "955ff32dcd677dd57bfabdd04a99af29d94bd216" and "485dad01b70823f2e562ee0da14274785c53d2ea" have entirely different histories.

7 changed files with 134 additions and 88 deletions

View File

@ -1,18 +1,18 @@
codecov:
require_ci_to_pass: true
# https://docs.codecov.com/docs/components
component_management:
individual_components:
- component_id: backend
# https://docs.codecov.com/docs/flags#recommended-automatic-flag-management
# Require each flag to have 1 upload before notification
flag_management:
individual_flags:
- name: backend
paths:
- src/**
- component_id: frontend
- src/
- name: frontend
paths:
- src-ui/**
- src-ui/
# https://docs.codecov.com/docs/pull-request-comments
# codecov will only comment if coverage changes
comment:
layout: "header, diff, components, flags, files"
require_changes: true
# https://docs.codecov.com/docs/javascript-bundle-analysis
require_bundle_changes: true

1
.github/FUNDING.yml vendored
View File

@ -1 +0,0 @@
github: [shamoon, stumpylog]

View File

@ -162,20 +162,16 @@ jobs:
--frozen \
pytest
-
name: Upload backend test results to Codecov
if: always()
uses: codecov/test-results-action@v1
name: Upload coverage
if: ${{ matrix.python-version == env.DEFAULT_PYTHON_VERSION }}
uses: actions/upload-artifact@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
flags: backend-python-${{ matrix.python-version }}
files: junit.xml
-
name: Upload backend coverage to Codecov
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
flags: backend-python-${{ matrix.python-version }}
files: coverage.xml
name: backend-coverage-report
path: |
coverage.xml
junit.xml
retention-days: 7
if-no-files-found: error
-
name: Stop containers
if: always()
@ -183,7 +179,7 @@ jobs:
docker compose --file ${{ github.workspace }}/docker/compose/docker-compose.ci-test.yml logs
docker compose --file ${{ github.workspace }}/docker/compose/docker-compose.ci-test.yml down
install-frontend-dependencies:
install-frontend-depedendencies:
name: "Install Frontend Dependencies"
runs-on: ubuntu-24.04
needs:
@ -218,7 +214,7 @@ jobs:
name: "Frontend Tests (Node ${{ matrix.node-version }} - ${{ matrix.shard-index }}/${{ matrix.shard-count }})"
runs-on: ubuntu-24.04
needs:
- install-frontend-dependencies
- install-frontend-depedendencies
strategy:
fail-fast: false
matrix:
@ -249,33 +245,111 @@ jobs:
run: cd src-ui && npm run lint
-
name: Run Jest unit tests
env:
JEST_JUNIT_OUTPUT_FILE: junit-report-${{ matrix.shard-index }}.xml
run: cd src-ui && npm run test -- --max-workers=2 --shard=${{ matrix.shard-index }}/${{ matrix.shard-count }}
-
name: Upload Jest coverage
if: always()
uses: actions/upload-artifact@v4
with:
name: jest-coverage-report-${{ matrix.shard-index }}
path: |
src-ui/coverage/coverage-final.json
src-ui/coverage/lcov.info
src-ui/coverage/clover.xml
retention-days: 7
if-no-files-found: error
-
name: Run Playwright e2e tests
run: cd src-ui && npx playwright test --shard ${{ matrix.shard-index }}/${{ matrix.shard-count }}
-
name: Upload frontend test results to Codecov
uses: codecov/test-results-action@v1
name: Upload Playwright test results
if: always()
uses: actions/upload-artifact@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
flags: frontend-node-${{ matrix.node-version }}
directory: src-ui/
name: playwright-report-${{ matrix.shard-index }}
path: src-ui/playwright-report
retention-days: 7
-
name: Upload frontend test results
if: always()
uses: actions/upload-artifact@v4
with:
name: junit-report-${{ matrix.shard-index }}
path: src-ui/junit-report-${{ matrix.shard-index }}.xml
retention-days: 7
tests-coverage-upload:
name: "Upload to Codecov"
runs-on: ubuntu-24.04
needs:
- tests-backend
- tests-frontend
steps:
-
uses: actions/checkout@v4
-
name: Download frontend jest coverage
uses: actions/download-artifact@v4
with:
path: src-ui/coverage/
pattern: jest-coverage-report-*
-
name: Download frontend playwright coverage
uses: actions/download-artifact@v4
with:
path: src-ui/coverage/
pattern: playwright-report-*
merge-multiple: true
-
name: Download frontend test results
uses: actions/download-artifact@v4
with:
path: src-ui/junit/
pattern: junit-report-*
merge-multiple: true
-
name: Upload frontend coverage to Codecov
uses: codecov/codecov-action@v5
with:
# not required for public repos, but intermittently fails otherwise
token: ${{ secrets.CODECOV_TOKEN }}
flags: frontend-node-${{ matrix.node-version }}
flags: frontend
directory: src-ui/coverage/
frontend-bundle-analysis:
name: "Frontend Bundle Analysis"
runs-on: ubuntu-24.04
needs:
- tests-frontend
steps:
- uses: actions/checkout@v4
# dont include backend coverage files here
files: '!coverage.xml'
-
name: Upload frontend test results to Codecov
if: ${{ !cancelled() }}
uses: codecov/test-results-action@v1
with:
token: ${{ secrets.CODECOV_TOKEN }}
flags: frontend
directory: src-ui/junit/
-
name: Download backend coverage
uses: actions/download-artifact@v4
with:
name: backend-coverage-report
path: src/
-
name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
with:
# not required for public repos, but intermittently fails otherwise
token: ${{ secrets.CODECOV_TOKEN }}
# future expansion
flags: backend
directory: src/
-
name: Upload backend test results to Codecov
if: ${{ !cancelled() }}
uses: codecov/test-results-action@v1
with:
token: ${{ secrets.CODECOV_TOKEN }}
flags: backend
directory: src/
-
name: Use Node.js 20
uses: actions/setup-node@v4

View File

@ -36,13 +36,7 @@ export const routes: Routes = [
component: AppFrameComponent,
canDeactivate: [DirtyDocGuard],
children: [
{
path: 'dashboard',
component: DashboardComponent,
data: {
componentName: 'AppFrameComponent',
},
},
{ path: 'dashboard', component: DashboardComponent },
{
path: 'documents',
component: DocumentListComponent,
@ -53,7 +47,6 @@ export const routes: Routes = [
action: PermissionAction.View,
type: PermissionType.Document,
},
componentName: 'DocumentListComponent',
},
},
{
@ -66,7 +59,6 @@ export const routes: Routes = [
action: PermissionAction.View,
type: PermissionType.SavedView,
},
componentName: 'DocumentListComponent',
},
},
{
@ -78,7 +70,6 @@ export const routes: Routes = [
action: PermissionAction.View,
type: PermissionType.Document,
},
componentName: 'DocumentDetailComponent',
},
},
{
@ -90,7 +81,6 @@ export const routes: Routes = [
action: PermissionAction.View,
type: PermissionType.Document,
},
componentName: 'DocumentDetailComponent',
},
},
{
@ -102,7 +92,6 @@ export const routes: Routes = [
action: PermissionAction.View,
type: PermissionType.Document,
},
componentName: 'DocumentAsnComponent',
},
},
{
@ -114,7 +103,6 @@ export const routes: Routes = [
action: PermissionAction.View,
type: PermissionType.Tag,
},
componentName: 'TagListComponent',
},
},
{
@ -126,7 +114,6 @@ export const routes: Routes = [
action: PermissionAction.View,
type: PermissionType.DocumentType,
},
componentName: 'DocumentTypeListComponent',
},
},
{
@ -138,7 +125,6 @@ export const routes: Routes = [
action: PermissionAction.View,
type: PermissionType.Correspondent,
},
componentName: 'CorrespondentListComponent',
},
},
{
@ -150,7 +136,6 @@ export const routes: Routes = [
action: PermissionAction.View,
type: PermissionType.StoragePath,
},
componentName: 'StoragePathListComponent',
},
},
{
@ -159,7 +144,6 @@ export const routes: Routes = [
canActivate: [PermissionsGuard],
data: {
requireAdmin: true,
componentName: 'LogsComponent',
},
},
{
@ -171,7 +155,6 @@ export const routes: Routes = [
action: PermissionAction.Delete,
type: PermissionType.Document,
},
componentName: 'TrashComponent',
},
},
// redirect old paths
@ -197,7 +180,6 @@ export const routes: Routes = [
action: PermissionAction.Change,
type: PermissionType.UISettings,
},
componentName: 'SettingsComponent',
},
},
{
@ -210,7 +192,6 @@ export const routes: Routes = [
action: PermissionAction.View,
type: PermissionType.UISettings,
},
componentName: 'SettingsComponent',
},
},
{
@ -222,7 +203,6 @@ export const routes: Routes = [
action: PermissionAction.Change,
type: PermissionType.AppConfig,
},
componentName: 'ConfigComponent',
},
},
{
@ -234,7 +214,6 @@ export const routes: Routes = [
action: PermissionAction.View,
type: PermissionType.PaperlessTask,
},
componentName: 'TasksComponent',
},
},
{
@ -246,7 +225,6 @@ export const routes: Routes = [
action: PermissionAction.View,
type: PermissionType.CustomField,
},
componentName: 'CustomFieldsComponent',
},
},
{
@ -258,7 +236,6 @@ export const routes: Routes = [
action: PermissionAction.View,
type: PermissionType.Workflow,
},
componentName: 'WorkflowsComponent',
},
},
{
@ -270,7 +247,6 @@ export const routes: Routes = [
action: PermissionAction.View,
type: PermissionType.MailAccount,
},
componentName: 'MailComponent',
},
},
{
@ -282,7 +258,6 @@ export const routes: Routes = [
action: PermissionAction.View,
type: PermissionType.User,
},
componentName: 'UsersAndGroupsComponent',
},
},
{
@ -294,7 +269,6 @@ export const routes: Routes = [
action: PermissionAction.View,
type: PermissionType.SavedView,
},
componentName: 'SavedViewsComponent',
},
},
],

View File

@ -29,7 +29,7 @@ describe('ComponentRouterService', () => {
eventsSubject.next(
new ActivationStart({
url: 'test-url',
data: { componentName: 'TestComponent' },
component: { name: 'TestComponent' },
} as any)
)
@ -41,13 +41,13 @@ describe('ComponentRouterService', () => {
eventsSubject.next(
new ActivationStart({
url: 'test-url-1',
data: { componentName: 'TestComponent' },
component: { name: 'TestComponent' },
} as any)
)
eventsSubject.next(
new ActivationStart({
url: 'test-url-2',
data: { componentName: 'TestComponent' },
component: { name: 'TestComponent' },
} as any)
)
@ -59,13 +59,13 @@ describe('ComponentRouterService', () => {
eventsSubject.next(
new ActivationStart({
url: 'test-url-1',
data: { componentName: 'TestComponent1' },
component: { name: 'TestComponent1' },
} as any)
)
eventsSubject.next(
new ActivationStart({
url: 'test-url-2',
data: { componentName: 'TestComponent2' },
component: { name: 'TestComponent2' },
} as any)
)
@ -76,13 +76,13 @@ describe('ComponentRouterService', () => {
eventsSubject.next(
new ActivationStart({
url: 'test-url-1',
data: { componentName: 'TestComponent' },
component: { name: 'TestComponent' },
} as any)
)
eventsSubject.next(
new ActivationStart({
url: 'test-url-2',
data: { componentName: 'TestComponent' },
component: { name: 'TestComponent' },
} as any)
)
@ -93,7 +93,7 @@ describe('ComponentRouterService', () => {
eventsSubject.next(
new ActivationStart({
url: 'test-url',
data: { componentName: 'TestComponent' },
component: { name: 'TestComponent' },
} as any)
)

View File

@ -17,11 +17,11 @@ export class ComponentRouterService {
.subscribe((event: ActivationStart) => {
if (
this.componentHistory[this.componentHistory.length - 1] !==
event.snapshot.data.componentName &&
!EXCLUDE_COMPONENTS.includes(event.snapshot.data.componentName)
event.snapshot.component.name &&
!EXCLUDE_COMPONENTS.includes(event.snapshot.component.name)
) {
this.history.push(event.snapshot.url.toString())
this.componentHistory.push(event.snapshot.data.componentName)
this.componentHistory.push(event.snapshot.component.name)
} else {
// Update the URL of the current component in case the same component was loaded via a different URL
this.history[this.history.length - 1] = event.snapshot.url.toString()

View File

@ -32,7 +32,6 @@ from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet
from documents.index import DelayedQuery
from documents.permissions import PaperlessObjectPermissions
from paperless.filters import GroupFilterSet
from paperless.filters import UserFilterSet
@ -67,15 +66,15 @@ class StandardPagination(PageNumberPagination):
)
def get_all_result_ids(self):
query = self.page.paginator.object_list
if isinstance(query, DelayedQuery):
ids = []
if hasattr(self.page.paginator.object_list, "saved_results"):
results_page = self.page.paginator.object_list.saved_results[0]
if results_page is not None:
for i in range(len(results_page.results.docs())):
try:
ids = [
query.searcher.ixreader.stored_fields(
doc_num,
)["id"]
for doc_num in query.saved_results.get(0).results.docs()
]
fields = results_page.results.fields(i)
if "id" in fields:
ids.append(fields["id"])
except Exception:
pass
else: