mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-02-24 00:59:35 -06:00
Basic frontend respect saved view perms
This commit is contained in:
@@ -104,11 +104,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
<div *pngxIfPermissions="{ action: PermissionAction.Change, type: PermissionType.SavedView }">
|
@if (list.activeSavedViewId && activeSavedViewCanChange) {
|
||||||
@if (list.activeSavedViewId) {
|
<button ngbDropdownItem (click)="saveViewConfig()" [disabled]="!savedViewIsModified" i18n>Save "{{list.activeSavedViewTitle}}"</button>
|
||||||
<button ngbDropdownItem (click)="saveViewConfig()" [disabled]="!savedViewIsModified" i18n>Save "{{list.activeSavedViewTitle}}"</button>
|
}
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<button ngbDropdownItem (click)="saveViewConfigAs()" *pngxIfPermissions="{ action: PermissionAction.Add, type: PermissionType.SavedView }" i18n>Save as...</button>
|
<button ngbDropdownItem (click)="saveViewConfigAs()" *pngxIfPermissions="{ action: PermissionAction.Add, type: PermissionType.SavedView }" i18n>Save as...</button>
|
||||||
<a ngbDropdownItem routerLink="/savedviews" *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.SavedView }" i18n>All saved views</a>
|
<a ngbDropdownItem routerLink="/savedviews" *pngxIfPermissions="{ action: PermissionAction.View, type: PermissionType.SavedView }" i18n>All saved views</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -452,7 +452,7 @@ describe('DocumentListComponent', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should handle error on view saving', () => {
|
it('should handle error on view saving', () => {
|
||||||
component.list.activateSavedView({
|
const view: SavedView = {
|
||||||
id: 10,
|
id: 10,
|
||||||
name: 'Saved View 10',
|
name: 'Saved View 10',
|
||||||
sort_field: 'added',
|
sort_field: 'added',
|
||||||
@@ -463,7 +463,16 @@ describe('DocumentListComponent', () => {
|
|||||||
value: '20',
|
value: '20',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
})
|
}
|
||||||
|
jest.spyOn(savedViewService, 'getCached').mockReturnValue(of(view))
|
||||||
|
const queryParams = { view: view.id.toString() }
|
||||||
|
jest
|
||||||
|
.spyOn(activatedRoute, 'queryParamMap', 'get')
|
||||||
|
.mockReturnValue(of(convertToParamMap(queryParams)))
|
||||||
|
activatedRoute.snapshot.queryParams = queryParams
|
||||||
|
router.routerState.snapshot.url = '/view/10/'
|
||||||
|
fixture.detectChanges()
|
||||||
|
|
||||||
const toastErrorSpy = jest.spyOn(toastService, 'showError')
|
const toastErrorSpy = jest.spyOn(toastService, 'showError')
|
||||||
jest
|
jest
|
||||||
.spyOn(savedViewService, 'patch')
|
.spyOn(savedViewService, 'patch')
|
||||||
@@ -475,6 +484,40 @@ describe('DocumentListComponent', () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should not save a view without object change permissions', () => {
|
||||||
|
const view: SavedView = {
|
||||||
|
id: 10,
|
||||||
|
name: 'Saved View 10',
|
||||||
|
sort_field: 'added',
|
||||||
|
sort_reverse: true,
|
||||||
|
filter_rules: [
|
||||||
|
{
|
||||||
|
rule_type: FILTER_HAS_TAGS_ANY,
|
||||||
|
value: '20',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
owner: 999,
|
||||||
|
user_can_change: false,
|
||||||
|
}
|
||||||
|
jest.spyOn(savedViewService, 'getCached').mockReturnValue(of(view))
|
||||||
|
jest
|
||||||
|
.spyOn(permissionService, 'currentUserHasObjectPermissions')
|
||||||
|
.mockReturnValue(false)
|
||||||
|
const queryParams = { view: view.id.toString() }
|
||||||
|
jest
|
||||||
|
.spyOn(activatedRoute, 'queryParamMap', 'get')
|
||||||
|
.mockReturnValue(of(convertToParamMap(queryParams)))
|
||||||
|
activatedRoute.snapshot.queryParams = queryParams
|
||||||
|
router.routerState.snapshot.url = '/view/10/'
|
||||||
|
fixture.detectChanges()
|
||||||
|
|
||||||
|
const patchSpy = jest.spyOn(savedViewService, 'patch')
|
||||||
|
|
||||||
|
component.saveViewConfig()
|
||||||
|
|
||||||
|
expect(patchSpy).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
it('should support edited view saving as', () => {
|
it('should support edited view saving as', () => {
|
||||||
const view: SavedView = {
|
const view: SavedView = {
|
||||||
id: 10,
|
id: 10,
|
||||||
|
|||||||
@@ -47,7 +47,10 @@ import { UsernamePipe } from 'src/app/pipes/username.pipe'
|
|||||||
import { DocumentListViewService } from 'src/app/services/document-list-view.service'
|
import { DocumentListViewService } from 'src/app/services/document-list-view.service'
|
||||||
import { HotKeyService } from 'src/app/services/hot-key.service'
|
import { HotKeyService } from 'src/app/services/hot-key.service'
|
||||||
import { OpenDocumentsService } from 'src/app/services/open-documents.service'
|
import { OpenDocumentsService } from 'src/app/services/open-documents.service'
|
||||||
import { PermissionsService } from 'src/app/services/permissions.service'
|
import {
|
||||||
|
PermissionAction,
|
||||||
|
PermissionsService,
|
||||||
|
} from 'src/app/services/permissions.service'
|
||||||
import { SavedViewService } from 'src/app/services/rest/saved-view.service'
|
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 { ToastService } from 'src/app/services/toast.service'
|
import { ToastService } from 'src/app/services/toast.service'
|
||||||
@@ -148,12 +151,18 @@ export class DocumentListComponent
|
|||||||
|
|
||||||
unmodifiedFilterRules: FilterRule[] = []
|
unmodifiedFilterRules: FilterRule[] = []
|
||||||
private unmodifiedSavedView: SavedView
|
private unmodifiedSavedView: SavedView
|
||||||
|
private activeSavedView: SavedView | null = null
|
||||||
|
|
||||||
private unsubscribeNotifier: Subject<any> = new Subject()
|
private unsubscribeNotifier: Subject<any> = new Subject()
|
||||||
|
|
||||||
get savedViewIsModified(): boolean {
|
get savedViewIsModified(): boolean {
|
||||||
if (!this.list.activeSavedViewId || !this.unmodifiedSavedView) return false
|
if (
|
||||||
else {
|
!this.list.activeSavedViewId ||
|
||||||
|
!this.unmodifiedSavedView ||
|
||||||
|
!this.activeSavedViewCanChange
|
||||||
|
) {
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
return (
|
return (
|
||||||
this.unmodifiedSavedView.sort_field !== this.list.sortField ||
|
this.unmodifiedSavedView.sort_field !== this.list.sortField ||
|
||||||
this.unmodifiedSavedView.sort_reverse !== this.list.sortReverse ||
|
this.unmodifiedSavedView.sort_reverse !== this.list.sortReverse ||
|
||||||
@@ -180,6 +189,16 @@ export class DocumentListComponent
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get activeSavedViewCanChange(): boolean {
|
||||||
|
if (!this.activeSavedView) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return this.permissionService.currentUserHasObjectPermissions(
|
||||||
|
PermissionAction.Change,
|
||||||
|
this.activeSavedView
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
get isFiltered() {
|
get isFiltered() {
|
||||||
return !!this.filterEditor?.rulesModified
|
return !!this.filterEditor?.rulesModified
|
||||||
}
|
}
|
||||||
@@ -256,11 +275,13 @@ export class DocumentListComponent
|
|||||||
.pipe(takeUntil(this.unsubscribeNotifier))
|
.pipe(takeUntil(this.unsubscribeNotifier))
|
||||||
.subscribe(({ view }) => {
|
.subscribe(({ view }) => {
|
||||||
if (!view) {
|
if (!view) {
|
||||||
|
this.activeSavedView = null
|
||||||
this.router.navigate(['404'], {
|
this.router.navigate(['404'], {
|
||||||
replaceUrl: true,
|
replaceUrl: true,
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
this.activeSavedView = view
|
||||||
this.unmodifiedSavedView = view
|
this.unmodifiedSavedView = view
|
||||||
this.list.activateSavedViewWithQueryParams(
|
this.list.activateSavedViewWithQueryParams(
|
||||||
view,
|
view,
|
||||||
@@ -284,6 +305,7 @@ export class DocumentListComponent
|
|||||||
// loading a saved view on /documents
|
// loading a saved view on /documents
|
||||||
this.loadViewConfig(parseInt(queryParams.get('view')))
|
this.loadViewConfig(parseInt(queryParams.get('view')))
|
||||||
} else {
|
} else {
|
||||||
|
this.activeSavedView = null
|
||||||
this.list.activateSavedView(null)
|
this.list.activateSavedView(null)
|
||||||
this.list.loadFromQueryParams(queryParams)
|
this.list.loadFromQueryParams(queryParams)
|
||||||
this.unmodifiedFilterRules = []
|
this.unmodifiedFilterRules = []
|
||||||
@@ -366,7 +388,7 @@ export class DocumentListComponent
|
|||||||
}
|
}
|
||||||
|
|
||||||
saveViewConfig() {
|
saveViewConfig() {
|
||||||
if (this.list.activeSavedViewId != null) {
|
if (this.list.activeSavedViewId != null && this.activeSavedViewCanChange) {
|
||||||
let savedView: SavedView = {
|
let savedView: SavedView = {
|
||||||
id: this.list.activeSavedViewId,
|
id: this.list.activeSavedViewId,
|
||||||
filter_rules: this.list.filterRules,
|
filter_rules: this.list.filterRules,
|
||||||
@@ -380,6 +402,7 @@ export class DocumentListComponent
|
|||||||
.pipe(first())
|
.pipe(first())
|
||||||
.subscribe({
|
.subscribe({
|
||||||
next: (view) => {
|
next: (view) => {
|
||||||
|
this.activeSavedView = view
|
||||||
this.unmodifiedSavedView = view
|
this.unmodifiedSavedView = view
|
||||||
this.toastService.showInfo(
|
this.toastService.showInfo(
|
||||||
$localize`View "${this.list.activeSavedViewTitle}" saved successfully.`
|
$localize`View "${this.list.activeSavedViewTitle}" saved successfully.`
|
||||||
@@ -401,6 +424,11 @@ export class DocumentListComponent
|
|||||||
.getCached(viewID)
|
.getCached(viewID)
|
||||||
.pipe(first())
|
.pipe(first())
|
||||||
.subscribe((view) => {
|
.subscribe((view) => {
|
||||||
|
if (!view) {
|
||||||
|
this.activeSavedView = null
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.activeSavedView = view
|
||||||
this.unmodifiedSavedView = view
|
this.unmodifiedSavedView = view
|
||||||
this.list.activateSavedView(view)
|
this.list.activateSavedView(view)
|
||||||
this.list.reload(() => {
|
this.list.reload(() => {
|
||||||
|
|||||||
@@ -25,15 +25,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
<label class="form-label" for="name_{{view.id}}" i18n>Actions</label>
|
@if (canDeleteSavedView(view)) {
|
||||||
<pngx-confirm-button
|
<label class="form-label" for="name_{{view.id}}" i18n>Actions</label>
|
||||||
label="Delete"
|
<pngx-confirm-button
|
||||||
i18n-label
|
label="Delete"
|
||||||
(confirm)="deleteSavedView(view)"
|
i18n-label
|
||||||
*pngxIfPermissions="{ action: PermissionAction.Delete, type: PermissionType.SavedView }"
|
(confirm)="deleteSavedView(view)"
|
||||||
buttonClasses="btn-sm btn-outline-danger form-control"
|
*pngxIfPermissions="{ action: PermissionAction.Delete, type: PermissionType.SavedView }"
|
||||||
iconName="trash">
|
buttonClasses="btn-sm btn-outline-danger form-control"
|
||||||
</pngx-confirm-button>
|
iconName="trash">
|
||||||
|
</pngx-confirm-button>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'
|
|||||||
import { provideHttpClientTesting } from '@angular/common/http/testing'
|
import { provideHttpClientTesting } from '@angular/common/http/testing'
|
||||||
import { ComponentFixture, TestBed } from '@angular/core/testing'
|
import { ComponentFixture, TestBed } from '@angular/core/testing'
|
||||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
|
||||||
import { By } from '@angular/platform-browser'
|
|
||||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
|
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
|
||||||
import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons'
|
import { NgxBootstrapIconsModule, allIcons } from 'ngx-bootstrap-icons'
|
||||||
import { of, throwError } from 'rxjs'
|
import { of, throwError } from 'rxjs'
|
||||||
@@ -57,6 +56,8 @@ describe('SavedViewsComponent', () => {
|
|||||||
provide: PermissionsService,
|
provide: PermissionsService,
|
||||||
useValue: {
|
useValue: {
|
||||||
currentUserCan: () => true,
|
currentUserCan: () => true,
|
||||||
|
currentUserHasObjectPermissions: () => true,
|
||||||
|
currentUserOwnsObject: () => true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -96,12 +97,11 @@ describe('SavedViewsComponent', () => {
|
|||||||
const toastErrorSpy = jest.spyOn(toastService, 'showError')
|
const toastErrorSpy = jest.spyOn(toastService, 'showError')
|
||||||
const toastSpy = jest.spyOn(toastService, 'show')
|
const toastSpy = jest.spyOn(toastService, 'show')
|
||||||
const savedViewPatchSpy = jest.spyOn(savedViewService, 'patchMany')
|
const savedViewPatchSpy = jest.spyOn(savedViewService, 'patchMany')
|
||||||
|
const control = component.savedViewsForm
|
||||||
const toggle = fixture.debugElement.query(
|
.get('savedViews')
|
||||||
By.css('.form-check.form-switch input')
|
.get(savedViews[0].id.toString())
|
||||||
)
|
.get('show_on_dashboard')
|
||||||
toggle.nativeElement.checked = true
|
control.setValue(!savedViews[0].show_on_dashboard)
|
||||||
toggle.nativeElement.dispatchEvent(new Event('change'))
|
|
||||||
|
|
||||||
// saved views error first
|
// saved views error first
|
||||||
savedViewPatchSpy.mockReturnValueOnce(
|
savedViewPatchSpy.mockReturnValueOnce(
|
||||||
@@ -116,6 +116,7 @@ describe('SavedViewsComponent', () => {
|
|||||||
|
|
||||||
// succeed saved views
|
// succeed saved views
|
||||||
savedViewPatchSpy.mockReturnValueOnce(of(savedViews as SavedView[]))
|
savedViewPatchSpy.mockReturnValueOnce(of(savedViews as SavedView[]))
|
||||||
|
control.setValue(savedViews[0].show_on_dashboard)
|
||||||
component.save()
|
component.save()
|
||||||
expect(toastErrorSpy).not.toHaveBeenCalled()
|
expect(toastErrorSpy).not.toHaveBeenCalled()
|
||||||
expect(savedViewPatchSpy).toHaveBeenCalled()
|
expect(savedViewPatchSpy).toHaveBeenCalled()
|
||||||
@@ -127,25 +128,21 @@ describe('SavedViewsComponent', () => {
|
|||||||
expect(patchSpy).not.toHaveBeenCalled()
|
expect(patchSpy).not.toHaveBeenCalled()
|
||||||
|
|
||||||
const view = savedViews[0]
|
const view = savedViews[0]
|
||||||
const toggle = fixture.debugElement.query(
|
component.savedViewsForm
|
||||||
By.css('.form-check.form-switch input')
|
.get('savedViews')
|
||||||
)
|
.get(view.id.toString())
|
||||||
toggle.nativeElement.checked = true
|
.get('show_on_dashboard')
|
||||||
toggle.nativeElement.dispatchEvent(new Event('change'))
|
.setValue(!view.show_on_dashboard)
|
||||||
// register change
|
|
||||||
component.savedViewsForm.get('savedViews').get(view.id.toString()).value[
|
|
||||||
'show_on_dashboard'
|
|
||||||
] = !view.show_on_dashboard
|
|
||||||
fixture.detectChanges()
|
fixture.detectChanges()
|
||||||
|
|
||||||
component.save()
|
component.save()
|
||||||
expect(patchSpy).toHaveBeenCalledWith([
|
expect(patchSpy).toHaveBeenCalledWith([
|
||||||
{
|
expect.objectContaining({
|
||||||
id: view.id,
|
id: view.id,
|
||||||
name: view.name,
|
name: view.name,
|
||||||
show_in_sidebar: view.show_in_sidebar,
|
show_in_sidebar: view.show_in_sidebar,
|
||||||
show_on_dashboard: !view.show_on_dashboard,
|
show_on_dashboard: !view.show_on_dashboard,
|
||||||
},
|
}),
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -162,14 +159,17 @@ describe('SavedViewsComponent', () => {
|
|||||||
|
|
||||||
it('should support reset', () => {
|
it('should support reset', () => {
|
||||||
const view = savedViews[0]
|
const view = savedViews[0]
|
||||||
component.savedViewsForm.get('savedViews').get(view.id.toString()).value[
|
component.savedViewsForm
|
||||||
'show_on_dashboard'
|
.get('savedViews')
|
||||||
] = !view.show_on_dashboard
|
.get(view.id.toString())
|
||||||
|
.get('show_on_dashboard')
|
||||||
|
.setValue(!view.show_on_dashboard)
|
||||||
component.reset()
|
component.reset()
|
||||||
expect(
|
expect(
|
||||||
component.savedViewsForm.get('savedViews').get(view.id.toString()).value[
|
component.savedViewsForm
|
||||||
'show_on_dashboard'
|
.get('savedViews')
|
||||||
]
|
.get(view.id.toString())
|
||||||
|
.get('show_on_dashboard').value
|
||||||
).toEqual(view.show_on_dashboard)
|
).toEqual(view.show_on_dashboard)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ import { BehaviorSubject, Observable, takeUntil } from 'rxjs'
|
|||||||
import { DisplayMode } from 'src/app/data/document'
|
import { DisplayMode } from 'src/app/data/document'
|
||||||
import { SavedView } from 'src/app/data/saved-view'
|
import { SavedView } from 'src/app/data/saved-view'
|
||||||
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
import { IfPermissionsDirective } from 'src/app/directives/if-permissions.directive'
|
||||||
|
import {
|
||||||
|
PermissionAction,
|
||||||
|
PermissionsService,
|
||||||
|
} from 'src/app/services/permissions.service'
|
||||||
import { SavedViewService } from 'src/app/services/rest/saved-view.service'
|
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 { ToastService } from 'src/app/services/toast.service'
|
import { ToastService } from 'src/app/services/toast.service'
|
||||||
@@ -41,6 +45,7 @@ export class SavedViewsComponent
|
|||||||
implements OnInit, OnDestroy
|
implements OnInit, OnDestroy
|
||||||
{
|
{
|
||||||
private savedViewService = inject(SavedViewService)
|
private savedViewService = inject(SavedViewService)
|
||||||
|
private permissionsService = inject(PermissionsService)
|
||||||
private settings = inject(SettingsService)
|
private settings = inject(SettingsService)
|
||||||
private toastService = inject(ToastService)
|
private toastService = inject(ToastService)
|
||||||
|
|
||||||
@@ -95,16 +100,20 @@ export class SavedViewsComponent
|
|||||||
display_mode: view.display_mode,
|
display_mode: view.display_mode,
|
||||||
display_fields: view.display_fields,
|
display_fields: view.display_fields,
|
||||||
}
|
}
|
||||||
|
const canEdit = this.canEditSavedView(view)
|
||||||
this.savedViewsGroup.addControl(
|
this.savedViewsGroup.addControl(
|
||||||
view.id.toString(),
|
view.id.toString(),
|
||||||
new FormGroup({
|
new FormGroup({
|
||||||
id: new FormControl(null),
|
id: new FormControl({ value: null, disabled: !canEdit }),
|
||||||
name: new FormControl(null),
|
name: new FormControl({ value: null, disabled: !canEdit }),
|
||||||
show_on_dashboard: new FormControl(null),
|
show_on_dashboard: new FormControl({
|
||||||
show_in_sidebar: new FormControl(null),
|
value: null,
|
||||||
page_size: new FormControl(null),
|
disabled: !canEdit,
|
||||||
display_mode: new FormControl(null),
|
}),
|
||||||
display_fields: new FormControl([]),
|
show_in_sidebar: new FormControl({ value: null, disabled: !canEdit }),
|
||||||
|
page_size: new FormControl({ value: null, disabled: !canEdit }),
|
||||||
|
display_mode: new FormControl({ value: null, disabled: !canEdit }),
|
||||||
|
display_fields: new FormControl({ value: [], disabled: !canEdit }),
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -126,6 +135,9 @@ export class SavedViewsComponent
|
|||||||
}
|
}
|
||||||
|
|
||||||
public deleteSavedView(savedView: SavedView) {
|
public deleteSavedView(savedView: SavedView) {
|
||||||
|
if (!this.canDeleteSavedView(savedView)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this.savedViewService.delete(savedView).subscribe(() => {
|
this.savedViewService.delete(savedView).subscribe(() => {
|
||||||
this.savedViewsGroup.removeControl(savedView.id.toString())
|
this.savedViewsGroup.removeControl(savedView.id.toString())
|
||||||
this.savedViews.splice(this.savedViews.indexOf(savedView), 1)
|
this.savedViews.splice(this.savedViews.indexOf(savedView), 1)
|
||||||
@@ -148,9 +160,9 @@ export class SavedViewsComponent
|
|||||||
// only patch views that have actually changed
|
// only patch views that have actually changed
|
||||||
const changed: SavedView[] = []
|
const changed: SavedView[] = []
|
||||||
Object.values(this.savedViewsGroup.controls)
|
Object.values(this.savedViewsGroup.controls)
|
||||||
.filter((g: FormGroup) => !g.pristine)
|
.filter((g: FormGroup) => g.enabled && !g.pristine)
|
||||||
.forEach((group: FormGroup) => {
|
.forEach((group: FormGroup) => {
|
||||||
changed.push(group.value)
|
changed.push(group.getRawValue())
|
||||||
})
|
})
|
||||||
if (changed.length) {
|
if (changed.length) {
|
||||||
this.savedViewService.patchMany(changed).subscribe({
|
this.savedViewService.patchMany(changed).subscribe({
|
||||||
@@ -167,4 +179,15 @@ export class SavedViewsComponent
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public canEditSavedView(view: SavedView): boolean {
|
||||||
|
return this.permissionsService.currentUserHasObjectPermissions(
|
||||||
|
PermissionAction.Change,
|
||||||
|
view
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public canDeleteSavedView(view: SavedView): boolean {
|
||||||
|
return this.permissionsService.currentUserOwnsObject(view)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user