Merge branch 'dev' into fix-consume-timeout
This commit is contained in:
commit
184204e039
@ -94,6 +94,10 @@ Object.defineProperty(navigator, 'clipboard', {
|
||||
})
|
||||
Object.defineProperty(navigator, 'canShare', { value: () => true })
|
||||
Object.defineProperty(window, 'ResizeObserver', { value: mock() })
|
||||
Object.defineProperty(window, 'location', {
|
||||
configurable: true,
|
||||
value: { reload: jest.fn() },
|
||||
})
|
||||
|
||||
HTMLCanvasElement.prototype.getContext = <
|
||||
typeof HTMLCanvasElement.prototype.getContext
|
||||
|
@ -309,10 +309,15 @@ describe('SettingsComponent', () => {
|
||||
component.store.getValue()['displayLanguage'] = 'en-US'
|
||||
component.store.getValue()['updateCheckingEnabled'] = false
|
||||
component.settingsForm.value.displayLanguage = 'en-GB'
|
||||
component.settingsForm.value.updateCheckingEnabled = true
|
||||
jest.spyOn(settingsService, 'storeSettings').mockReturnValueOnce(of(true))
|
||||
jest.spyOn(settingsService, 'storeSettings').mockReturnValue(of(true))
|
||||
component.saveSettings()
|
||||
expect(toast.actionName).toEqual('Reload now')
|
||||
|
||||
component.settingsForm.value.updateCheckingEnabled = true
|
||||
component.saveSettings()
|
||||
|
||||
expect(toast.actionName).toEqual('Reload now')
|
||||
toast.action()
|
||||
})
|
||||
|
||||
it('should allow setting theme color, visually apply change immediately but not save', () => {
|
||||
|
@ -4,16 +4,16 @@
|
||||
(click)="isMenuCollapsed = !isMenuCollapsed">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<a class="navbar-brand d-flex col-auto col-md-3 col-lg-2 me-0 px-3 py-3 order-sm-0"
|
||||
[ngClass]="{ 'slim': slimSidebarEnabled, 'd-flex col-auto col-md-3 col-lg-2' : !slimSidebarEnabled, 'py-3' : !customAppTitle?.length || slimSidebarEnabled, 'py-2': customAppTitle?.length }"
|
||||
<a class="navbar-brand d-flex align-items-center me-0 px-3 py-3 order-sm-0"
|
||||
[ngClass]="{ 'slim': slimSidebarEnabled, 'col-auto col-md-3 col-lg-2' : !slimSidebarEnabled, 'py-3' : !customAppTitle?.length || slimSidebarEnabled, 'py-2': customAppTitle?.length }"
|
||||
routerLink="/dashboard"
|
||||
tourAnchor="tour.intro">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 198.43 238.91" width="1em" class="me-2" fill="currentColor">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 198.43 238.91" width="1em" height="1.5em" fill="currentColor">
|
||||
<path
|
||||
d="M194.7,0C164.22,70.94,17.64,79.74,64.55,194.06c.58,1.47-10.85,17-18.47,29.9-1.76-6.45-3.81-13.48-3.52-14.07,38.11-45.14-27.26-70.65-30.78-107.58C-4.64,131.62-10.5,182.92,39,212.53c.3,0,2.64,11.14,3.81,16.71a58.55,58.55,0,0,0-2.93,6.45c-1.17,2.93,7.62,2.64,7.62,3.22.88-.29,21.7-36.93,22.28-37.23C187.67,174.72,208.48,68.6,194.7,0ZM134.61,74.75C79.5,124,70.12,160.64,71.88,178.53,53.41,134.85,107.64,86.77,134.61,74.75ZM28.2,145.11c10.55,9.67,28.14,39.28,13.19,56.57C44.91,193.77,46.08,175.89,28.2,145.11Z"
|
||||
transform="translate(0 0)" />
|
||||
</svg>
|
||||
<div class="ms-2 d-inline-block" [class.visually-hidden]="slimSidebarEnabled">
|
||||
<div class="ms-3 d-inline-block" [class.d-md-none]="slimSidebarEnabled">
|
||||
@if (customAppTitle?.length) {
|
||||
<div class="d-flex flex-column align-items-start">
|
||||
<span class="title">{{customAppTitle}}</span>
|
||||
|
@ -493,12 +493,17 @@ describe('FilterableDropdownComponent & FilterableDropdownSelectionModel', () =>
|
||||
expect(changedResult.getExcludedItems()).toEqual(items)
|
||||
}))
|
||||
|
||||
it('FilterableDropdownSelectionModel should sort items by state', () => {
|
||||
component.items = items
|
||||
it('selection model should sort items by state', () => {
|
||||
component.items = items.concat([{ id: null, name: 'Null B' }])
|
||||
component.selectionModel = selectionModel
|
||||
selectionModel.toggle(items[1].id)
|
||||
selectionModel.apply()
|
||||
expect(selectionModel.itemsSorted).toEqual([nullItem, items[1], items[0]])
|
||||
expect(selectionModel.itemsSorted).toEqual([
|
||||
nullItem,
|
||||
{ id: null, name: 'Null B' },
|
||||
items[1],
|
||||
items[0],
|
||||
])
|
||||
})
|
||||
|
||||
it('should set support create, keep open model and call createRef method', fakeAsync(() => {
|
||||
@ -542,4 +547,34 @@ describe('FilterableDropdownComponent & FilterableDropdownSelectionModel', () =>
|
||||
tick(300)
|
||||
expect(createSpy).toHaveBeenCalled()
|
||||
}))
|
||||
|
||||
it('should exclude item and trigger change event', () => {
|
||||
const id = 1
|
||||
const state = ToggleableItemState.Selected
|
||||
component.selectionModel = selectionModel
|
||||
component.manyToOne = true
|
||||
component.selectionModel.singleSelect = true
|
||||
component.selectionModel.intersection = Intersection.Include
|
||||
component.selectionModel['temporarySelectionStates'].set(id, state)
|
||||
const changedSpy = jest.spyOn(component.selectionModel.changed, 'next')
|
||||
component.selectionModel.exclude(id)
|
||||
expect(component.selectionModel.temporaryLogicalOperator).toBe(
|
||||
LogicalOperator.And
|
||||
)
|
||||
expect(component.selectionModel['temporarySelectionStates'].get(id)).toBe(
|
||||
ToggleableItemState.Excluded
|
||||
)
|
||||
expect(component.selectionModel['temporarySelectionStates'].size).toBe(1)
|
||||
expect(changedSpy).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should initialize selection states and apply changes', () => {
|
||||
selectionModel.items = items
|
||||
const map = new Map<number, ToggleableItemState>()
|
||||
map.set(1, ToggleableItemState.Selected)
|
||||
map.set(2, ToggleableItemState.Excluded)
|
||||
selectionModel.init(map)
|
||||
expect(selectionModel.getSelectedItems()).toEqual([items[0]])
|
||||
expect(selectionModel.getExcludedItems()).toEqual([items[1]])
|
||||
})
|
||||
})
|
||||
|
@ -275,7 +275,7 @@ export class FilterableDropdownSelectionModel {
|
||||
)
|
||||
}
|
||||
|
||||
init(map) {
|
||||
init(map: Map<number, ToggleableItemState>) {
|
||||
this.temporarySelectionStates = map
|
||||
this.apply()
|
||||
}
|
||||
|
@ -118,4 +118,18 @@ describe('SelectComponent', () => {
|
||||
tick(3000)
|
||||
expect(clearSpy).toHaveBeenCalled()
|
||||
}))
|
||||
|
||||
it('should emit filtered documents', () => {
|
||||
component.value = 10
|
||||
component.items = items
|
||||
const emitSpy = jest.spyOn(component.filterDocuments, 'emit')
|
||||
component.onFilterDocuments()
|
||||
expect(emitSpy).toHaveBeenCalledWith([items[2]])
|
||||
})
|
||||
|
||||
it('should return the correct filter button title', () => {
|
||||
component.title = 'Tag'
|
||||
const expectedTitle = `Filter documents with this ${component.title}`
|
||||
expect(component.filterButtonTitle).toEqual(expectedTitle)
|
||||
})
|
||||
})
|
||||
|
@ -169,4 +169,12 @@ describe('TagsComponent', () => {
|
||||
expect(component.getTag(2)).toEqual(tags[1])
|
||||
expect(component.getTag(4)).toBeUndefined()
|
||||
})
|
||||
|
||||
it('should emit filtered documents', () => {
|
||||
component.value = [10]
|
||||
component.tags = tags
|
||||
const emitSpy = jest.spyOn(component.filterDocuments, 'emit')
|
||||
component.onFilterDocuments()
|
||||
expect(emitSpy).toHaveBeenCalledWith([tags[2]])
|
||||
})
|
||||
})
|
||||
|
@ -119,6 +119,8 @@ describe('UploadFileWidgetComponent', () => {
|
||||
const processingStatus = new FileStatus()
|
||||
processingStatus.phase = FileStatusPhase.WORKING
|
||||
expect(component.getStatusColor(processingStatus)).toEqual('primary')
|
||||
processingStatus.phase = FileStatusPhase.UPLOADING
|
||||
expect(component.getStatusColor(processingStatus)).toEqual('primary')
|
||||
const failedStatus = new FileStatus()
|
||||
failedStatus.phase = FileStatusPhase.FAILED
|
||||
expect(component.getStatusColor(failedStatus)).toEqual('danger')
|
||||
|
@ -17,6 +17,7 @@ describe('DirtyFormGuard', () => {
|
||||
let guard: DirtyFormGuard
|
||||
let component: DirtyComponent
|
||||
let route: ActivatedRoute
|
||||
let modalService: NgbModal
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
@ -37,6 +38,7 @@ describe('DirtyFormGuard', () => {
|
||||
|
||||
guard = TestBed.inject(DirtyFormGuard)
|
||||
route = TestBed.inject(ActivatedRoute)
|
||||
modalService = TestBed.inject(NgbModal)
|
||||
const fixture = TestBed.createComponent(GenericDirtyComponent)
|
||||
component = fixture.componentInstance
|
||||
|
||||
@ -57,9 +59,14 @@ describe('DirtyFormGuard', () => {
|
||||
component.isDirty$ = true
|
||||
const confirmSpy = jest.spyOn(guard, 'confirmChanges')
|
||||
const canDeactivate = guard.canDeactivate(component, route.snapshot)
|
||||
let modal
|
||||
modalService.activeInstances.subscribe((instances) => {
|
||||
modal = instances[0]
|
||||
})
|
||||
canDeactivate.subscribe()
|
||||
|
||||
expect(canDeactivate).toHaveProperty('source') // Observable
|
||||
expect(confirmSpy).toHaveBeenCalled()
|
||||
modal.componentInstance.confirmClicked.next()
|
||||
})
|
||||
})
|
||||
|
@ -108,6 +108,7 @@ describe('OpenDocumentsService', () => {
|
||||
})
|
||||
|
||||
it('should close documents', () => {
|
||||
openDocumentsService.closeDocument({ id: 999 } as any)
|
||||
subscriptions.push(
|
||||
openDocumentsService.openDocument(documents[0]).subscribe()
|
||||
)
|
||||
@ -128,15 +129,21 @@ describe('OpenDocumentsService', () => {
|
||||
subscriptions.push(
|
||||
openDocumentsService.openDocument(documents[0]).subscribe()
|
||||
)
|
||||
openDocumentsService.setDirty({ id: 999 }, true) // coverage
|
||||
openDocumentsService.setDirty(documents[0], false)
|
||||
expect(openDocumentsService.hasDirty()).toBeFalsy()
|
||||
openDocumentsService.setDirty(documents[0], true)
|
||||
expect(openDocumentsService.hasDirty()).toBeTruthy()
|
||||
let openModal
|
||||
modalService.activeInstances.subscribe((instances) => {
|
||||
openModal = instances[0]
|
||||
})
|
||||
const modalSpy = jest.spyOn(modalService, 'open')
|
||||
subscriptions.push(
|
||||
openDocumentsService.closeDocument(documents[0]).subscribe()
|
||||
)
|
||||
expect(modalSpy).toHaveBeenCalled()
|
||||
openModal.componentInstance.confirmClicked.next()
|
||||
})
|
||||
|
||||
it('should allow set dirty status, warn on closeAll', () => {
|
||||
@ -148,9 +155,14 @@ describe('OpenDocumentsService', () => {
|
||||
)
|
||||
openDocumentsService.setDirty(documents[0], true)
|
||||
expect(openDocumentsService.hasDirty()).toBeTruthy()
|
||||
let openModal
|
||||
modalService.activeInstances.subscribe((instances) => {
|
||||
openModal = instances[0]
|
||||
})
|
||||
const modalSpy = jest.spyOn(modalService, 'open')
|
||||
subscriptions.push(openDocumentsService.closeAll().subscribe())
|
||||
expect(modalSpy).toHaveBeenCalled()
|
||||
openModal.componentInstance.confirmClicked.next()
|
||||
})
|
||||
|
||||
it('should load open documents from localStorage', () => {
|
||||
|
@ -58,12 +58,25 @@ describe(`Additional service tests for MailAccountService`, () => {
|
||||
it('should support patchMany', () => {
|
||||
subscription = service.patchMany(mail_accounts).subscribe()
|
||||
mail_accounts.forEach((mail_account) => {
|
||||
const reqs = httpTestingController.match(
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/${mail_account.id}/`
|
||||
)
|
||||
expect(reqs).toHaveLength(1)
|
||||
expect(reqs[0].request.method).toEqual('PATCH')
|
||||
expect(req.request.method).toEqual('PATCH')
|
||||
req.flush(mail_account)
|
||||
})
|
||||
httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/?page=1&page_size=100000`
|
||||
)
|
||||
})
|
||||
|
||||
it('should support reload', () => {
|
||||
service['reload']()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/?page=1&page_size=100000`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
req.flush({ results: mail_accounts })
|
||||
expect(service.allAccounts).toEqual(mail_accounts)
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
|
@ -76,12 +76,26 @@ describe(`Additional service tests for MailRuleService`, () => {
|
||||
it('should support patchMany', () => {
|
||||
subscription = service.patchMany(mail_rules).subscribe()
|
||||
mail_rules.forEach((mail_rule) => {
|
||||
const reqs = httpTestingController.match(
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/${mail_rule.id}/`
|
||||
)
|
||||
expect(reqs).toHaveLength(1)
|
||||
expect(reqs[0].request.method).toEqual('PATCH')
|
||||
expect(req.request.method).toEqual('PATCH')
|
||||
req.flush(mail_rule)
|
||||
})
|
||||
const reloadReq = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/?page=1&page_size=100000`
|
||||
)
|
||||
reloadReq.flush({ results: mail_rules })
|
||||
})
|
||||
|
||||
it('should support reload', () => {
|
||||
service['reload']()
|
||||
const req = httpTestingController.expectOne(
|
||||
`${environment.apiBaseUrl}${endpoint}/?page=1&page_size=100000`
|
||||
)
|
||||
expect(req.request.method).toEqual('GET')
|
||||
req.flush({ results: mail_rules })
|
||||
expect(service.allRules).toEqual(mail_rules)
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
|
@ -262,7 +262,7 @@ a.btn-link:focus-visible,
|
||||
}
|
||||
|
||||
.ng-dropdown-panel .ng-dropdown-panel-items .ng-option.ng-option-marked {
|
||||
background-color: var(--pngx-bg-darker) !important;
|
||||
background-color: var(--pngx-bg-alt) !important;
|
||||
color: var(--pngx-body-color-accent) !important;
|
||||
}
|
||||
|
||||
@ -439,7 +439,7 @@ ul.pagination {
|
||||
color: var(--bs-body-color);
|
||||
|
||||
&:hover, &:focus {
|
||||
background-color: var(--pngx-bg-darker);
|
||||
background-color: var(--pngx-bg-alt);
|
||||
color: var(--bs-body-color);
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ from rest_framework.authtoken.models import Token
|
||||
from rest_framework.filters import OrderingFilter
|
||||
from rest_framework.generics import GenericAPIView
|
||||
from rest_framework.pagination import PageNumberPagination
|
||||
from rest_framework.permissions import DjangoObjectPermissions
|
||||
from rest_framework.permissions import DjangoModelPermissions
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
@ -171,7 +171,7 @@ class ApplicationConfigurationViewSet(ModelViewSet):
|
||||
queryset = ApplicationConfiguration.objects
|
||||
|
||||
serializer_class = ApplicationConfigurationSerializer
|
||||
permission_classes = (IsAuthenticated, DjangoObjectPermissions)
|
||||
permission_classes = (IsAuthenticated, DjangoModelPermissions)
|
||||
|
||||
|
||||
class DisconnectSocialAccountView(GenericAPIView):
|
||||
|
Loading…
x
Reference in New Issue
Block a user