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 localeSr from '@angular/common/locales/sr'
|
||||||
import localeSv from '@angular/common/locales/sv'
|
import localeSv from '@angular/common/locales/sv'
|
||||||
import localeTr from '@angular/common/locales/tr'
|
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(localeAr)
|
||||||
registerLocaleData(localeBe)
|
registerLocaleData(localeBe)
|
||||||
@ -215,6 +216,7 @@ function initializeApp(settings: SettingsService) {
|
|||||||
IfObjectPermissionsDirective,
|
IfObjectPermissionsDirective,
|
||||||
PermissionsDialogComponent,
|
PermissionsDialogComponent,
|
||||||
PermissionsFormComponent,
|
PermissionsFormComponent,
|
||||||
|
FolderCreateDialogComponent,
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
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>
|
</app-page-header>
|
||||||
|
|
||||||
<div class="row sticky-top pt-3 pt-sm-4 pb-2 pb-lg-4 bg-body">
|
<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">
|
<span *ngFor="let pathPart of folderPath.split('/'); let i = index">
|
||||||
<a (click)="clickPathPart(i)">{{ pathPart }}</a>
|
<a (click)="clickPathPart(i)">{{ pathPart }}</a>
|
||||||
<span *ngIf="i < folderPath.split('/').length - 1"> / </span>
|
<span *ngIf="i < folderPath.split('/').length - 1"> / </span>
|
||||||
@ -182,6 +182,17 @@
|
|||||||
[selectionData]="list.selectionData"
|
[selectionData]="list.selectionData"
|
||||||
#filterEditor
|
#filterEditor
|
||||||
></app-filter-editor> -->
|
></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>
|
<app-bulk-editor [hidden]="!isBulkEditing"></app-bulk-editor>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -6,18 +6,9 @@ import {
|
|||||||
ViewChild,
|
ViewChild,
|
||||||
ViewChildren,
|
ViewChildren,
|
||||||
} from '@angular/core'
|
} from '@angular/core'
|
||||||
import { ActivatedRoute, Router, convertToParamMap } from '@angular/router'
|
import { ActivatedRoute, Router } from '@angular/router'
|
||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||||
import {
|
import { Subject, takeUntil } from 'rxjs'
|
||||||
Subject,
|
|
||||||
filter,
|
|
||||||
first,
|
|
||||||
map,
|
|
||||||
switchMap,
|
|
||||||
take,
|
|
||||||
takeUntil,
|
|
||||||
tap,
|
|
||||||
} from 'rxjs'
|
|
||||||
import {
|
import {
|
||||||
FilterRule,
|
FilterRule,
|
||||||
filterRulesDiffer,
|
filterRulesDiffer,
|
||||||
@ -26,6 +17,7 @@ import {
|
|||||||
import { FILTER_FULLTEXT_MORELIKE } from 'src/app/data/filter-rule-type'
|
import { FILTER_FULLTEXT_MORELIKE } from 'src/app/data/filter-rule-type'
|
||||||
import { PaperlessDocument } from 'src/app/data/paperless-document'
|
import { PaperlessDocument } from 'src/app/data/paperless-document'
|
||||||
import { PaperlessSavedView } from 'src/app/data/paperless-saved-view'
|
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 { SETTINGS_KEYS } from 'src/app/data/paperless-uisettings'
|
||||||
import {
|
import {
|
||||||
SortEvent,
|
SortEvent,
|
||||||
@ -41,9 +33,9 @@ import { SavedViewService } from 'src/app/services/rest/saved-view.service'
|
|||||||
import { SettingsService } from 'src/app/services/settings.service'
|
import { SettingsService } from 'src/app/services/settings.service'
|
||||||
import { StoragePathListViewService } from 'src/app/services/storage-path-list-view.service'
|
import { StoragePathListViewService } from 'src/app/services/storage-path-list-view.service'
|
||||||
import { ToastService } from 'src/app/services/toast.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 { ComponentWithPermissions } from '../with-permissions/with-permissions.component'
|
||||||
import { FilterEditorComponent } from './filter-editor/filter-editor.component'
|
import { FilterEditorComponent } from './filter-editor/filter-editor.component'
|
||||||
import { PaperlessStoragePath } from 'src/app/data/paperless-storage-path'
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-explorer',
|
selector: 'app-explorer',
|
||||||
@ -169,9 +161,11 @@ export class ExplorerComponent
|
|||||||
}
|
}
|
||||||
|
|
||||||
clickPathPart(index: number) {
|
clickPathPart(index: number) {
|
||||||
|
if (index === 0) return this.router.navigate(['explorer'])
|
||||||
const pathUntilPart = this.folderPath
|
const pathUntilPart = this.folderPath
|
||||||
|
.replace('DMS/', '')
|
||||||
.split('/')
|
.split('/')
|
||||||
.slice(0, index + 1)
|
.slice(0, index)
|
||||||
.join('/')
|
.join('/')
|
||||||
this.list.getStoragePathByPath(pathUntilPart).subscribe((storagePath) => {
|
this.list.getStoragePathByPath(pathUntilPart).subscribe((storagePath) => {
|
||||||
this.router.navigate(['explorer'], {
|
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) {
|
openDocumentDetail(storagePath: PaperlessStoragePath) {
|
||||||
this.router.navigate(['explorer'], {
|
this.router.navigate(['explorer'], {
|
||||||
queryParams: { spid: storagePath.id },
|
queryParams: { spid: storagePath.id },
|
||||||
|
@ -51,7 +51,7 @@ export class CustomStoragePathService extends AbstractPaperlessService<Paperless
|
|||||||
if (parentStoragePathId !== null && parentStoragePathId !== undefined) {
|
if (parentStoragePathId !== null && parentStoragePathId !== undefined) {
|
||||||
return this.get(parentStoragePathId).pipe(
|
return this.get(parentStoragePathId).pipe(
|
||||||
switchMap((storagePath) => {
|
switchMap((storagePath) => {
|
||||||
params.path__istartswith = storagePath.path
|
params.path__istartswith = storagePath.path + '/'
|
||||||
return this.list(page, pageSize, sortField, sortReverse, params).pipe(
|
return this.list(page, pageSize, sortField, sortReverse, params).pipe(
|
||||||
map((results) => {
|
map((results) => {
|
||||||
results.results = results.results.filter((s) => {
|
results.results = results.results.filter((s) => {
|
||||||
|
@ -1,18 +1,12 @@
|
|||||||
import { Injectable } from '@angular/core'
|
import { Injectable } from '@angular/core'
|
||||||
import { ParamMap, Router } from '@angular/router'
|
import { ParamMap, Router } from '@angular/router'
|
||||||
import { Observable } from 'rxjs'
|
import { Observable } from 'rxjs'
|
||||||
import {
|
import { FilterRule, isFullTextFilterRule } from '../data/filter-rule'
|
||||||
FilterRule,
|
|
||||||
cloneFilterRules,
|
|
||||||
filterRulesDiffer,
|
|
||||||
isFullTextFilterRule,
|
|
||||||
} from '../data/filter-rule'
|
|
||||||
import { PaperlessDocument } from '../data/paperless-document'
|
import { PaperlessDocument } from '../data/paperless-document'
|
||||||
import { PaperlessSavedView } from '../data/paperless-saved-view'
|
|
||||||
import { PaperlessStoragePath } from '../data/paperless-storage-path'
|
import { PaperlessStoragePath } from '../data/paperless-storage-path'
|
||||||
import { SETTINGS_KEYS } from '../data/paperless-uisettings'
|
import { SETTINGS_KEYS } from '../data/paperless-uisettings'
|
||||||
import { DOCUMENT_LIST_SERVICE } from '../data/storage-keys'
|
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 { CustomStoragePathService } from './rest/custom-storage-path.service'
|
||||||
import { DOCUMENT_SORT_FIELDS, SelectionData } from './rest/document.service'
|
import { DOCUMENT_SORT_FIELDS, SelectionData } from './rest/document.service'
|
||||||
import { SettingsService } from './settings.service'
|
import { SettingsService } from './settings.service'
|
||||||
@ -136,29 +130,38 @@ export class StoragePathListViewService {
|
|||||||
if (queryParams.has('spid')) {
|
if (queryParams.has('spid')) {
|
||||||
newState.storagePathId = parseInt(queryParams.get('spid'))
|
newState.storagePathId = parseInt(queryParams.get('spid'))
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
newState = this.defaultListViewState()
|
||||||
}
|
}
|
||||||
if (newState == undefined) newState = this.defaultListViewState() // if nothing in local storage
|
if (newState == undefined) newState = this.defaultListViewState() // if nothing in local storage
|
||||||
|
|
||||||
|
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.activeListViewState.parentStoragePath = newState.parentStoragePath
|
||||||
|
this.reload(null, isParamsEmpty)
|
||||||
// only reload if things have changed
|
// only reload if things have changed
|
||||||
if (
|
// if (
|
||||||
!this.initialized ||
|
// !this.initialized ||
|
||||||
isParamsEmpty ||
|
// isParamsEmpty ||
|
||||||
this.activeListViewState.sortField !== newState.sortField ||
|
// this.activeListViewState.sortField !== newState.sortField ||
|
||||||
this.activeListViewState.sortReverse !== newState.sortReverse ||
|
// this.activeListViewState.sortReverse !== newState.sortReverse ||
|
||||||
this.activeListViewState.currentPage !== newState.currentPage ||
|
// this.activeListViewState.currentPage !== newState.currentPage ||
|
||||||
this.activeListViewState.storagePathId !== newState.storagePathId ||
|
// this.activeListViewState.storagePathId !== newState.storagePathId ||
|
||||||
filterRulesDiffer(
|
// filterRulesDiffer(
|
||||||
this.activeListViewState.filterRules,
|
// this.activeListViewState.filterRules,
|
||||||
newState.filterRules
|
// newState.filterRules
|
||||||
)
|
// )
|
||||||
) {
|
// ) {
|
||||||
this.activeListViewState.filterRules = newState.filterRules
|
// this.activeListViewState.filterRules = newState.filterRules
|
||||||
this.activeListViewState.sortField = newState.sortField
|
// this.activeListViewState.sortField = newState.sortField
|
||||||
this.activeListViewState.sortReverse = newState.sortReverse
|
// this.activeListViewState.sortReverse = newState.sortReverse
|
||||||
this.activeListViewState.currentPage = newState.currentPage
|
// this.activeListViewState.currentPage = newState.currentPage
|
||||||
this.activeListViewState.storagePathId = newState.storagePathId
|
// this.activeListViewState.storagePathId = newState.storagePathId
|
||||||
this.reload(null, isParamsEmpty) // update the params if there arent any
|
// this.reload(null, isParamsEmpty) // update the params if there arent any
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
getStoragePathByPath(path: string): Observable<PaperlessStoragePath> {
|
getStoragePathByPath(path: string): Observable<PaperlessStoragePath> {
|
||||||
@ -297,7 +300,8 @@ export class StoragePathListViewService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get currentFolderPath(): string {
|
get currentFolderPath(): string {
|
||||||
return this.activeListViewState.parentStoragePath?.path || '/'
|
const path = this.activeListViewState.parentStoragePath?.path
|
||||||
|
return path ? 'DMS/' + path : 'DMS/'
|
||||||
}
|
}
|
||||||
|
|
||||||
setSort(field: string, reverse: boolean) {
|
setSort(field: string, reverse: boolean) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user