Add folder creation and fix other bugs
This commit is contained in:
parent
3d3ce79b0d
commit
ee84acd853
@ -113,7 +113,8 @@ import localeSl from '@angular/common/locales/sl'
|
||||
import localeSr from '@angular/common/locales/sr'
|
||||
import localeSv from '@angular/common/locales/sv'
|
||||
import localeTr from '@angular/common/locales/tr'
|
||||
import localeZh from '@angular/common/locales/zh'
|
||||
import localeZh from '@angular/common/locales/zh';
|
||||
import { FolderCreateDialogComponent } from './components/common/create-dialog/folder-create-dialog/folder-create-dialog.component'
|
||||
|
||||
registerLocaleData(localeAr)
|
||||
registerLocaleData(localeBe)
|
||||
@ -215,6 +216,7 @@ function initializeApp(settings: SettingsService) {
|
||||
IfObjectPermissionsDirective,
|
||||
PermissionsDialogComponent,
|
||||
PermissionsFormComponent,
|
||||
FolderCreateDialogComponent,
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
|
@ -0,0 +1,47 @@
|
||||
<form [formGroup]="objectForm" (ngSubmit)="submit()">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title" id="modal-basic-title">{{ getTitle() }}</h4>
|
||||
<button
|
||||
type="button"
|
||||
[disabled]="!closeEnabled"
|
||||
class="btn-close"
|
||||
aria-label="Close"
|
||||
(click)="cancel()"
|
||||
></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<app-input-text
|
||||
i18n-title
|
||||
title="Name"
|
||||
formControlName="name"
|
||||
[error]="error?.name"
|
||||
></app-input-text>
|
||||
|
||||
<div *appIfOwner="object">
|
||||
<app-permissions-form
|
||||
[users]="users"
|
||||
accordion="true"
|
||||
formControlName="permissions_form"
|
||||
></app-permissions-form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-outline-secondary"
|
||||
(click)="cancel()"
|
||||
i18n
|
||||
[disabled]="networkActive"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-primary"
|
||||
i18n
|
||||
[disabled]="networkActive"
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
@ -0,0 +1,23 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { FolderCreateDialogComponent } from './folder-create-dialog.component';
|
||||
|
||||
describe('FolderCreateDialogComponent', () => {
|
||||
let component: FolderCreateDialogComponent;
|
||||
let fixture: ComponentFixture<FolderCreateDialogComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ FolderCreateDialogComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(FolderCreateDialogComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,57 @@
|
||||
import { Component, OnInit } from '@angular/core'
|
||||
import { FormControl, FormGroup } from '@angular/forms'
|
||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { DEFAULT_MATCHING_ALGORITHM } from 'src/app/data/matching-model'
|
||||
import { PaperlessStoragePath } from 'src/app/data/paperless-storage-path'
|
||||
import { StoragePathService } from 'src/app/services/rest/storage-path.service'
|
||||
import { UserService } from 'src/app/services/rest/user.service'
|
||||
import { EditDialogComponent } from '../../edit-dialog/edit-dialog.component'
|
||||
import { Subscription } from 'rxjs'
|
||||
|
||||
@Component({
|
||||
selector: 'app-folder-create-dialog',
|
||||
templateUrl: './folder-create-dialog.component.html',
|
||||
styleUrls: ['./folder-create-dialog.component.scss'],
|
||||
})
|
||||
export class FolderCreateDialogComponent
|
||||
extends EditDialogComponent<PaperlessStoragePath>
|
||||
implements OnInit
|
||||
{
|
||||
nameSub: Subscription
|
||||
|
||||
constructor(
|
||||
service: StoragePathService,
|
||||
activeModal: NgbActiveModal,
|
||||
userService: UserService
|
||||
) {
|
||||
super(service, activeModal, userService)
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
const nameField = this.objectForm.get('name')
|
||||
const parentFolderPath = this.object?.path ?? ''
|
||||
this.nameSub = nameField.valueChanges.subscribe(() => {
|
||||
const fullPath = parentFolderPath + '/' + nameField.value
|
||||
this.objectForm.get('path').patchValue(fullPath)
|
||||
this.objectForm.get('slug').patchValue(fullPath)
|
||||
})
|
||||
}
|
||||
|
||||
submit(): void {
|
||||
this.nameSub.unsubscribe()
|
||||
this.objectForm.get('name').patchValue(this.objectForm.get('path').value)
|
||||
this.save()
|
||||
}
|
||||
|
||||
getForm(): FormGroup<any> {
|
||||
return new FormGroup({
|
||||
name: new FormControl(''),
|
||||
path: new FormControl(''),
|
||||
slug: new FormControl(''),
|
||||
matching_algorithm: new FormControl(DEFAULT_MATCHING_ALGORITHM),
|
||||
match: new FormControl(''),
|
||||
is_insensitive: new FormControl(true),
|
||||
permissions_form: new FormControl(null),
|
||||
})
|
||||
}
|
||||
}
|
@ -169,7 +169,7 @@
|
||||
</app-page-header>
|
||||
|
||||
<div class="row sticky-top pt-3 pt-sm-4 pb-2 pb-lg-4 bg-body">
|
||||
<div class="flex pb-2">
|
||||
<div class="flex pb-2 mb-4">
|
||||
<span *ngFor="let pathPart of folderPath.split('/'); let i = index">
|
||||
<a (click)="clickPathPart(i)">{{ pathPart }}</a>
|
||||
<span *ngIf="i < folderPath.split('/').length - 1"> / </span>
|
||||
@ -182,6 +182,17 @@
|
||||
[selectionData]="list.selectionData"
|
||||
#filterEditor
|
||||
></app-filter-editor> -->
|
||||
|
||||
<div class="row w-auto">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary btn-sm mx-2"
|
||||
(click)="createFolder()"
|
||||
>
|
||||
+ New Folder
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<app-bulk-editor [hidden]="!isBulkEditing"></app-bulk-editor>
|
||||
</div>
|
||||
|
||||
|
@ -6,18 +6,9 @@ import {
|
||||
ViewChild,
|
||||
ViewChildren,
|
||||
} from '@angular/core'
|
||||
import { ActivatedRoute, Router, convertToParamMap } from '@angular/router'
|
||||
import { ActivatedRoute, Router } from '@angular/router'
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import {
|
||||
Subject,
|
||||
filter,
|
||||
first,
|
||||
map,
|
||||
switchMap,
|
||||
take,
|
||||
takeUntil,
|
||||
tap,
|
||||
} from 'rxjs'
|
||||
import { Subject, takeUntil } from 'rxjs'
|
||||
import {
|
||||
FilterRule,
|
||||
filterRulesDiffer,
|
||||
@ -26,6 +17,7 @@ import {
|
||||
import { FILTER_FULLTEXT_MORELIKE } from 'src/app/data/filter-rule-type'
|
||||
import { PaperlessDocument } from 'src/app/data/paperless-document'
|
||||
import { PaperlessSavedView } from 'src/app/data/paperless-saved-view'
|
||||
import { PaperlessStoragePath } from 'src/app/data/paperless-storage-path'
|
||||
import { SETTINGS_KEYS } from 'src/app/data/paperless-uisettings'
|
||||
import {
|
||||
SortEvent,
|
||||
@ -41,9 +33,9 @@ import { SavedViewService } from 'src/app/services/rest/saved-view.service'
|
||||
import { SettingsService } from 'src/app/services/settings.service'
|
||||
import { StoragePathListViewService } from 'src/app/services/storage-path-list-view.service'
|
||||
import { ToastService } from 'src/app/services/toast.service'
|
||||
import { FolderCreateDialogComponent } from '../common/create-dialog/folder-create-dialog/folder-create-dialog.component'
|
||||
import { ComponentWithPermissions } from '../with-permissions/with-permissions.component'
|
||||
import { FilterEditorComponent } from './filter-editor/filter-editor.component'
|
||||
import { PaperlessStoragePath } from 'src/app/data/paperless-storage-path'
|
||||
|
||||
@Component({
|
||||
selector: 'app-explorer',
|
||||
@ -169,9 +161,11 @@ export class ExplorerComponent
|
||||
}
|
||||
|
||||
clickPathPart(index: number) {
|
||||
if (index === 0) return this.router.navigate(['explorer'])
|
||||
const pathUntilPart = this.folderPath
|
||||
.replace('DMS/', '')
|
||||
.split('/')
|
||||
.slice(0, index + 1)
|
||||
.slice(0, index)
|
||||
.join('/')
|
||||
this.list.getStoragePathByPath(pathUntilPart).subscribe((storagePath) => {
|
||||
this.router.navigate(['explorer'], {
|
||||
@ -180,6 +174,19 @@ export class ExplorerComponent
|
||||
})
|
||||
}
|
||||
|
||||
createFolder() {
|
||||
var modal = this.modalService.open(FolderCreateDialogComponent, {
|
||||
backdrop: 'static',
|
||||
})
|
||||
modal.componentInstance.dialogMode = 'create'
|
||||
modal.componentInstance.object = {
|
||||
path: this.folderPath.replace('DMS/', ''),
|
||||
}
|
||||
modal.componentInstance.succeeded
|
||||
.pipe(takeUntil(this.unsubscribeNotifier))
|
||||
.subscribe(() => this.list.reload())
|
||||
}
|
||||
|
||||
openDocumentDetail(storagePath: PaperlessStoragePath) {
|
||||
this.router.navigate(['explorer'], {
|
||||
queryParams: { spid: storagePath.id },
|
||||
|
@ -51,7 +51,7 @@ export class CustomStoragePathService extends AbstractPaperlessService<Paperless
|
||||
if (parentStoragePathId !== null && parentStoragePathId !== undefined) {
|
||||
return this.get(parentStoragePathId).pipe(
|
||||
switchMap((storagePath) => {
|
||||
params.path__istartswith = storagePath.path
|
||||
params.path__istartswith = storagePath.path + '/'
|
||||
return this.list(page, pageSize, sortField, sortReverse, params).pipe(
|
||||
map((results) => {
|
||||
results.results = results.results.filter((s) => {
|
||||
|
@ -1,18 +1,12 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { ParamMap, Router } from '@angular/router'
|
||||
import { Observable } from 'rxjs'
|
||||
import {
|
||||
FilterRule,
|
||||
cloneFilterRules,
|
||||
filterRulesDiffer,
|
||||
isFullTextFilterRule,
|
||||
} from '../data/filter-rule'
|
||||
import { FilterRule, isFullTextFilterRule } from '../data/filter-rule'
|
||||
import { PaperlessDocument } from '../data/paperless-document'
|
||||
import { PaperlessSavedView } from '../data/paperless-saved-view'
|
||||
import { PaperlessStoragePath } from '../data/paperless-storage-path'
|
||||
import { SETTINGS_KEYS } from '../data/paperless-uisettings'
|
||||
import { DOCUMENT_LIST_SERVICE } from '../data/storage-keys'
|
||||
import { paramsFromViewState, paramsToViewState } from '../utils/query-params'
|
||||
import { paramsToViewState } from '../utils/query-params'
|
||||
import { CustomStoragePathService } from './rest/custom-storage-path.service'
|
||||
import { DOCUMENT_SORT_FIELDS, SelectionData } from './rest/document.service'
|
||||
import { SettingsService } from './settings.service'
|
||||
@ -136,29 +130,38 @@ export class StoragePathListViewService {
|
||||
if (queryParams.has('spid')) {
|
||||
newState.storagePathId = parseInt(queryParams.get('spid'))
|
||||
}
|
||||
} else {
|
||||
newState = this.defaultListViewState()
|
||||
}
|
||||
if (newState == undefined) newState = this.defaultListViewState() // if nothing in local storage
|
||||
|
||||
// only reload if things have changed
|
||||
if (
|
||||
!this.initialized ||
|
||||
isParamsEmpty ||
|
||||
this.activeListViewState.sortField !== newState.sortField ||
|
||||
this.activeListViewState.sortReverse !== newState.sortReverse ||
|
||||
this.activeListViewState.currentPage !== newState.currentPage ||
|
||||
this.activeListViewState.storagePathId !== newState.storagePathId ||
|
||||
filterRulesDiffer(
|
||||
this.activeListViewState.filterRules,
|
||||
newState.filterRules
|
||||
)
|
||||
) {
|
||||
this.activeListViewState.filterRules = newState.filterRules
|
||||
this.activeListViewState.sortField = newState.sortField
|
||||
this.activeListViewState.sortReverse = newState.sortReverse
|
||||
this.activeListViewState.currentPage = newState.currentPage
|
||||
this.activeListViewState.storagePathId = newState.storagePathId
|
||||
this.reload(null, isParamsEmpty) // update the params if there arent any
|
||||
}
|
||||
this.activeListViewState.parentStoragePath = newState.parentStoragePath
|
||||
this.reload(null, isParamsEmpty)
|
||||
// only reload if things have changed
|
||||
// if (
|
||||
// !this.initialized ||
|
||||
// isParamsEmpty ||
|
||||
// this.activeListViewState.sortField !== newState.sortField ||
|
||||
// this.activeListViewState.sortReverse !== newState.sortReverse ||
|
||||
// this.activeListViewState.currentPage !== newState.currentPage ||
|
||||
// this.activeListViewState.storagePathId !== newState.storagePathId ||
|
||||
// filterRulesDiffer(
|
||||
// this.activeListViewState.filterRules,
|
||||
// newState.filterRules
|
||||
// )
|
||||
// ) {
|
||||
// this.activeListViewState.filterRules = newState.filterRules
|
||||
// this.activeListViewState.sortField = newState.sortField
|
||||
// this.activeListViewState.sortReverse = newState.sortReverse
|
||||
// this.activeListViewState.currentPage = newState.currentPage
|
||||
// this.activeListViewState.storagePathId = newState.storagePathId
|
||||
// this.reload(null, isParamsEmpty) // update the params if there arent any
|
||||
// }
|
||||
}
|
||||
|
||||
getStoragePathByPath(path: string): Observable<PaperlessStoragePath> {
|
||||
@ -297,7 +300,8 @@ export class StoragePathListViewService {
|
||||
}
|
||||
|
||||
get currentFolderPath(): string {
|
||||
return this.activeListViewState.parentStoragePath?.path || '/'
|
||||
const path = this.activeListViewState.parentStoragePath?.path
|
||||
return path ? 'DMS/' + path : 'DMS/'
|
||||
}
|
||||
|
||||
setSort(field: string, reverse: boolean) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user