mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-07-28 18:24:38 -05:00
added paperless ui
This commit is contained in:
16
src-ui/src/app/services/auth-guard.service.spec.ts
Normal file
16
src-ui/src/app/services/auth-guard.service.spec.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AuthGuardService } from './auth-guard.service';
|
||||
|
||||
describe('AuthGuardService', () => {
|
||||
let service: AuthGuardService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(AuthGuardService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
20
src-ui/src/app/services/auth-guard.service.ts
Normal file
20
src-ui/src/app/services/auth-guard.service.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { AuthService } from './auth.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class AuthGuardService {
|
||||
|
||||
constructor(public auth: AuthService, public router: Router) { }
|
||||
|
||||
canActivate(): boolean {
|
||||
if (!this.auth.isAuthenticated()) {
|
||||
this.router.navigate(['login']);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
16
src-ui/src/app/services/auth.interceptor.spec.ts
Normal file
16
src-ui/src/app/services/auth.interceptor.spec.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AuthInterceptor } from './auth.interceptor';
|
||||
|
||||
describe('AuthInterceptor', () => {
|
||||
beforeEach(() => TestBed.configureTestingModule({
|
||||
providers: [
|
||||
AuthInterceptor
|
||||
]
|
||||
}));
|
||||
|
||||
it('should be created', () => {
|
||||
const interceptor: AuthInterceptor = TestBed.inject(AuthInterceptor);
|
||||
expect(interceptor).toBeTruthy();
|
||||
});
|
||||
});
|
26
src-ui/src/app/services/auth.interceptor.ts
Normal file
26
src-ui/src/app/services/auth.interceptor.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import {
|
||||
HttpRequest,
|
||||
HttpHandler,
|
||||
HttpEvent,
|
||||
HttpInterceptor
|
||||
} from '@angular/common/http';
|
||||
import { Observable } from 'rxjs';
|
||||
import { AuthService } from './auth.service';
|
||||
|
||||
@Injectable()
|
||||
export class AuthInterceptor implements HttpInterceptor {
|
||||
|
||||
constructor(private authService: AuthService) {}
|
||||
|
||||
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
|
||||
if (this.authService.isAuthenticated()) {
|
||||
request = request.clone({
|
||||
setHeaders: {
|
||||
Authorization: 'Token ' + this.authService.getToken()
|
||||
}
|
||||
});
|
||||
}
|
||||
return next.handle(request);
|
||||
}
|
||||
}
|
16
src-ui/src/app/services/auth.service.spec.ts
Normal file
16
src-ui/src/app/services/auth.service.spec.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AuthService } from './auth.service';
|
||||
|
||||
describe('AuthService', () => {
|
||||
let service: AuthService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(AuthService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
76
src-ui/src/app/services/auth.service.ts
Normal file
76
src-ui/src/app/services/auth.service.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { map } from 'rxjs/operators';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Router } from '@angular/router';
|
||||
import { environment } from 'src/environments/environment';
|
||||
|
||||
interface TokenResponse {
|
||||
token: string
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class AuthService {
|
||||
|
||||
private currentUsername: string
|
||||
|
||||
private token: string
|
||||
|
||||
constructor(private http: HttpClient, private router: Router) {
|
||||
this.token = localStorage.getItem('auth-service:token')
|
||||
if (this.token == null) {
|
||||
this.token = sessionStorage.getItem('auth-service:token')
|
||||
}
|
||||
this.currentUsername = localStorage.getItem('auth-service:currentUsername')
|
||||
if (this.currentUsername == null) {
|
||||
this.currentUsername = sessionStorage.getItem('auth-service:currentUsername')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private requestToken(username: string, password: string): Observable<TokenResponse> {
|
||||
return this.http.post<TokenResponse>(`${environment.apiBaseUrl}token/`, {"username": username, "password": password})
|
||||
}
|
||||
|
||||
isAuthenticated(): boolean {
|
||||
return this.currentUsername != null
|
||||
}
|
||||
|
||||
logout() {
|
||||
this.currentUsername = null
|
||||
this.token = null
|
||||
localStorage.removeItem('auth-service:token')
|
||||
localStorage.removeItem('auth-service:currentUsername')
|
||||
sessionStorage.removeItem('auth-service:token')
|
||||
sessionStorage.removeItem('auth-service:currentUsername')
|
||||
this.router.navigate(['login'])
|
||||
}
|
||||
|
||||
login(username: string, password: string, rememberMe: boolean): Observable<boolean> {
|
||||
return this.requestToken(username,password).pipe(
|
||||
map(tokenResponse => {
|
||||
this.currentUsername = username
|
||||
this.token = tokenResponse.token
|
||||
if (rememberMe) {
|
||||
localStorage.setItem('auth-service:token', this.token)
|
||||
localStorage.setItem('auth-service:currentUsername', this.currentUsername)
|
||||
} else {
|
||||
sessionStorage.setItem('auth-service:token', this.token)
|
||||
sessionStorage.setItem('auth-service:currentUsername', this.currentUsername)
|
||||
}
|
||||
return true
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
getToken(): string {
|
||||
return this.token
|
||||
}
|
||||
|
||||
getCurrentUsername(): string {
|
||||
return this.currentUsername
|
||||
}
|
||||
}
|
16
src-ui/src/app/services/document-list-view.service.spec.ts
Normal file
16
src-ui/src/app/services/document-list-view.service.spec.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { DocumentListViewService } from './document-list-view.service';
|
||||
|
||||
describe('DocumentListViewService', () => {
|
||||
let service: DocumentListViewService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(DocumentListViewService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
101
src-ui/src/app/services/document-list-view.service.ts
Normal file
101
src-ui/src/app/services/document-list-view.service.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { FilterRuleSet } from '../components/filter-editor/filter-editor.component';
|
||||
import { PaperlessDocument } from '../data/paperless-document';
|
||||
import { DocumentService } from './rest/document.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class DocumentListViewService {
|
||||
|
||||
static DEFAULT_SORT_FIELD = 'created'
|
||||
|
||||
static SORT_FIELDS = [
|
||||
{field: "correspondent__name", name: "Correspondent"},
|
||||
{field: 'title', name: 'Title'},
|
||||
{field: 'archive_serial_number', name: 'ASN'},
|
||||
{field: 'created', name: 'Created'},
|
||||
{field: 'added', name: 'Added'},
|
||||
{field: 'modified', name: 'Modified'}
|
||||
]
|
||||
|
||||
documents: PaperlessDocument[] = []
|
||||
currentPage = 1
|
||||
collectionSize: number
|
||||
|
||||
currentFilter = new FilterRuleSet()
|
||||
|
||||
currentSortDirection = 'des'
|
||||
currentSortField = DocumentListViewService.DEFAULT_SORT_FIELD
|
||||
|
||||
reload(onFinish?) {
|
||||
this.documentService.list(
|
||||
this.currentPage,
|
||||
null,
|
||||
this.getOrderingQueryParam(),
|
||||
this.currentFilter.toQueryParams()).subscribe(
|
||||
result => {
|
||||
this.collectionSize = result.count
|
||||
this.documents = result.results
|
||||
if (onFinish) {
|
||||
onFinish()
|
||||
}
|
||||
},
|
||||
error => {
|
||||
if (error.error['detail'] == 'Invalid page.') {
|
||||
this.currentPage = 1
|
||||
this.reload()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
getOrderingQueryParam() {
|
||||
if (DocumentListViewService.SORT_FIELDS.find(f => f.field == this.currentSortField)) {
|
||||
return (this.currentSortDirection == 'des' ? '-' : '') + this.currentSortField
|
||||
} else {
|
||||
return DocumentListViewService.DEFAULT_SORT_FIELD
|
||||
}
|
||||
}
|
||||
|
||||
setFilter(filter: FilterRuleSet) {
|
||||
this.currentFilter = filter
|
||||
}
|
||||
|
||||
getLastPage(): number {
|
||||
return Math.ceil(this.collectionSize / 25)
|
||||
}
|
||||
|
||||
hasNext(doc: number) {
|
||||
if (this.documents) {
|
||||
let index = this.documents.findIndex(d => d.id == doc)
|
||||
return index != -1 && (this.currentPage < this.getLastPage() || (index + 1) < this.documents.length)
|
||||
}
|
||||
}
|
||||
|
||||
getNext(currentDocId: number): Observable<number> {
|
||||
return new Observable(nextDocId => {
|
||||
if (this.documents != null) {
|
||||
|
||||
let index = this.documents.findIndex(d => d.id == currentDocId)
|
||||
|
||||
if (index != -1 && (index + 1) < this.documents.length) {
|
||||
nextDocId.next(this.documents[index+1].id)
|
||||
nextDocId.complete()
|
||||
} else if (index != -1 && this.currentPage < this.getLastPage()) {
|
||||
this.currentPage += 1
|
||||
this.reload(() => {
|
||||
nextDocId.next(this.documents[0].id)
|
||||
nextDocId.complete()
|
||||
})
|
||||
} else {
|
||||
nextDocId.complete()
|
||||
}
|
||||
} else {
|
||||
nextDocId.complete()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
constructor(private documentService: DocumentService) { }
|
||||
}
|
16
src-ui/src/app/services/open-documents.service.spec.ts
Normal file
16
src-ui/src/app/services/open-documents.service.spec.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { OpenDocumentsService } from './open-documents.service';
|
||||
|
||||
describe('OpenDocumentsService', () => {
|
||||
let service: OpenDocumentsService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(OpenDocumentsService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
35
src-ui/src/app/services/open-documents.service.ts
Normal file
35
src-ui/src/app/services/open-documents.service.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { PaperlessDocument } from '../data/paperless-document';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class OpenDocumentsService {
|
||||
|
||||
constructor() { }
|
||||
|
||||
private openDocuments: PaperlessDocument[] = []
|
||||
|
||||
private openDocumentsSubject: Subject<PaperlessDocument[]> = new Subject()
|
||||
|
||||
getOpenDocuments(): Observable<PaperlessDocument[]> {
|
||||
return this.openDocumentsSubject
|
||||
}
|
||||
|
||||
openDocument(doc: PaperlessDocument) {
|
||||
if (this.openDocuments.find(d => d.id == doc.id) == null) {
|
||||
this.openDocuments.push(doc)
|
||||
this.openDocumentsSubject.next(this.openDocuments)
|
||||
}
|
||||
}
|
||||
|
||||
closeDocument(doc: PaperlessDocument) {
|
||||
let index = this.openDocuments.findIndex(d => d.id == doc.id)
|
||||
if (index > -1) {
|
||||
this.openDocuments.splice(index, 1)
|
||||
this.openDocumentsSubject.next(this.openDocuments)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
import { AbstractPaperlessService } from './abstract-paperless-service';
|
||||
|
||||
describe('AbstractPaperlessService', () => {
|
||||
it('should create an instance', () => {
|
||||
expect(new AbstractPaperlessService()).toBeTruthy();
|
||||
});
|
||||
});
|
58
src-ui/src/app/services/rest/abstract-paperless-service.ts
Normal file
58
src-ui/src/app/services/rest/abstract-paperless-service.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import { HttpClient, HttpParams } from '@angular/common/http'
|
||||
import { Observable } from 'rxjs'
|
||||
import { ObjectWithId } from 'src/app/data/object-with-id'
|
||||
import { Results } from 'src/app/data/results'
|
||||
import { environment } from 'src/environments/environment'
|
||||
|
||||
export abstract class AbstractPaperlessService<T extends ObjectWithId> {
|
||||
|
||||
protected baseUrl: string = environment.apiBaseUrl
|
||||
|
||||
constructor(protected http: HttpClient, private resourceName: string) { }
|
||||
|
||||
protected getResourceUrl(id?: number, action?: string): string {
|
||||
let url = `${this.baseUrl}${this.resourceName}/`
|
||||
if (id) {
|
||||
url += `${id}/`
|
||||
if (action) {
|
||||
url += `${action}/`
|
||||
}
|
||||
}
|
||||
return url
|
||||
}
|
||||
|
||||
list(page?: number, pageSize?: number, ordering?: string, extraParams?): Observable<Results<T>> {
|
||||
let httpParams = new HttpParams()
|
||||
if (page) {
|
||||
httpParams = httpParams.set('page', page.toString())
|
||||
}
|
||||
if (pageSize) {
|
||||
httpParams = httpParams.set('page_size', pageSize.toString())
|
||||
}
|
||||
if (ordering) {
|
||||
httpParams = httpParams.set('ordering', ordering)
|
||||
}
|
||||
for (let extraParamKey in extraParams) {
|
||||
if (extraParams[extraParamKey]) {
|
||||
httpParams = httpParams.set(extraParamKey, extraParams[extraParamKey])
|
||||
}
|
||||
}
|
||||
return this.http.get<Results<T>>(this.getResourceUrl(), {params: httpParams})
|
||||
}
|
||||
|
||||
get(id: number): Observable<T> {
|
||||
return this.http.get<T>(this.getResourceUrl(id))
|
||||
}
|
||||
|
||||
create(o: T): Observable<T> {
|
||||
return this.http.post<T>(this.getResourceUrl(), o)
|
||||
}
|
||||
|
||||
delete(o: T): Observable<any> {
|
||||
return this.http.delete(this.getResourceUrl(o.id))
|
||||
}
|
||||
|
||||
update(o: T): Observable<T> {
|
||||
return this.http.put<T>(this.getResourceUrl(o.id), o)
|
||||
}
|
||||
}
|
16
src-ui/src/app/services/rest/correspondent.service.spec.ts
Normal file
16
src-ui/src/app/services/rest/correspondent.service.spec.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CorrespondentService } from './correspondent.service';
|
||||
|
||||
describe('CorrespondentService', () => {
|
||||
let service: CorrespondentService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(CorrespondentService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
15
src-ui/src/app/services/rest/correspondent.service.ts
Normal file
15
src-ui/src/app/services/rest/correspondent.service.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { PaperlessCorrespondent } from 'src/app/data/paperless-correspondent';
|
||||
import { AbstractPaperlessService } from './abstract-paperless-service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class CorrespondentService extends AbstractPaperlessService<PaperlessCorrespondent> {
|
||||
|
||||
constructor(http: HttpClient) {
|
||||
super(http, 'correspondents')
|
||||
}
|
||||
|
||||
}
|
16
src-ui/src/app/services/rest/document-type.service.spec.ts
Normal file
16
src-ui/src/app/services/rest/document-type.service.spec.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { DocumentTypeService } from './document-type.service';
|
||||
|
||||
describe('DocumentTypeService', () => {
|
||||
let service: DocumentTypeService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(DocumentTypeService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
14
src-ui/src/app/services/rest/document-type.service.ts
Normal file
14
src-ui/src/app/services/rest/document-type.service.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { PaperlessDocumentType } from 'src/app/data/paperless-document-type';
|
||||
import { AbstractPaperlessService } from './abstract-paperless-service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class DocumentTypeService extends AbstractPaperlessService<PaperlessDocumentType> {
|
||||
|
||||
constructor(http: HttpClient) {
|
||||
super(http, 'document_types')
|
||||
}
|
||||
}
|
16
src-ui/src/app/services/rest/document.service.spec.ts
Normal file
16
src-ui/src/app/services/rest/document.service.spec.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { DocumentService } from './document.service';
|
||||
|
||||
describe('DocumentService', () => {
|
||||
let service: DocumentService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(DocumentService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
29
src-ui/src/app/services/rest/document.service.ts
Normal file
29
src-ui/src/app/services/rest/document.service.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { PaperlessDocument } from 'src/app/data/paperless-document';
|
||||
import { AbstractPaperlessService } from './abstract-paperless-service';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Observable } from 'rxjs';
|
||||
import { AuthService } from '../auth.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class DocumentService extends AbstractPaperlessService<PaperlessDocument> {
|
||||
|
||||
constructor(http: HttpClient, private auth: AuthService) {
|
||||
super(http, 'documents')
|
||||
}
|
||||
|
||||
getPreviewUrl(id: number): string {
|
||||
return this.getResourceUrl(id, 'preview') + `?auth_token=${this.auth.getToken()}`
|
||||
}
|
||||
|
||||
getThumbUrl(id: number): string {
|
||||
return this.getResourceUrl(id, 'thumb') + `?auth_token=${this.auth.getToken()}`
|
||||
}
|
||||
|
||||
getDownloadUrl(id: number): string {
|
||||
return this.getResourceUrl(id, 'download') + `?auth_token=${this.auth.getToken()}`
|
||||
}
|
||||
|
||||
}
|
16
src-ui/src/app/services/rest/search.service.spec.ts
Normal file
16
src-ui/src/app/services/rest/search.service.spec.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { SearchService } from './search.service';
|
||||
|
||||
describe('SearchService', () => {
|
||||
let service: SearchService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(SearchService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
37
src-ui/src/app/services/rest/search.service.ts
Normal file
37
src-ui/src/app/services/rest/search.service.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { PaperlessDocument } from 'src/app/data/paperless-document';
|
||||
import { environment } from 'src/environments/environment';
|
||||
|
||||
export class SearchResultHighlightedText {
|
||||
text?: string
|
||||
term?: number
|
||||
|
||||
toString(): string {
|
||||
return this.text
|
||||
}
|
||||
}
|
||||
|
||||
export class SearchResult {
|
||||
id?: number
|
||||
title?: string
|
||||
content?: string
|
||||
|
||||
score?: number
|
||||
highlights?: SearchResultHighlightedText[][]
|
||||
|
||||
document?: PaperlessDocument
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class SearchService {
|
||||
|
||||
constructor(private http: HttpClient) { }
|
||||
|
||||
search(query: string): Observable<SearchResult[]> {
|
||||
return this.http.get<SearchResult[]>(`${environment.apiBaseUrl}search/`, {params: new HttpParams().set('query', query)})
|
||||
}
|
||||
}
|
16
src-ui/src/app/services/rest/tag.service.spec.ts
Normal file
16
src-ui/src/app/services/rest/tag.service.spec.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { TagService } from './tag.service';
|
||||
|
||||
describe('TagService', () => {
|
||||
let service: TagService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(TagService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
14
src-ui/src/app/services/rest/tag.service.ts
Normal file
14
src-ui/src/app/services/rest/tag.service.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { PaperlessTag } from 'src/app/data/paperless-tag';
|
||||
import { AbstractPaperlessService } from './abstract-paperless-service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class TagService extends AbstractPaperlessService<PaperlessTag> {
|
||||
|
||||
constructor(http: HttpClient) {
|
||||
super(http, 'tags')
|
||||
}
|
||||
}
|
16
src-ui/src/app/services/toast.service.spec.ts
Normal file
16
src-ui/src/app/services/toast.service.spec.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ToastService } from './toast.service';
|
||||
|
||||
describe('ToastService', () => {
|
||||
let service: ToastService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(ToastService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
52
src-ui/src/app/services/toast.service.ts
Normal file
52
src-ui/src/app/services/toast.service.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Subject } from 'rxjs';
|
||||
|
||||
export class Toast {
|
||||
|
||||
static make(title: string, content: string, delay?: number): Toast {
|
||||
let t = new Toast()
|
||||
t.title = title
|
||||
t.content = content
|
||||
if (delay) {
|
||||
t.delay = delay
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
title: string
|
||||
|
||||
content: string
|
||||
|
||||
delay: number = 5000
|
||||
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class ToastService {
|
||||
|
||||
constructor() { }
|
||||
|
||||
private toasts: Toast[] = []
|
||||
|
||||
private toastSubject: Subject<Toast[]> = new Subject()
|
||||
|
||||
showToast(toast: Toast) {
|
||||
this.toasts.push(toast)
|
||||
this.toastSubject.next(this.toasts)
|
||||
}
|
||||
|
||||
closeToast(toast: Toast) {
|
||||
let index = this.toasts.findIndex(t => t == toast)
|
||||
if (index > -1) {
|
||||
this.toasts.splice(index, 1)
|
||||
this.toastSubject.next(this.toasts)
|
||||
}
|
||||
}
|
||||
|
||||
getToasts() {
|
||||
return this.toastSubject
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user