@cleavelandprice/ngx-lib 3.11.0 → 3.11.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/active-directory/gui/components/user-chooser/user-chooser.component.d.ts +4 -6
- package/active-directory/gui/components/user-form-field/user-form-field.component.d.ts +2 -4
- package/active-directory/services/active-directory.service.d.ts +1 -4
- package/authentication/object/services/authentication.service.d.ts +2 -4
- package/authentication/token/gui/components/login/login.component.d.ts +0 -2
- package/authentication/token/gui/components/login-form/login-form.component.d.ts +4 -4
- package/authentication/token/gui/services/authentication.service.d.ts +2 -3
- package/authentication/token/services/authentication.service.d.ts +1 -1
- package/dialog/components/choice/choice.component.d.ts +1 -2
- package/dialog/components/confirmation/confirmation.component.d.ts +1 -2
- package/dialog/components/input/input.component.d.ts +1 -2
- package/dialog/components/message/message.component.d.ts +1 -2
- package/esm2022/active-directory/gui/components/user-chooser/user-chooser.component.mjs +30 -28
- package/esm2022/active-directory/gui/components/user-form-field/user-form-field.component.mjs +28 -26
- package/esm2022/active-directory/services/active-directory.service.mjs +29 -34
- package/esm2022/authentication/object/services/authentication.service.mjs +20 -18
- package/esm2022/authentication/token/gui/components/login/login.component.mjs +13 -12
- package/esm2022/authentication/token/gui/components/login-form/login-form.component.mjs +21 -20
- package/esm2022/authentication/token/gui/services/authentication.service.mjs +9 -7
- package/esm2022/authentication/token/services/authentication.service.mjs +12 -8
- package/esm2022/dialog/components/choice/choice.component.mjs +12 -14
- package/esm2022/dialog/components/confirmation/confirmation.component.mjs +12 -14
- package/esm2022/dialog/components/input/input.component.mjs +12 -14
- package/esm2022/dialog/components/message/message.component.mjs +12 -14
- package/esm2022/lib/services/app-path-config.service.mjs +9 -12
- package/esm2022/quill/components/editor/editor.component.mjs +2 -2
- package/esm2022/quill/components/raw/raw.component.mjs +6 -9
- package/esm2022/sharepoint/components/employee-photo/employee-photo.component.mjs +10 -10
- package/esm2022/sharepoint/pipes/employee-photo-url.pipe.mjs +8 -8
- package/esm2022/sharepoint/services/sharepoint.service.mjs +41 -40
- package/esm2022/upload/components/upload/upload.component.mjs +13 -11
- package/esm2022/upload/components/upload-dialog/upload-dialog.component.mjs +16 -14
- package/esm2022/upload/services/upload.service.mjs +10 -13
- package/esm2022/url-utilities/pipes/safe-resource-url.pipe.mjs +7 -7
- package/esm2022/url-utilities/pipes/safe-url.pipe.mjs +7 -7
- package/fesm2022/cleavelandprice-ngx-lib-active-directory-gui.mjs +44 -41
- package/fesm2022/cleavelandprice-ngx-lib-active-directory-gui.mjs.map +1 -1
- package/fesm2022/cleavelandprice-ngx-lib-active-directory.mjs +28 -32
- package/fesm2022/cleavelandprice-ngx-lib-active-directory.mjs.map +1 -1
- package/fesm2022/cleavelandprice-ngx-lib-authentication-object.mjs +19 -16
- package/fesm2022/cleavelandprice-ngx-lib-authentication-object.mjs.map +1 -1
- package/fesm2022/cleavelandprice-ngx-lib-authentication-token-gui.mjs +33 -29
- package/fesm2022/cleavelandprice-ngx-lib-authentication-token-gui.mjs.map +1 -1
- package/fesm2022/cleavelandprice-ngx-lib-authentication-token.mjs +11 -7
- package/fesm2022/cleavelandprice-ngx-lib-authentication-token.mjs.map +1 -1
- package/fesm2022/cleavelandprice-ngx-lib-dialog.mjs +32 -36
- package/fesm2022/cleavelandprice-ngx-lib-dialog.mjs.map +1 -1
- package/fesm2022/cleavelandprice-ngx-lib-quill.mjs +5 -8
- package/fesm2022/cleavelandprice-ngx-lib-quill.mjs.map +1 -1
- package/fesm2022/cleavelandprice-ngx-lib-sharepoint.mjs +50 -48
- package/fesm2022/cleavelandprice-ngx-lib-sharepoint.mjs.map +1 -1
- package/fesm2022/cleavelandprice-ngx-lib-upload.mjs +30 -29
- package/fesm2022/cleavelandprice-ngx-lib-upload.mjs.map +1 -1
- package/fesm2022/cleavelandprice-ngx-lib-url-utilities.mjs +10 -10
- package/fesm2022/cleavelandprice-ngx-lib-url-utilities.mjs.map +1 -1
- package/fesm2022/cleavelandprice-ngx-lib.mjs +8 -10
- package/fesm2022/cleavelandprice-ngx-lib.mjs.map +1 -1
- package/lib/services/app-path-config.service.d.ts +2 -4
- package/package.json +7 -7
- package/quill/components/editor/editor.component.d.ts +1 -1
- package/quill/components/raw/raw.component.d.ts +0 -1
- package/sharepoint/components/employee-photo/employee-photo.component.d.ts +1 -2
- package/sharepoint/pipes/employee-photo-url.pipe.d.ts +0 -2
- package/sharepoint/services/sharepoint.service.d.ts +3 -5
- package/upload/components/upload/upload.component.d.ts +1 -2
- package/upload/components/upload-dialog/upload-dialog.component.d.ts +1 -2
- package/upload/services/upload.service.d.ts +2 -4
- package/url-utilities/pipes/safe-resource-url.pipe.d.ts +1 -2
- package/url-utilities/pipes/safe-url.pipe.d.ts +1 -2
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { ServiceConfig as ServiceConfig$1 } from '@cleavelandprice/ngx-lib';
|
|
2
2
|
import * as i0 from '@angular/core';
|
|
3
|
-
import {
|
|
3
|
+
import { inject, Injectable, Pipe, Component, Input, NgModule, Optional, SkipSelf } from '@angular/core';
|
|
4
4
|
import { of, map } from 'rxjs';
|
|
5
|
+
import { HttpClient } from '@angular/common/http';
|
|
5
6
|
import { DateTime } from 'luxon';
|
|
6
|
-
import
|
|
7
|
-
import * as i1 from '@
|
|
8
|
-
import * as i2$1 from '@angular/common';
|
|
7
|
+
import { ActiveDirectoryService } from '@cleavelandprice/ngx-lib/active-directory';
|
|
8
|
+
import * as i1 from '@angular/common';
|
|
9
9
|
import { CommonModule } from '@angular/common';
|
|
10
10
|
|
|
11
11
|
class ServiceConfig extends ServiceConfig$1 {
|
|
@@ -40,26 +40,28 @@ class SharePointService {
|
|
|
40
40
|
if (!cache) {
|
|
41
41
|
return true;
|
|
42
42
|
}
|
|
43
|
-
const lifeMinutes = this.config
|
|
43
|
+
const lifeMinutes = this.config?.caching?.lifeMinutes ?? this.defaultCacheLifeMinutes;
|
|
44
44
|
const expiration = cache.lastUpdate.plus({ minutes: lifeMinutes });
|
|
45
45
|
return DateTime.now() > expiration;
|
|
46
46
|
}
|
|
47
47
|
//#endregion
|
|
48
48
|
//#region Initialization
|
|
49
|
-
constructor(
|
|
50
|
-
|
|
51
|
-
this.
|
|
49
|
+
constructor() {
|
|
50
|
+
//#region Services
|
|
51
|
+
this.config = inject(ServiceConfig, { optional: true }) ?? new ServiceConfig();
|
|
52
|
+
this.http = inject(HttpClient);
|
|
52
53
|
this.defaultCacheLifeMinutes = 720;
|
|
53
|
-
this.config = this.config ?? new ServiceConfig();
|
|
54
54
|
this.configureCaching();
|
|
55
55
|
this.configureLogging();
|
|
56
56
|
}
|
|
57
57
|
configureCaching() {
|
|
58
58
|
// If caching config is missing entirely, give it a default
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
59
|
+
if (this.config) {
|
|
60
|
+
this.config.caching = this.config?.caching ?? {
|
|
61
|
+
enabled: false,
|
|
62
|
+
lifeMinutes: this.defaultCacheLifeMinutes
|
|
63
|
+
};
|
|
64
|
+
}
|
|
63
65
|
this.cache = {
|
|
64
66
|
photos: undefined,
|
|
65
67
|
users: undefined
|
|
@@ -67,29 +69,31 @@ class SharePointService {
|
|
|
67
69
|
}
|
|
68
70
|
configureLogging() {
|
|
69
71
|
// If logging config is missing entirely, give it a default
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
72
|
+
if (this.config) {
|
|
73
|
+
this.config.logging = this.config.logging ?? {
|
|
74
|
+
dataCached: false,
|
|
75
|
+
cachedDataReturned: false,
|
|
76
|
+
freshDataReturned: false,
|
|
77
|
+
cacheCleared: false
|
|
78
|
+
};
|
|
79
|
+
}
|
|
76
80
|
}
|
|
77
81
|
//#endregion
|
|
78
82
|
getListItems(request) {
|
|
79
|
-
const apiUrl = this.config
|
|
80
|
-
const endpoint = this.config
|
|
83
|
+
const apiUrl = this.config?.apiUrl;
|
|
84
|
+
const endpoint = this.config?.listItemsEndpoint;
|
|
81
85
|
return this.http.post(`${apiUrl}${endpoint}`, request);
|
|
82
86
|
}
|
|
83
87
|
getPhotos() {
|
|
84
88
|
const request = {
|
|
85
|
-
username: this.config
|
|
86
|
-
password: this.config
|
|
87
|
-
site: this.config
|
|
88
|
-
list: this.config
|
|
89
|
-
additionalPropertiesToRetrieve: this.config
|
|
89
|
+
username: this.config?.username,
|
|
90
|
+
password: this.config?.password,
|
|
91
|
+
site: this.config?.photos.site,
|
|
92
|
+
list: this.config?.photos.list,
|
|
93
|
+
additionalPropertiesToRetrieve: this.config?.photos.additionalPropertiesToRetrieve
|
|
90
94
|
};
|
|
91
95
|
const observable$ = this.getListItems(request);
|
|
92
|
-
if (this.config
|
|
96
|
+
if (this.config?.caching?.enabled) {
|
|
93
97
|
if (this.cacheExpired(this.cache?.photos)) {
|
|
94
98
|
// Get the data and cache it
|
|
95
99
|
observable$.subscribe(data => {
|
|
@@ -97,7 +101,7 @@ class SharePointService {
|
|
|
97
101
|
data,
|
|
98
102
|
lastUpdate: DateTime.now()
|
|
99
103
|
};
|
|
100
|
-
if (this.config
|
|
104
|
+
if (this.config?.logging?.dataCached) {
|
|
101
105
|
const lifeMinutes = this.config.caching?.lifeMinutes ?? this.defaultCacheLifeMinutes;
|
|
102
106
|
console.log(`Photos cached for ${lifeMinutes} minutes`);
|
|
103
107
|
}
|
|
@@ -112,14 +116,14 @@ class SharePointService {
|
|
|
112
116
|
}
|
|
113
117
|
}
|
|
114
118
|
// Cache is either disabled or expired, return data from API
|
|
115
|
-
if (this.config
|
|
119
|
+
if (this.config?.logging?.freshDataReturned) {
|
|
116
120
|
console.log('Returning fresh photos');
|
|
117
121
|
}
|
|
118
122
|
return observable$;
|
|
119
123
|
}
|
|
120
124
|
getUsers(request, id) {
|
|
121
|
-
const apiUrl = this.config
|
|
122
|
-
const endpoint = this.config
|
|
125
|
+
const apiUrl = this.config?.apiUrl;
|
|
126
|
+
const endpoint = this.config?.usersEndpoint;
|
|
123
127
|
const observable$ = this.http.post(`${apiUrl}${endpoint}/${id ?? ''}`, request);
|
|
124
128
|
//#region Single user
|
|
125
129
|
if (id) {
|
|
@@ -127,7 +131,7 @@ class SharePointService {
|
|
|
127
131
|
}
|
|
128
132
|
//#endregion
|
|
129
133
|
//#region Multiple users
|
|
130
|
-
if (this.config
|
|
134
|
+
if (this.config?.caching?.enabled) {
|
|
131
135
|
if (this.cacheExpired(this.cache.users)) {
|
|
132
136
|
// Get the data and cache it
|
|
133
137
|
observable$.subscribe(data => {
|
|
@@ -135,7 +139,7 @@ class SharePointService {
|
|
|
135
139
|
data: data,
|
|
136
140
|
lastUpdate: DateTime.now()
|
|
137
141
|
};
|
|
138
|
-
if (this.config
|
|
142
|
+
if (this.config?.logging?.dataCached) {
|
|
139
143
|
const lifeMinutes = this.config.caching?.lifeMinutes ?? this.defaultCacheLifeMinutes;
|
|
140
144
|
console.log(`Users cached for ${lifeMinutes} minutes`);
|
|
141
145
|
}
|
|
@@ -150,7 +154,7 @@ class SharePointService {
|
|
|
150
154
|
}
|
|
151
155
|
}
|
|
152
156
|
// Cache is either disabled or expired, return data from API
|
|
153
|
-
if (this.config
|
|
157
|
+
if (this.config?.logging?.freshDataReturned) {
|
|
154
158
|
console.log('Returning fresh users');
|
|
155
159
|
}
|
|
156
160
|
return observable$;
|
|
@@ -158,11 +162,11 @@ class SharePointService {
|
|
|
158
162
|
}
|
|
159
163
|
clearCache() {
|
|
160
164
|
this.cache = undefined;
|
|
161
|
-
if (this.config
|
|
165
|
+
if (this.config?.logging?.cacheCleared) {
|
|
162
166
|
console.log('Cache cleared');
|
|
163
167
|
}
|
|
164
168
|
}
|
|
165
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: SharePointService, deps: [
|
|
169
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: SharePointService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
166
170
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: SharePointService, providedIn: 'root' }); }
|
|
167
171
|
}
|
|
168
172
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: SharePointService, decorators: [{
|
|
@@ -170,13 +174,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImpor
|
|
|
170
174
|
args: [{
|
|
171
175
|
providedIn: 'root'
|
|
172
176
|
}]
|
|
173
|
-
}], ctorParameters: () => [
|
|
174
|
-
type: Optional
|
|
175
|
-
}] }, { type: i2.HttpClient }] });
|
|
177
|
+
}], ctorParameters: () => [] });
|
|
176
178
|
|
|
177
179
|
class EmployeePhotoUrlPipe {
|
|
178
|
-
constructor(
|
|
179
|
-
this.sharePointService =
|
|
180
|
+
constructor() {
|
|
181
|
+
this.sharePointService = inject(SharePointService);
|
|
180
182
|
}
|
|
181
183
|
transform(user, userPhotos) {
|
|
182
184
|
const observable$ = userPhotos ? of(userPhotos) : this.sharePointService.getPhotos();
|
|
@@ -198,7 +200,7 @@ class EmployeePhotoUrlPipe {
|
|
|
198
200
|
|
|
199
201
|
return photo ? photo.encodedAbsUrl : null;*/
|
|
200
202
|
}
|
|
201
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: EmployeePhotoUrlPipe, deps: [
|
|
203
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: EmployeePhotoUrlPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
202
204
|
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "17.1.2", ngImport: i0, type: EmployeePhotoUrlPipe, name: "employeePhotoUrl" }); }
|
|
203
205
|
}
|
|
204
206
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: EmployeePhotoUrlPipe, decorators: [{
|
|
@@ -206,11 +208,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImpor
|
|
|
206
208
|
args: [{
|
|
207
209
|
name: 'employeePhotoUrl'
|
|
208
210
|
}]
|
|
209
|
-
}]
|
|
211
|
+
}] });
|
|
210
212
|
|
|
211
213
|
class EmployeePhotoComponent {
|
|
212
|
-
constructor(
|
|
213
|
-
this.activeDirectoryService =
|
|
214
|
+
constructor() {
|
|
215
|
+
this.activeDirectoryService = inject(ActiveDirectoryService);
|
|
214
216
|
this.size = "2em";
|
|
215
217
|
this.notRound = false;
|
|
216
218
|
}
|
|
@@ -222,13 +224,13 @@ class EmployeePhotoComponent {
|
|
|
222
224
|
.subscribe(user => this.employee = user);
|
|
223
225
|
}
|
|
224
226
|
}
|
|
225
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: EmployeePhotoComponent, deps: [
|
|
226
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.1.2", type: EmployeePhotoComponent, selector: "employee-photo", inputs: { employee: "employee", accountName: "accountName", employeePhotos: "employeePhotos", size: "size", notRound: "notRound" }, ngImport: i0, template: "@if (employee) {\n @if ((employee | employeePhotoUrl:employeePhotos | async)) {\n <img\n [src]=\"employee | employeePhotoUrl:employeePhotos | async\"\n [style.width]=\"size\"\n [style.height]=\"size\"\n [style.border-radius]=\"notRound ? 'default' : '100%'\">\n }\n}", styles: [""], dependencies: [{ kind: "pipe", type:
|
|
227
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: EmployeePhotoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
228
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.1.2", type: EmployeePhotoComponent, selector: "employee-photo", inputs: { employee: "employee", accountName: "accountName", employeePhotos: "employeePhotos", size: "size", notRound: "notRound" }, ngImport: i0, template: "@if (employee) {\n @if ((employee | employeePhotoUrl:employeePhotos | async)) {\n <img\n [src]=\"employee | employeePhotoUrl:employeePhotos | async\"\n [style.width]=\"size\"\n [style.height]=\"size\"\n [style.border-radius]=\"notRound ? 'default' : '100%'\">\n }\n}", styles: [""], dependencies: [{ kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: EmployeePhotoUrlPipe, name: "employeePhotoUrl" }] }); }
|
|
227
229
|
}
|
|
228
230
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: EmployeePhotoComponent, decorators: [{
|
|
229
231
|
type: Component,
|
|
230
232
|
args: [{ selector: 'employee-photo', template: "@if (employee) {\n @if ((employee | employeePhotoUrl:employeePhotos | async)) {\n <img\n [src]=\"employee | employeePhotoUrl:employeePhotos | async\"\n [style.width]=\"size\"\n [style.height]=\"size\"\n [style.border-radius]=\"notRound ? 'default' : '100%'\">\n }\n}" }]
|
|
231
|
-
}],
|
|
233
|
+
}], propDecorators: { employee: [{
|
|
232
234
|
type: Input
|
|
233
235
|
}], accountName: [{
|
|
234
236
|
type: Input
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cleavelandprice-ngx-lib-sharepoint.mjs","sources":["../../../../projects/cleavelandprice/ngx-lib/sharepoint/src/model/service-config.ts","../../../../projects/cleavelandprice/ngx-lib/sharepoint/src/services/sharepoint.service.ts","../../../../projects/cleavelandprice/ngx-lib/sharepoint/src/pipes/employee-photo-url.pipe.ts","../../../../projects/cleavelandprice/ngx-lib/sharepoint/src/components/employee-photo/employee-photo.component.ts","../../../../projects/cleavelandprice/ngx-lib/sharepoint/src/components/employee-photo/employee-photo.component.html","../../../../projects/cleavelandprice/ngx-lib/sharepoint/src/sharepoint.module.ts","../../../../projects/cleavelandprice/ngx-lib/sharepoint/src/cleavelandprice-ngx-lib-sharepoint.ts"],"sourcesContent":["import { ServiceConfig as NgxLibServiceConfig } from '@cleavelandprice/ngx-lib';\r\n\r\nexport class ServiceConfig extends NgxLibServiceConfig {\r\n usersEndpoint = '/sharepoint/users';\r\n listItemsEndpoint = '/sharepoint/listitems';\r\n username: string | undefined;\r\n password: string | undefined;\r\n photos = {\r\n site: 'https://sharepoint.cleavelandprice.com/digitaldisplay',\r\n list: 'Employee Thumbnail Photos',\r\n additionalPropertiesToRetrieve: [\r\n 'EncodedAbsUrl'\r\n ]\r\n };\r\n caching = {\r\n enabled: true,\r\n lifeMinutes: 720\r\n };\r\n logging = {\r\n dataCached: true,\r\n cachedDataReturned: true,\r\n freshDataReturned: true,\r\n cacheCleared: true\r\n };\r\n\r\n // See the comment in the library's main service-config.ts file for an explanation\r\n constructor(useSsl_or_customApiUrl: boolean | string = false) {\r\n super(useSsl_or_customApiUrl);\r\n }\r\n}","import { Injectable, Optional } from '@angular/core';\r\nimport { HttpClient } from '@angular/common/http';\r\nimport { Observable, of } from 'rxjs';\r\nimport { DateTime } from 'luxon';\r\n\r\nimport { CacheObject } from '../model/cache-object';\r\nimport { ListItem } from '../model/list-item';\r\nimport { ListItemsRequest } from '../model/list-items-request';\r\nimport { PhotoItem } from '../model/photo-item';\r\nimport { ServiceConfig } from '../model/service-config';\r\nimport { UserRequest } from '../model/user-request';\r\nimport { User } from '../model/user';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class SharePointService {\r\n private cache: {\r\n users: CacheObject<User> | undefined,\r\n photos: CacheObject<PhotoItem> | undefined\r\n } | undefined;\r\n\r\n private defaultCacheLifeMinutes = 720;\r\n\r\n //#region Utilities\r\n private cacheExpired<T>(cache: CacheObject<T>): boolean {\r\n if (!cache) {\r\n return true;\r\n }\r\n\r\n const lifeMinutes = this.config.caching?.lifeMinutes ?? this.defaultCacheLifeMinutes;\r\n const expiration = cache.lastUpdate.plus({ minutes: lifeMinutes});\r\n\r\n return DateTime.now() > expiration;\r\n }\r\n //#endregion\r\n\r\n //#region Initialization\r\n constructor(@Optional() private config: ServiceConfig,\r\n private http: HttpClient) {\r\n\r\n this.config = this.config ?? new ServiceConfig();\r\n \r\n this.configureCaching();\r\n this.configureLogging();\r\n }\r\n\r\n private configureCaching(): void {\r\n // If caching config is missing entirely, give it a default\r\n this.config.caching = this.config.caching ?? {\r\n enabled: false,\r\n lifeMinutes: this.defaultCacheLifeMinutes\r\n };\r\n\r\n this.cache = {\r\n photos: undefined,\r\n users: undefined\r\n };\r\n }\r\n\r\n private configureLogging(): void {\r\n // If logging config is missing entirely, give it a default\r\n this.config.logging = this.config.logging ?? {\r\n dataCached: false,\r\n cachedDataReturned: false,\r\n freshDataReturned: false,\r\n cacheCleared: false\r\n }\r\n }\r\n //#endregion\r\n\r\n getListItems(request: ListItemsRequest): Observable<ListItem[]> {\r\n const apiUrl = this.config.apiUrl;\r\n const endpoint = this.config.listItemsEndpoint;\r\n\r\n return this.http.post<ListItem[]>(`${apiUrl}${endpoint}`, request);\r\n }\r\n\r\n getPhotos(): Observable<PhotoItem[]> {\r\n const request: ListItemsRequest = {\r\n username: this.config.username,\r\n password: this.config.password,\r\n site: this.config.photos.site,\r\n list: this.config.photos.list,\r\n additionalPropertiesToRetrieve: this.config.photos.additionalPropertiesToRetrieve\r\n };\r\n\r\n const observable$ = this.getListItems(request) as Observable<PhotoItem[]>;\r\n\r\n if (this.config.caching?.enabled) {\r\n if (this.cacheExpired<PhotoItem>(this.cache?.photos!)) {\r\n // Get the data and cache it\r\n observable$.subscribe(data => {\r\n this.cache!.photos = {\r\n data,\r\n lastUpdate: DateTime.now()\r\n };\r\n\r\n if (this.config.logging?.dataCached) {\r\n const lifeMinutes = this.config.caching?.lifeMinutes ?? this.defaultCacheLifeMinutes;\r\n console.log(`Photos cached for ${lifeMinutes} minutes`);\r\n }\r\n });\r\n } else {\r\n // Cache exists and hasn't expired yet\r\n if (this.config.logging?.cachedDataReturned) {\r\n console.log('Returning cached photos');\r\n }\r\n\r\n return of(this.cache!.photos!.data);\r\n }\r\n }\r\n\r\n // Cache is either disabled or expired, return data from API\r\n if (this.config.logging?.freshDataReturned) {\r\n console.log('Returning fresh photos');\r\n }\r\n\r\n return observable$;\r\n }\r\n\r\n getUsers(request: UserRequest, id?: number): Observable<User | User[]> {\r\n const apiUrl = this.config.apiUrl;\r\n const endpoint = this.config.usersEndpoint;\r\n \r\n const observable$ = this.http.post<User | User[]>(`${apiUrl}${endpoint}/${id ?? ''}`, request);\r\n\r\n //#region Single user\r\n if (id) {\r\n return observable$;\r\n }\r\n //#endregion\r\n\r\n //#region Multiple users\r\n if (this.config.caching?.enabled) {\r\n if (this.cacheExpired<User>(this.cache!.users!)) {\r\n // Get the data and cache it\r\n observable$.subscribe(data => {\r\n this.cache!.users = {\r\n data: data as User[],\r\n lastUpdate: DateTime.now()\r\n };\r\n\r\n if (this.config.logging?.dataCached) {\r\n const lifeMinutes = this.config.caching?.lifeMinutes ?? this.defaultCacheLifeMinutes;\r\n console.log(`Users cached for ${lifeMinutes} minutes`);\r\n }\r\n });\r\n } else {\r\n // Cache exists and hasn't expired yet\r\n if (this.config.logging?.cachedDataReturned) {\r\n console.log('Returning cached users');\r\n }\r\n\r\n return of(this.cache!.users!.data);\r\n }\r\n }\r\n\r\n // Cache is either disabled or expired, return data from API\r\n if (this.config.logging?.freshDataReturned) {\r\n console.log('Returning fresh users');\r\n }\r\n\r\n return observable$;\r\n //#endregion\r\n }\r\n\r\n clearCache(): void {\r\n this.cache = undefined;\r\n\r\n if (this.config.logging?.cacheCleared) {\r\n console.log('Cache cleared');\r\n }\r\n }\r\n}","import { Pipe, PipeTransform } from '@angular/core';\nimport { of, map } from 'rxjs';\nimport { CleavelandPriceUser } from '@cleavelandprice/ngx-lib/active-directory';\nimport { PhotoItem } from '../model/photo-item';\nimport { SharePointService } from '../services/sharepoint.service';\n\n@Pipe({\n name: 'employeePhotoUrl'\n})\nexport class EmployeePhotoUrlPipe implements PipeTransform {\n constructor (private sharePointService: SharePointService) { }\n\n transform(user: CleavelandPriceUser, userPhotos?: PhotoItem[]): any {\n const observable$ = userPhotos ? of(userPhotos) : this.sharePointService.getPhotos();\n\n return observable$\n .pipe(\n map(photos =>\n photos.find(pic =>\n // Try to match by employeeNumber, accountName, or title\n (pic.employeeNumber && user.employeeNumber && +pic.employeeNumber === +user.employeeNumber) ||\n (pic.accountName && pic.accountName.toLowerCase() === user.sAMAccountName.toLowerCase()) ||\n (pic.title && pic.title.toLowerCase() === user.displayName.toLowerCase())\n )?.encodedAbsUrl\n )\n );\n\n /*const photo = photos\n .find(pic =>\n (pic.employeeNumber && user.employeeNumber && +pic.employeeNumber === +user.employeeNumber) ||\n (pic.accountName && pic.accountName.toLowerCase() === user.sAMAccountName.toLowerCase()) ||\n (pic.title && pic.title.toLowerCase() === user.displayName.toLowerCase()));\n\n if (!photo) {\n console.log(`No photo match for ${user.displayName}`);\n }\n\n return photo ? photo.encodedAbsUrl : null;*/\n }\n}","import { Component, Input, OnInit } from '@angular/core';\nimport { ActiveDirectoryService, CleavelandPriceUser } from '@cleavelandprice/ngx-lib/active-directory';\nimport { PhotoItem } from '../../model/photo-item';\n\n@Component({\n selector: 'employee-photo',\n templateUrl: './employee-photo.component.html',\n styleUrls: ['./employee-photo.component.css']\n})\nexport class EmployeePhotoComponent implements OnInit {\n @Input() employee: CleavelandPriceUser | undefined;\n // Or...\n @Input() accountName: string | undefined;\n\n @Input() employeePhotos?: PhotoItem[];\n @Input() size = \"2em\";\n @Input() notRound = false;\n\n constructor(private activeDirectoryService: ActiveDirectoryService) { }\n\n ngOnInit(): void {\n if (this.accountName && !this.employee) {\n // Developer passed in an account name instead of a user object\n // We need to do the work of getting the user object ourselves\n this.activeDirectoryService.getUser(this.accountName)\n .subscribe(user => this.employee = user);\n }\n }\n}","@if (employee) {\n @if ((employee | employeePhotoUrl:employeePhotos | async)) {\n <img\n [src]=\"employee | employeePhotoUrl:employeePhotos | async\"\n [style.width]=\"size\"\n [style.height]=\"size\"\n [style.border-radius]=\"notRound ? 'default' : '100%'\">\n }\n}","import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\n\r\nimport { ServiceConfig } from './model/service-config';\r\nimport { SharePointService } from './services/sharepoint.service';\r\nimport { EmployeePhotoUrlPipe } from './pipes/employee-photo-url.pipe';\r\nimport { EmployeePhotoComponent } from './components/employee-photo/employee-photo.component';\r\n\r\n@NgModule({\r\n declarations: [\r\n EmployeePhotoUrlPipe,\r\n EmployeePhotoComponent\r\n ],\r\n imports: [\r\n CommonModule\r\n ],\r\n exports: [\r\n EmployeePhotoUrlPipe,\r\n EmployeePhotoComponent\r\n ]\r\n})\r\nexport class SharePointModule {\r\n static forRoot(config: ServiceConfig): ModuleWithProviders<SharePointModule> {\r\n return {\r\n ngModule: SharePointModule,\r\n providers: [\r\n SharePointService,\r\n { provide: ServiceConfig, useValue: config }\r\n ]\r\n };\r\n }\r\n\r\n constructor(@Optional() @SkipSelf() parentModule: SharePointModule) {\r\n if (parentModule) {\r\n throw new Error(\r\n 'SharePointModule is already loaded. Import it in the AppModule only');\r\n }\r\n }\r\n}","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":["NgxLibServiceConfig","i1.ServiceConfig","i1.SharePointService","i2","i3.EmployeePhotoUrlPipe"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cleavelandprice-ngx-lib-sharepoint.mjs","sources":["../../../../projects/cleavelandprice/ngx-lib/sharepoint/src/model/service-config.ts","../../../../projects/cleavelandprice/ngx-lib/sharepoint/src/services/sharepoint.service.ts","../../../../projects/cleavelandprice/ngx-lib/sharepoint/src/pipes/employee-photo-url.pipe.ts","../../../../projects/cleavelandprice/ngx-lib/sharepoint/src/components/employee-photo/employee-photo.component.ts","../../../../projects/cleavelandprice/ngx-lib/sharepoint/src/components/employee-photo/employee-photo.component.html","../../../../projects/cleavelandprice/ngx-lib/sharepoint/src/sharepoint.module.ts","../../../../projects/cleavelandprice/ngx-lib/sharepoint/src/cleavelandprice-ngx-lib-sharepoint.ts"],"sourcesContent":["import { ServiceConfig as NgxLibServiceConfig } from '@cleavelandprice/ngx-lib';\r\n\r\nexport class ServiceConfig extends NgxLibServiceConfig {\r\n usersEndpoint = '/sharepoint/users';\r\n listItemsEndpoint = '/sharepoint/listitems';\r\n username: string | undefined;\r\n password: string | undefined;\r\n photos = {\r\n site: 'https://sharepoint.cleavelandprice.com/digitaldisplay',\r\n list: 'Employee Thumbnail Photos',\r\n additionalPropertiesToRetrieve: [\r\n 'EncodedAbsUrl'\r\n ]\r\n };\r\n caching = {\r\n enabled: true,\r\n lifeMinutes: 720\r\n };\r\n logging = {\r\n dataCached: true,\r\n cachedDataReturned: true,\r\n freshDataReturned: true,\r\n cacheCleared: true\r\n };\r\n\r\n // See the comment in the library's main service-config.ts file for an explanation\r\n constructor(useSsl_or_customApiUrl: boolean | string = false) {\r\n super(useSsl_or_customApiUrl);\r\n }\r\n}","import { HttpClient } from '@angular/common/http';\r\nimport { inject, Injectable } from '@angular/core';\r\nimport { DateTime } from 'luxon';\r\nimport { Observable, of } from 'rxjs';\r\n\r\nimport { CacheObject } from '../model/cache-object';\r\nimport { ListItem } from '../model/list-item';\r\nimport { ListItemsRequest } from '../model/list-items-request';\r\nimport { PhotoItem } from '../model/photo-item';\r\nimport { ServiceConfig } from '../model/service-config';\r\nimport { User } from '../model/user';\r\nimport { UserRequest } from '../model/user-request';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class SharePointService {\r\n //#region Services\r\n private config = inject(ServiceConfig, { optional: true }) ?? new ServiceConfig();\r\n private http = inject(HttpClient);\r\n //#endregion\r\n\r\n private cache: {\r\n users: CacheObject<User> | undefined,\r\n photos: CacheObject<PhotoItem> | undefined\r\n } | undefined;\r\n\r\n private defaultCacheLifeMinutes = 720;\r\n\r\n //#region Utilities\r\n private cacheExpired<T>(cache: CacheObject<T>): boolean {\r\n if (!cache) {\r\n return true;\r\n }\r\n\r\n const lifeMinutes = this.config?.caching?.lifeMinutes ?? this.defaultCacheLifeMinutes;\r\n const expiration = cache.lastUpdate.plus({ minutes: lifeMinutes});\r\n\r\n return DateTime.now() > expiration;\r\n }\r\n //#endregion\r\n\r\n //#region Initialization\r\n constructor() {\r\n this.configureCaching();\r\n this.configureLogging();\r\n }\r\n\r\n private configureCaching(): void {\r\n // If caching config is missing entirely, give it a default\r\n if (this.config) {\r\n this.config.caching = this.config?.caching ?? {\r\n enabled: false,\r\n lifeMinutes: this.defaultCacheLifeMinutes\r\n };\r\n }\r\n\r\n this.cache = {\r\n photos: undefined,\r\n users: undefined\r\n };\r\n }\r\n\r\n private configureLogging(): void {\r\n // If logging config is missing entirely, give it a default\r\n if (this.config) {\r\n this.config.logging = this.config.logging ?? {\r\n dataCached: false,\r\n cachedDataReturned: false,\r\n freshDataReturned: false,\r\n cacheCleared: false\r\n }\r\n }\r\n }\r\n //#endregion\r\n\r\n getListItems(request: ListItemsRequest): Observable<ListItem[]> {\r\n const apiUrl = this.config?.apiUrl;\r\n const endpoint = this.config?.listItemsEndpoint;\r\n\r\n return this.http.post<ListItem[]>(`${apiUrl}${endpoint}`, request);\r\n }\r\n\r\n getPhotos(): Observable<PhotoItem[]> {\r\n const request: ListItemsRequest = {\r\n username: this.config?.username,\r\n password: this.config?.password,\r\n site: this.config?.photos.site,\r\n list: this.config?.photos.list,\r\n additionalPropertiesToRetrieve: this.config?.photos.additionalPropertiesToRetrieve\r\n };\r\n\r\n const observable$ = this.getListItems(request) as Observable<PhotoItem[]>;\r\n\r\n if (this.config?.caching?.enabled) {\r\n if (this.cacheExpired<PhotoItem>(this.cache?.photos!)) {\r\n // Get the data and cache it\r\n observable$.subscribe(data => {\r\n this.cache!.photos = {\r\n data,\r\n lastUpdate: DateTime.now()\r\n };\r\n\r\n if (this.config?.logging?.dataCached) {\r\n const lifeMinutes = this.config.caching?.lifeMinutes ?? this.defaultCacheLifeMinutes;\r\n console.log(`Photos cached for ${lifeMinutes} minutes`);\r\n }\r\n });\r\n } else {\r\n // Cache exists and hasn't expired yet\r\n if (this.config.logging?.cachedDataReturned) {\r\n console.log('Returning cached photos');\r\n }\r\n\r\n return of(this.cache!.photos!.data);\r\n }\r\n }\r\n\r\n // Cache is either disabled or expired, return data from API\r\n if (this.config?.logging?.freshDataReturned) {\r\n console.log('Returning fresh photos');\r\n }\r\n\r\n return observable$;\r\n }\r\n\r\n getUsers(request: UserRequest, id?: number): Observable<User | User[]> {\r\n const apiUrl = this.config?.apiUrl;\r\n const endpoint = this.config?.usersEndpoint;\r\n \r\n const observable$ = this.http.post<User | User[]>(`${apiUrl}${endpoint}/${id ?? ''}`, request);\r\n\r\n //#region Single user\r\n if (id) {\r\n return observable$;\r\n }\r\n //#endregion\r\n\r\n //#region Multiple users\r\n if (this.config?.caching?.enabled) {\r\n if (this.cacheExpired<User>(this.cache!.users!)) {\r\n // Get the data and cache it\r\n observable$.subscribe(data => {\r\n this.cache!.users = {\r\n data: data as User[],\r\n lastUpdate: DateTime.now()\r\n };\r\n\r\n if (this.config?.logging?.dataCached) {\r\n const lifeMinutes = this.config.caching?.lifeMinutes ?? this.defaultCacheLifeMinutes;\r\n console.log(`Users cached for ${lifeMinutes} minutes`);\r\n }\r\n });\r\n } else {\r\n // Cache exists and hasn't expired yet\r\n if (this.config.logging?.cachedDataReturned) {\r\n console.log('Returning cached users');\r\n }\r\n\r\n return of(this.cache!.users!.data);\r\n }\r\n }\r\n\r\n // Cache is either disabled or expired, return data from API\r\n if (this.config?.logging?.freshDataReturned) {\r\n console.log('Returning fresh users');\r\n }\r\n\r\n return observable$;\r\n //#endregion\r\n }\r\n\r\n clearCache(): void {\r\n this.cache = undefined;\r\n\r\n if (this.config?.logging?.cacheCleared) {\r\n console.log('Cache cleared');\r\n }\r\n }\r\n}","import { inject, Pipe, PipeTransform } from '@angular/core';\nimport { CleavelandPriceUser } from '@cleavelandprice/ngx-lib/active-directory';\nimport { map, of } from 'rxjs';\nimport { PhotoItem } from '../model/photo-item';\nimport { SharePointService } from '../services/sharepoint.service';\n\n@Pipe({\n name: 'employeePhotoUrl'\n})\nexport class EmployeePhotoUrlPipe implements PipeTransform {\n private sharePointService = inject(SharePointService);\n\n transform(user: CleavelandPriceUser, userPhotos?: PhotoItem[]): any {\n const observable$ = userPhotos ? of(userPhotos) : this.sharePointService.getPhotos();\n\n return observable$\n .pipe(\n map(photos =>\n photos.find(pic =>\n // Try to match by employeeNumber, accountName, or title\n (pic.employeeNumber && user.employeeNumber && +pic.employeeNumber === +user.employeeNumber) ||\n (pic.accountName && pic.accountName.toLowerCase() === user.sAMAccountName.toLowerCase()) ||\n (pic.title && pic.title.toLowerCase() === user.displayName.toLowerCase())\n )?.encodedAbsUrl\n )\n );\n\n /*const photo = photos\n .find(pic =>\n (pic.employeeNumber && user.employeeNumber && +pic.employeeNumber === +user.employeeNumber) ||\n (pic.accountName && pic.accountName.toLowerCase() === user.sAMAccountName.toLowerCase()) ||\n (pic.title && pic.title.toLowerCase() === user.displayName.toLowerCase()));\n\n if (!photo) {\n console.log(`No photo match for ${user.displayName}`);\n }\n\n return photo ? photo.encodedAbsUrl : null;*/\n }\n}","import { Component, inject, Input, OnInit } from '@angular/core';\nimport { ActiveDirectoryService, CleavelandPriceUser } from '@cleavelandprice/ngx-lib/active-directory';\nimport { PhotoItem } from '../../model/photo-item';\n\n@Component({\n selector: 'employee-photo',\n templateUrl: './employee-photo.component.html',\n styleUrls: ['./employee-photo.component.css']\n})\nexport class EmployeePhotoComponent implements OnInit {\n private activeDirectoryService = inject(ActiveDirectoryService);\n\n @Input() employee: CleavelandPriceUser | undefined;\n // Or...\n @Input() accountName: string | undefined;\n\n @Input() employeePhotos?: PhotoItem[];\n @Input() size = \"2em\";\n @Input() notRound = false;\n\n ngOnInit(): void {\n if (this.accountName && !this.employee) {\n // Developer passed in an account name instead of a user object\n // We need to do the work of getting the user object ourselves\n this.activeDirectoryService.getUser(this.accountName)\n .subscribe(user => this.employee = user);\n }\n }\n}","@if (employee) {\n @if ((employee | employeePhotoUrl:employeePhotos | async)) {\n <img\n [src]=\"employee | employeePhotoUrl:employeePhotos | async\"\n [style.width]=\"size\"\n [style.height]=\"size\"\n [style.border-radius]=\"notRound ? 'default' : '100%'\">\n }\n}","import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\n\r\nimport { ServiceConfig } from './model/service-config';\r\nimport { SharePointService } from './services/sharepoint.service';\r\nimport { EmployeePhotoUrlPipe } from './pipes/employee-photo-url.pipe';\r\nimport { EmployeePhotoComponent } from './components/employee-photo/employee-photo.component';\r\n\r\n@NgModule({\r\n declarations: [\r\n EmployeePhotoUrlPipe,\r\n EmployeePhotoComponent\r\n ],\r\n imports: [\r\n CommonModule\r\n ],\r\n exports: [\r\n EmployeePhotoUrlPipe,\r\n EmployeePhotoComponent\r\n ]\r\n})\r\nexport class SharePointModule {\r\n static forRoot(config: ServiceConfig): ModuleWithProviders<SharePointModule> {\r\n return {\r\n ngModule: SharePointModule,\r\n providers: [\r\n SharePointService,\r\n { provide: ServiceConfig, useValue: config }\r\n ]\r\n };\r\n }\r\n\r\n constructor(@Optional() @SkipSelf() parentModule: SharePointModule) {\r\n if (parentModule) {\r\n throw new Error(\r\n 'SharePointModule is already loaded. Import it in the AppModule only');\r\n }\r\n }\r\n}","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":["NgxLibServiceConfig","i2.EmployeePhotoUrlPipe"],"mappings":"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"}
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
import { ServiceConfig as ServiceConfig$1 } from '@cleavelandprice/ngx-lib';
|
|
2
2
|
import * as i0 from '@angular/core';
|
|
3
|
-
import {
|
|
3
|
+
import { inject, Injectable, Component, ViewChild, EventEmitter, Output, NgModule, Optional, SkipSelf } from '@angular/core';
|
|
4
|
+
import * as i2 from '@angular/material/dialog';
|
|
5
|
+
import { MatDialogRef, MatDialog, MatDialogModule } from '@angular/material/dialog';
|
|
6
|
+
import { HttpClient, HttpHeaders, HttpRequest, HttpEventType, HttpResponse } from '@angular/common/http';
|
|
4
7
|
import { Subject, forkJoin } from 'rxjs';
|
|
5
|
-
import * as i1
|
|
6
|
-
import { MatDialogModule } from '@angular/material/dialog';
|
|
7
|
-
import * as i1 from '@angular/common/http';
|
|
8
|
-
import { HttpHeaders, HttpRequest, HttpEventType, HttpResponse } from '@angular/common/http';
|
|
9
|
-
import * as i3 from '@angular/material/button';
|
|
8
|
+
import * as i1 from '@angular/material/button';
|
|
10
9
|
import { MatButtonModule } from '@angular/material/button';
|
|
11
|
-
import * as
|
|
10
|
+
import * as i3 from '@angular/material/list';
|
|
12
11
|
import { MatListModule } from '@angular/material/list';
|
|
13
|
-
import * as
|
|
12
|
+
import * as i4 from '@angular/material/progress-bar';
|
|
14
13
|
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
|
15
|
-
import * as
|
|
14
|
+
import * as i5 from '@angular/common';
|
|
16
15
|
import { CommonModule } from '@angular/common';
|
|
17
16
|
|
|
18
17
|
class ServiceConfig extends ServiceConfig$1 {
|
|
@@ -32,11 +31,12 @@ class ServiceConfig extends ServiceConfig$1 {
|
|
|
32
31
|
|
|
33
32
|
// https://malcoded.com/posts/angular-file-upload-component-with-express
|
|
34
33
|
class UploadService {
|
|
35
|
-
constructor(
|
|
36
|
-
|
|
37
|
-
this.
|
|
38
|
-
this.config =
|
|
34
|
+
constructor() {
|
|
35
|
+
//#region Services
|
|
36
|
+
this.http = inject(HttpClient);
|
|
37
|
+
this.config = inject(ServiceConfig, { optional: true }) ?? new ServiceConfig();
|
|
39
38
|
}
|
|
39
|
+
//#endregion
|
|
40
40
|
upload(files) {
|
|
41
41
|
// this will be the our resulting map
|
|
42
42
|
const status = {};
|
|
@@ -102,7 +102,7 @@ class UploadService {
|
|
|
102
102
|
getUploadInfo(request) {
|
|
103
103
|
return this.http.post(`${this.config.apiUrl}${this.config.databaseEndpoint}/info`, request);
|
|
104
104
|
}
|
|
105
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: UploadService, deps: [
|
|
105
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: UploadService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
106
106
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: UploadService, providedIn: 'root' }); }
|
|
107
107
|
}
|
|
108
108
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: UploadService, decorators: [{
|
|
@@ -110,14 +110,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImpor
|
|
|
110
110
|
args: [{
|
|
111
111
|
providedIn: 'root'
|
|
112
112
|
}]
|
|
113
|
-
}]
|
|
114
|
-
type: Optional
|
|
115
|
-
}] }] });
|
|
113
|
+
}] });
|
|
116
114
|
|
|
117
115
|
class UploadDialogComponent {
|
|
118
|
-
constructor(
|
|
119
|
-
|
|
120
|
-
this.
|
|
116
|
+
constructor() {
|
|
117
|
+
//#region Services
|
|
118
|
+
this.dialogRef = inject((MatDialogRef));
|
|
119
|
+
this.uploadService = inject(UploadService);
|
|
121
120
|
this.files = new Set();
|
|
122
121
|
this.canBeClosed = true;
|
|
123
122
|
this.showCancelButton = true;
|
|
@@ -180,21 +179,23 @@ class UploadDialogComponent {
|
|
|
180
179
|
this.uploading = false;
|
|
181
180
|
});
|
|
182
181
|
}
|
|
183
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: UploadDialogComponent, deps: [
|
|
184
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.1.2", type: UploadDialogComponent, selector: "ng-component", viewQueries: [{ propertyName: "file", first: true, predicate: ["file"], descendants: true, static: true }], ngImport: i0, template: "<input type=\"file\" #file style=\"display: none\" (change)=\"onFilesAdded()\" multiple />\n\n<div mat-dialog-title id=\"title\">\n <div>{{ uploadService.config.uploadDialogTitle }}</div>\n <button [disabled]=\"uploading || uploadSuccessful\" mat-raised-button color=\"primary\" class=\"add-files-btn\" (click)=\"addFiles()\">\n {{ uploadService.config.uploadDialogAddFilesButtonText }}\n </button>\n</div>\n\n@if (existingFileConflict) {\n <div id=\"conflict\">\n {{ existingFileConflict }} already exists on the server and cannot be overwritten\n </div>\n}\n\n<mat-dialog-content>\n <mat-list>\n @for (file of files; track file) {\n <mat-list-item>\n <h4 mat-line>{{file.name}}</h4>\n @if (progress) {\n <mat-progress-bar mode=\"determinate\" [value]=\"progress[file.name].progress | async\"></mat-progress-bar>\n }\n </mat-list-item>\n }\n </mat-list>\n</mat-dialog-content>\n\n<mat-dialog-actions id=\"actions\">\n @if (showCancelButton) {\n <button mat-button mat-dialog-close>{{ uploadService.config.uploadDialogCancelButtonText }}</button>\n }\n @if (files.size > 0) {\n <button mat-raised-button color=\"primary\" [disabled]=\"!canBeClosed\" (click)=\"closeDialog()\">{{ primaryButtonText }}</button>\n }\n</mat-dialog-actions>\n", styles: ["#title{display:flex;justify-content:space-between}#actions{display:flex;justify-content:flex-end}#conflict{font-size:.8em;color:red;margin-top:.5em}\n"], dependencies: [{ kind: "component", type:
|
|
182
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: UploadDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
183
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.1.2", type: UploadDialogComponent, selector: "ng-component", viewQueries: [{ propertyName: "file", first: true, predicate: ["file"], descendants: true, static: true }], ngImport: i0, template: "<input type=\"file\" #file style=\"display: none\" (change)=\"onFilesAdded()\" multiple />\n\n<div mat-dialog-title id=\"title\">\n <div>{{ uploadService.config.uploadDialogTitle }}</div>\n <button [disabled]=\"uploading || uploadSuccessful\" mat-raised-button color=\"primary\" class=\"add-files-btn\" (click)=\"addFiles()\">\n {{ uploadService.config.uploadDialogAddFilesButtonText }}\n </button>\n</div>\n\n@if (existingFileConflict) {\n <div id=\"conflict\">\n {{ existingFileConflict }} already exists on the server and cannot be overwritten\n </div>\n}\n\n<mat-dialog-content>\n <mat-list>\n @for (file of files; track file) {\n <mat-list-item>\n <h4 mat-line>{{file.name}}</h4>\n @if (progress) {\n <mat-progress-bar mode=\"determinate\" [value]=\"progress[file.name].progress | async\"></mat-progress-bar>\n }\n </mat-list-item>\n }\n </mat-list>\n</mat-dialog-content>\n\n<mat-dialog-actions id=\"actions\">\n @if (showCancelButton) {\n <button mat-button mat-dialog-close>{{ uploadService.config.uploadDialogCancelButtonText }}</button>\n }\n @if (files.size > 0) {\n <button mat-raised-button color=\"primary\" [disabled]=\"!canBeClosed\" (click)=\"closeDialog()\">{{ primaryButtonText }}</button>\n }\n</mat-dialog-actions>\n", styles: ["#title{display:flex;justify-content:space-between}#actions{display:flex;justify-content:flex-end}#conflict{font-size:.8em;color:red;margin-top:.5em}\n"], dependencies: [{ kind: "component", type: i1.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "directive", type: i2.MatDialogClose, selector: "[mat-dialog-close], [matDialogClose]", inputs: ["aria-label", "type", "mat-dialog-close", "matDialogClose"], exportAs: ["matDialogClose"] }, { kind: "directive", type: i2.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i2.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i2.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "component", type: i3.MatList, selector: "mat-list", exportAs: ["matList"] }, { kind: "component", type: i3.MatListItem, selector: "mat-list-item, a[mat-list-item], button[mat-list-item]", inputs: ["activated"], exportAs: ["matListItem"] }, { kind: "component", type: i4.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }] }); }
|
|
185
184
|
}
|
|
186
185
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: UploadDialogComponent, decorators: [{
|
|
187
186
|
type: Component,
|
|
188
187
|
args: [{ template: "<input type=\"file\" #file style=\"display: none\" (change)=\"onFilesAdded()\" multiple />\n\n<div mat-dialog-title id=\"title\">\n <div>{{ uploadService.config.uploadDialogTitle }}</div>\n <button [disabled]=\"uploading || uploadSuccessful\" mat-raised-button color=\"primary\" class=\"add-files-btn\" (click)=\"addFiles()\">\n {{ uploadService.config.uploadDialogAddFilesButtonText }}\n </button>\n</div>\n\n@if (existingFileConflict) {\n <div id=\"conflict\">\n {{ existingFileConflict }} already exists on the server and cannot be overwritten\n </div>\n}\n\n<mat-dialog-content>\n <mat-list>\n @for (file of files; track file) {\n <mat-list-item>\n <h4 mat-line>{{file.name}}</h4>\n @if (progress) {\n <mat-progress-bar mode=\"determinate\" [value]=\"progress[file.name].progress | async\"></mat-progress-bar>\n }\n </mat-list-item>\n }\n </mat-list>\n</mat-dialog-content>\n\n<mat-dialog-actions id=\"actions\">\n @if (showCancelButton) {\n <button mat-button mat-dialog-close>{{ uploadService.config.uploadDialogCancelButtonText }}</button>\n }\n @if (files.size > 0) {\n <button mat-raised-button color=\"primary\" [disabled]=\"!canBeClosed\" (click)=\"closeDialog()\">{{ primaryButtonText }}</button>\n }\n</mat-dialog-actions>\n", styles: ["#title{display:flex;justify-content:space-between}#actions{display:flex;justify-content:flex-end}#conflict{font-size:.8em;color:red;margin-top:.5em}\n"] }]
|
|
189
|
-
}],
|
|
188
|
+
}], propDecorators: { file: [{
|
|
190
189
|
type: ViewChild,
|
|
191
190
|
args: ['file', { static: true }]
|
|
192
191
|
}] } });
|
|
193
192
|
|
|
194
193
|
class UploadComponent {
|
|
195
|
-
constructor(
|
|
196
|
-
|
|
197
|
-
this.
|
|
194
|
+
constructor() {
|
|
195
|
+
//#region Services
|
|
196
|
+
this.dialog = inject(MatDialog);
|
|
197
|
+
this.uploadService = inject(UploadService);
|
|
198
|
+
//#endregion
|
|
198
199
|
this.dialogClosed = new EventEmitter();
|
|
199
200
|
}
|
|
200
201
|
ngOnInit() {
|
|
@@ -206,8 +207,8 @@ class UploadComponent {
|
|
|
206
207
|
this.dialog.open(UploadDialogComponent, { width: '50%' })
|
|
207
208
|
.afterClosed().subscribe(() => this.dialogClosed.emit());
|
|
208
209
|
}
|
|
209
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: UploadComponent, deps: [
|
|
210
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.1.2", type: UploadComponent, selector: "cp-upload", outputs: { dialogClosed: "dialogClosed" }, ngImport: i0, template: '<button mat-raised-button (click)="openUploadDialog()">{{ uploadButtonText }}</button>', isInline: true, dependencies: [{ kind: "component", type:
|
|
210
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: UploadComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
211
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.1.2", type: UploadComponent, selector: "cp-upload", outputs: { dialogClosed: "dialogClosed" }, ngImport: i0, template: '<button mat-raised-button (click)="openUploadDialog()">{{ uploadButtonText }}</button>', isInline: true, dependencies: [{ kind: "component", type: i1.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }] }); }
|
|
211
212
|
}
|
|
212
213
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: UploadComponent, decorators: [{
|
|
213
214
|
type: Component,
|
|
@@ -215,7 +216,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImpor
|
|
|
215
216
|
selector: 'cp-upload',
|
|
216
217
|
template: '<button mat-raised-button (click)="openUploadDialog()">{{ uploadButtonText }}</button>'
|
|
217
218
|
}]
|
|
218
|
-
}],
|
|
219
|
+
}], propDecorators: { dialogClosed: [{
|
|
219
220
|
type: Output
|
|
220
221
|
}] } });
|
|
221
222
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cleavelandprice-ngx-lib-upload.mjs","sources":["../../../../projects/cleavelandprice/ngx-lib/upload/src/model/service-config.ts","../../../../projects/cleavelandprice/ngx-lib/upload/src/services/upload.service.ts","../../../../projects/cleavelandprice/ngx-lib/upload/src/components/upload-dialog/upload-dialog.component.ts","../../../../projects/cleavelandprice/ngx-lib/upload/src/components/upload-dialog/upload-dialog.component.html","../../../../projects/cleavelandprice/ngx-lib/upload/src/components/upload/upload.component.ts","../../../../projects/cleavelandprice/ngx-lib/upload/src/upload.module.ts","../../../../projects/cleavelandprice/ngx-lib/upload/src/cleavelandprice-ngx-lib-upload.ts"],"sourcesContent":["import { ServiceConfig as NgxLibServiceConfig } from '@cleavelandprice/ngx-lib';\r\n\r\nexport class ServiceConfig extends NgxLibServiceConfig {\r\n databaseEndpoint = '/upload/database';\r\n uploadDialogTitle = 'Upload Files';\r\n uploadPath: string | undefined;\r\n comment: string | undefined;\r\n dbAppId: string | undefined;\r\n externalReferenceId: string | undefined;\r\n \r\n // UI configuration\r\n uploadButtonText = 'Upload';\r\n uploadDialogCancelButtonText = 'Cancel';\r\n uploadDialogFinishButtonText = 'Finish';\r\n uploadDialogUploadButtonText = 'Upload';\r\n uploadDialogAddFilesButtonText = 'Add Files';\r\n\r\n // See the comment in the library's main service-config.ts file for an explanation\r\n constructor(useSsl_or_customApiUrl: boolean | string = false) {\r\n super(useSsl_or_customApiUrl);\r\n }\r\n}","import { Injectable, Optional } from '@angular/core';\r\nimport { HttpClient, HttpRequest, HttpEventType, HttpResponse, HttpHeaders } from '@angular/common/http';\r\nimport { Subject , Observable } from 'rxjs';\r\n\r\nimport { DatabaseFileInfo } from '../model/database-file-info';\r\nimport { FilesystemFileInfo } from '../model/filesystem-file-info';\r\nimport { FileUploadRequest } from '../model/file-upload-request';\r\nimport { ServiceConfig } from '../model/service-config';\r\n\r\n// https://malcoded.com/posts/angular-file-upload-component-with-express\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class UploadService {\r\n constructor(private http: HttpClient,\r\n @Optional() public config: ServiceConfig) {\r\n\r\n this.config = this.config ?? new ServiceConfig();\r\n }\r\n\r\n public upload(files: Set<File>): any { // {[key: string]: Observable<number>} {\r\n // this will be the our resulting map\r\n const status: {[key: string]: {progress: Observable<number>}} = {};\r\n\r\n files.forEach(file => {\r\n // create a new multipart-form for every file\r\n const formData: FormData = new FormData();\r\n formData.append('file', file, file.name);\r\n\r\n // create a http-post request and pass the form\r\n // tell it to report the upload progress\r\n\r\n // A 'Destination' header is used to optionally configure the file upload destination (filesystem)\r\n // A 'DbAppId' header is used to configure the unique identifier of database uploads\r\n \r\n let headers = new HttpHeaders();\r\n if (this.config.uploadPath) {\r\n headers = headers.set('Destination', this.config.uploadPath);\r\n }\r\n if (this.config.dbAppId) {\r\n headers = headers.set('DbAppId', this.config.dbAppId);\r\n }\r\n if (this.config.externalReferenceId) {\r\n headers = headers.set('ExternalReferenceId', this.config.externalReferenceId);\r\n }\r\n if (this.config.comment) {\r\n headers = headers.set('Comment', this.config.comment);\r\n }\r\n\r\n const req = new HttpRequest('POST', `${this.config.apiUrl}${this.config.databaseEndpoint}`, formData, {\r\n reportProgress: true,\r\n responseType: 'blob',\r\n headers\r\n });\r\n\r\n // create a new progress-subject for every file\r\n const progress = new Subject<number>();\r\n\r\n // send the http-request and subscribe for progress-updates\r\n this.http.request(req).subscribe(event => {\r\n if (event.type === HttpEventType.UploadProgress) {\r\n\r\n // calculate the progress percentage\r\n const percentDone = Math.round(100 * event.loaded / (event.total ?? 1));\r\n\r\n // pass the percentage into the progress-stream\r\n progress.next(percentDone);\r\n } else if (event instanceof HttpResponse) {\r\n\r\n // Close the progress-stream if we get an answer form the API\r\n // The upload is complete\r\n progress.complete();\r\n }\r\n });\r\n\r\n // Save every progress-observable in a map of all observables\r\n status[file.name] = {\r\n progress: progress.asObservable()\r\n };\r\n });\r\n\r\n // return the map of progress.observables\r\n return status;\r\n }\r\n\r\n public exists(fileName: string): Observable<boolean> {\r\n const query = `${this.config.apiUrl}${this.config.databaseEndpoint}`.toLowerCase().indexOf('filesystem') === -1 ?\r\n { name: fileName, dbAppId: this.config.dbAppId } :\r\n { name: fileName, destination: this.config.uploadPath };\r\n\r\n return this.http.post<boolean>(`${this.config.apiUrl}${this.config.databaseEndpoint}/exists`, query);\r\n }\r\n\r\n public download(request: FileUploadRequest): Observable<Blob> {\r\n return this.http.post(`${this.config.apiUrl}${this.config.databaseEndpoint}/stream`, request, { responseType: 'blob' });\r\n }\r\n\r\n public getUploadInfo(request: FileUploadRequest):\r\n Observable<DatabaseFileInfo | DatabaseFileInfo[] | FilesystemFileInfo | FilesystemFileInfo[]> {\r\n return this.http.post<DatabaseFileInfo | DatabaseFileInfo[] | FilesystemFileInfo | FilesystemFileInfo[]>\r\n (`${this.config.apiUrl}${this.config.databaseEndpoint}/info`, request);\r\n }\r\n}\r\n","import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';\r\nimport { MatDialogRef } from '@angular/material/dialog';\r\nimport { forkJoin } from 'rxjs';\r\n\r\nimport { UploadService } from './../../services/upload.service';\r\n\r\n@Component({\r\n templateUrl: './upload-dialog.component.html',\r\n styleUrls: ['./upload-dialog.component.css']\r\n})\r\nexport class UploadDialogComponent implements OnInit {\r\n @ViewChild('file', { static: true }) file!: ElementRef;\r\n public files: Set<File> = new Set();\r\n existingFileConflict: string | undefined;\r\n\r\n // State\r\n progress: any;\r\n canBeClosed = true;\r\n primaryButtonText: string | undefined;\r\n showCancelButton = true;\r\n uploading = false;\r\n uploadSuccessful = false;\r\n \r\n constructor(public dialogRef: MatDialogRef<UploadDialogComponent>, public uploadService: UploadService) { }\r\n\r\n ngOnInit() {\r\n this.primaryButtonText = this.uploadService.config.uploadDialogUploadButtonText;\r\n }\r\n\r\n addFiles() {\r\n this.file.nativeElement.click();\r\n }\r\n\r\n onFilesAdded() {\r\n const files: { [key: string]: File } = this.file.nativeElement.files;\r\n for (const key in files) {\r\n if (!isNaN(parseInt(key))) {\r\n // See if the file already exists\r\n this.uploadService.exists(files[key].name)\r\n .subscribe(exists => {\r\n if (exists) {\r\n this.existingFileConflict = files[key].name;\r\n }\r\n\r\n if (!exists) {\r\n this.files.add(files[key]);\r\n }\r\n });\r\n }\r\n }\r\n }\r\n\r\n closeDialog() {\r\n // if everything was uploaded already, just close the dialog\r\n if (this.uploadSuccessful) {\r\n return this.dialogRef.close();\r\n }\r\n\r\n // set the component state to \"uploading\"\r\n this.uploading = true;\r\n\r\n // start the upload and save the progress map\r\n this.progress = this.uploadService.upload(this.files);\r\n\r\n // convert the progress map into an array\r\n const allProgressObservables: any[] = [];\r\n\r\n for (let key in this.progress) {\r\n allProgressObservables.push(this.progress[key].progress);\r\n }\r\n\r\n // Adjust the state variables\r\n\r\n // The OK-button should have the text \"Finish\" now\r\n this.primaryButtonText = this.uploadService.config.uploadDialogFinishButtonText;\r\n\r\n // The dialog should not be closed while uploading\r\n this.canBeClosed = false;\r\n this.dialogRef.disableClose = true;\r\n\r\n // Hide the cancel-button\r\n this.showCancelButton = false;\r\n\r\n // When all progress-observables are completed...\r\n forkJoin(allProgressObservables).subscribe(end => {\r\n // ... the dialog can be closed again...\r\n this.canBeClosed = true;\r\n this.dialogRef.disableClose = false;\r\n\r\n // ... the upload was successful...\r\n this.uploadSuccessful = true;\r\n\r\n // ... and the component is no longer uploading\r\n this.uploading = false;\r\n });\r\n }\r\n}\r\n","<input type=\"file\" #file style=\"display: none\" (change)=\"onFilesAdded()\" multiple />\n\n<div mat-dialog-title id=\"title\">\n <div>{{ uploadService.config.uploadDialogTitle }}</div>\n <button [disabled]=\"uploading || uploadSuccessful\" mat-raised-button color=\"primary\" class=\"add-files-btn\" (click)=\"addFiles()\">\n {{ uploadService.config.uploadDialogAddFilesButtonText }}\n </button>\n</div>\n\n@if (existingFileConflict) {\n <div id=\"conflict\">\n {{ existingFileConflict }} already exists on the server and cannot be overwritten\n </div>\n}\n\n<mat-dialog-content>\n <mat-list>\n @for (file of files; track file) {\n <mat-list-item>\n <h4 mat-line>{{file.name}}</h4>\n @if (progress) {\n <mat-progress-bar mode=\"determinate\" [value]=\"progress[file.name].progress | async\"></mat-progress-bar>\n }\n </mat-list-item>\n }\n </mat-list>\n</mat-dialog-content>\n\n<mat-dialog-actions id=\"actions\">\n @if (showCancelButton) {\n <button mat-button mat-dialog-close>{{ uploadService.config.uploadDialogCancelButtonText }}</button>\n }\n @if (files.size > 0) {\n <button mat-raised-button color=\"primary\" [disabled]=\"!canBeClosed\" (click)=\"closeDialog()\">{{ primaryButtonText }}</button>\n }\n</mat-dialog-actions>\n","import { Component, OnInit, Output, EventEmitter } from '@angular/core';\r\nimport { MatDialog } from '@angular/material/dialog';\r\n\r\nimport { UploadDialogComponent } from './../upload-dialog/upload-dialog.component';\r\nimport { UploadService } from './../../services/upload.service';\r\n\r\n@Component({\r\n selector: 'cp-upload',\r\n template: '<button mat-raised-button (click)=\"openUploadDialog()\">{{ uploadButtonText }}</button>'\r\n})\r\nexport class UploadComponent implements OnInit {\r\n @Output() dialogClosed = new EventEmitter();\r\n uploadButtonText!: string;\r\n\r\n constructor(public dialog: MatDialog, public uploadService: UploadService) { }\r\n\r\n ngOnInit(): void {\r\n this.uploadButtonText = this.uploadService.config.uploadButtonText ?\r\n this.uploadService.config.uploadButtonText :\r\n 'Upload';\r\n }\r\n\r\n public openUploadDialog() {\r\n this.dialog.open(UploadDialogComponent, { width: '50%' })\r\n .afterClosed().subscribe(() => this.dialogClosed.emit());\r\n }\r\n}\r\n","import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\n\r\nimport { MatButtonModule } from '@angular/material/button';\r\nimport { MatDialogModule } from '@angular/material/dialog';\r\nimport { MatListModule } from '@angular/material/list';\r\nimport { MatProgressBarModule } from '@angular/material/progress-bar';\r\n\r\nimport { ServiceConfig } from './model/service-config';\r\n\r\nimport { UploadService } from './services/upload.service';\r\n\r\nimport { UploadComponent } from './components/upload/upload.component';\r\nimport { UploadDialogComponent } from './components/upload-dialog/upload-dialog.component';\r\n\r\n@NgModule({\r\n declarations: [\r\n UploadComponent,\r\n UploadDialogComponent\r\n ],\r\n imports: [\r\n CommonModule,\r\n MatButtonModule,\r\n MatDialogModule,\r\n MatListModule,\r\n MatProgressBarModule\r\n ],\r\n exports: [\r\n UploadComponent,\r\n UploadDialogComponent\r\n ]\r\n})\r\nexport class UploadModule {\r\n static forRoot(uploadConfig: ServiceConfig): ModuleWithProviders<UploadModule> {\r\n return {\r\n ngModule: UploadModule,\r\n providers: [\r\n UploadService,\r\n { provide: ServiceConfig, useValue: uploadConfig }\r\n ]\r\n };\r\n }\r\n\r\n constructor(@Optional() @SkipSelf() parentModule: UploadModule) {\r\n if (parentModule) {\r\n throw new Error(\r\n 'UploadModule is already loaded. Import it in the AppModule only');\r\n }\r\n }\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":["NgxLibServiceConfig","i2.ServiceConfig","i1","i2.UploadService"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cleavelandprice-ngx-lib-upload.mjs","sources":["../../../../projects/cleavelandprice/ngx-lib/upload/src/model/service-config.ts","../../../../projects/cleavelandprice/ngx-lib/upload/src/services/upload.service.ts","../../../../projects/cleavelandprice/ngx-lib/upload/src/components/upload-dialog/upload-dialog.component.ts","../../../../projects/cleavelandprice/ngx-lib/upload/src/components/upload-dialog/upload-dialog.component.html","../../../../projects/cleavelandprice/ngx-lib/upload/src/components/upload/upload.component.ts","../../../../projects/cleavelandprice/ngx-lib/upload/src/upload.module.ts","../../../../projects/cleavelandprice/ngx-lib/upload/src/cleavelandprice-ngx-lib-upload.ts"],"sourcesContent":["import { ServiceConfig as NgxLibServiceConfig } from '@cleavelandprice/ngx-lib';\r\n\r\nexport class ServiceConfig extends NgxLibServiceConfig {\r\n databaseEndpoint = '/upload/database';\r\n uploadDialogTitle = 'Upload Files';\r\n uploadPath: string | undefined;\r\n comment: string | undefined;\r\n dbAppId: string | undefined;\r\n externalReferenceId: string | undefined;\r\n \r\n // UI configuration\r\n uploadButtonText = 'Upload';\r\n uploadDialogCancelButtonText = 'Cancel';\r\n uploadDialogFinishButtonText = 'Finish';\r\n uploadDialogUploadButtonText = 'Upload';\r\n uploadDialogAddFilesButtonText = 'Add Files';\r\n\r\n // See the comment in the library's main service-config.ts file for an explanation\r\n constructor(useSsl_or_customApiUrl: boolean | string = false) {\r\n super(useSsl_or_customApiUrl);\r\n }\r\n}","import { HttpClient, HttpEventType, HttpHeaders, HttpRequest, HttpResponse } from '@angular/common/http';\r\nimport { inject, Injectable } from '@angular/core';\r\nimport { Observable, Subject } from 'rxjs';\r\n\r\nimport { DatabaseFileInfo } from '../model/database-file-info';\r\nimport { FileUploadRequest } from '../model/file-upload-request';\r\nimport { FilesystemFileInfo } from '../model/filesystem-file-info';\r\nimport { ServiceConfig } from '../model/service-config';\r\n\r\n// https://malcoded.com/posts/angular-file-upload-component-with-express\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class UploadService {\r\n //#region Services\r\n private http = inject(HttpClient);\r\n public config = inject(ServiceConfig, { optional: true }) ?? new ServiceConfig();\r\n //#endregion\r\n\r\n\r\n public upload(files: Set<File>): any { // {[key: string]: Observable<number>} {\r\n // this will be the our resulting map\r\n const status: {[key: string]: {progress: Observable<number>}} = {};\r\n\r\n files.forEach(file => {\r\n // create a new multipart-form for every file\r\n const formData: FormData = new FormData();\r\n formData.append('file', file, file.name);\r\n\r\n // create a http-post request and pass the form\r\n // tell it to report the upload progress\r\n\r\n // A 'Destination' header is used to optionally configure the file upload destination (filesystem)\r\n // A 'DbAppId' header is used to configure the unique identifier of database uploads\r\n \r\n let headers = new HttpHeaders();\r\n if (this.config.uploadPath) {\r\n headers = headers.set('Destination', this.config.uploadPath);\r\n }\r\n if (this.config.dbAppId) {\r\n headers = headers.set('DbAppId', this.config.dbAppId);\r\n }\r\n if (this.config.externalReferenceId) {\r\n headers = headers.set('ExternalReferenceId', this.config.externalReferenceId);\r\n }\r\n if (this.config.comment) {\r\n headers = headers.set('Comment', this.config.comment);\r\n }\r\n\r\n const req = new HttpRequest('POST', `${this.config.apiUrl}${this.config.databaseEndpoint}`, formData, {\r\n reportProgress: true,\r\n responseType: 'blob',\r\n headers\r\n });\r\n\r\n // create a new progress-subject for every file\r\n const progress = new Subject<number>();\r\n\r\n // send the http-request and subscribe for progress-updates\r\n this.http.request(req).subscribe(event => {\r\n if (event.type === HttpEventType.UploadProgress) {\r\n\r\n // calculate the progress percentage\r\n const percentDone = Math.round(100 * event.loaded / (event.total ?? 1));\r\n\r\n // pass the percentage into the progress-stream\r\n progress.next(percentDone);\r\n } else if (event instanceof HttpResponse) {\r\n\r\n // Close the progress-stream if we get an answer form the API\r\n // The upload is complete\r\n progress.complete();\r\n }\r\n });\r\n\r\n // Save every progress-observable in a map of all observables\r\n status[file.name] = {\r\n progress: progress.asObservable()\r\n };\r\n });\r\n\r\n // return the map of progress.observables\r\n return status;\r\n }\r\n\r\n public exists(fileName: string): Observable<boolean> {\r\n const query = `${this.config.apiUrl}${this.config.databaseEndpoint}`.toLowerCase().indexOf('filesystem') === -1 ?\r\n { name: fileName, dbAppId: this.config.dbAppId } :\r\n { name: fileName, destination: this.config.uploadPath };\r\n\r\n return this.http.post<boolean>(`${this.config.apiUrl}${this.config.databaseEndpoint}/exists`, query);\r\n }\r\n\r\n public download(request: FileUploadRequest): Observable<Blob> {\r\n return this.http.post(`${this.config.apiUrl}${this.config.databaseEndpoint}/stream`, request, { responseType: 'blob' });\r\n }\r\n\r\n public getUploadInfo(request: FileUploadRequest):\r\n Observable<DatabaseFileInfo | DatabaseFileInfo[] | FilesystemFileInfo | FilesystemFileInfo[]> {\r\n return this.http.post<DatabaseFileInfo | DatabaseFileInfo[] | FilesystemFileInfo | FilesystemFileInfo[]>\r\n (`${this.config.apiUrl}${this.config.databaseEndpoint}/info`, request);\r\n }\r\n}\r\n","import { Component, ElementRef, inject, OnInit, ViewChild } from '@angular/core';\r\nimport { MatDialogRef } from '@angular/material/dialog';\r\nimport { forkJoin } from 'rxjs';\r\n\r\nimport { UploadService } from './../../services/upload.service';\r\n\r\n@Component({\r\n templateUrl: './upload-dialog.component.html',\r\n styleUrls: ['./upload-dialog.component.css']\r\n})\r\nexport class UploadDialogComponent implements OnInit {\r\n //#region Services\r\n public dialogRef = inject(MatDialogRef<UploadDialogComponent>);\r\n public uploadService = inject(UploadService);\r\n //#endregion\r\n\r\n @ViewChild('file', { static: true }) file!: ElementRef;\r\n public files: Set<File> = new Set();\r\n existingFileConflict: string | undefined;\r\n\r\n // State\r\n progress: any;\r\n canBeClosed = true;\r\n primaryButtonText: string | undefined;\r\n showCancelButton = true;\r\n uploading = false;\r\n uploadSuccessful = false;\r\n\r\n ngOnInit() {\r\n this.primaryButtonText = this.uploadService.config.uploadDialogUploadButtonText;\r\n }\r\n\r\n addFiles() {\r\n this.file.nativeElement.click();\r\n }\r\n\r\n onFilesAdded() {\r\n const files: { [key: string]: File } = this.file.nativeElement.files;\r\n for (const key in files) {\r\n if (!isNaN(parseInt(key))) {\r\n // See if the file already exists\r\n this.uploadService.exists(files[key].name)\r\n .subscribe(exists => {\r\n if (exists) {\r\n this.existingFileConflict = files[key].name;\r\n }\r\n\r\n if (!exists) {\r\n this.files.add(files[key]);\r\n }\r\n });\r\n }\r\n }\r\n }\r\n\r\n closeDialog() {\r\n // if everything was uploaded already, just close the dialog\r\n if (this.uploadSuccessful) {\r\n return this.dialogRef.close();\r\n }\r\n\r\n // set the component state to \"uploading\"\r\n this.uploading = true;\r\n\r\n // start the upload and save the progress map\r\n this.progress = this.uploadService.upload(this.files);\r\n\r\n // convert the progress map into an array\r\n const allProgressObservables: any[] = [];\r\n\r\n for (let key in this.progress) {\r\n allProgressObservables.push(this.progress[key].progress);\r\n }\r\n\r\n // Adjust the state variables\r\n\r\n // The OK-button should have the text \"Finish\" now\r\n this.primaryButtonText = this.uploadService.config.uploadDialogFinishButtonText;\r\n\r\n // The dialog should not be closed while uploading\r\n this.canBeClosed = false;\r\n this.dialogRef.disableClose = true;\r\n\r\n // Hide the cancel-button\r\n this.showCancelButton = false;\r\n\r\n // When all progress-observables are completed...\r\n forkJoin(allProgressObservables).subscribe(end => {\r\n // ... the dialog can be closed again...\r\n this.canBeClosed = true;\r\n this.dialogRef.disableClose = false;\r\n\r\n // ... the upload was successful...\r\n this.uploadSuccessful = true;\r\n\r\n // ... and the component is no longer uploading\r\n this.uploading = false;\r\n });\r\n }\r\n}\r\n","<input type=\"file\" #file style=\"display: none\" (change)=\"onFilesAdded()\" multiple />\n\n<div mat-dialog-title id=\"title\">\n <div>{{ uploadService.config.uploadDialogTitle }}</div>\n <button [disabled]=\"uploading || uploadSuccessful\" mat-raised-button color=\"primary\" class=\"add-files-btn\" (click)=\"addFiles()\">\n {{ uploadService.config.uploadDialogAddFilesButtonText }}\n </button>\n</div>\n\n@if (existingFileConflict) {\n <div id=\"conflict\">\n {{ existingFileConflict }} already exists on the server and cannot be overwritten\n </div>\n}\n\n<mat-dialog-content>\n <mat-list>\n @for (file of files; track file) {\n <mat-list-item>\n <h4 mat-line>{{file.name}}</h4>\n @if (progress) {\n <mat-progress-bar mode=\"determinate\" [value]=\"progress[file.name].progress | async\"></mat-progress-bar>\n }\n </mat-list-item>\n }\n </mat-list>\n</mat-dialog-content>\n\n<mat-dialog-actions id=\"actions\">\n @if (showCancelButton) {\n <button mat-button mat-dialog-close>{{ uploadService.config.uploadDialogCancelButtonText }}</button>\n }\n @if (files.size > 0) {\n <button mat-raised-button color=\"primary\" [disabled]=\"!canBeClosed\" (click)=\"closeDialog()\">{{ primaryButtonText }}</button>\n }\n</mat-dialog-actions>\n","import { Component, EventEmitter, inject, OnInit, Output } from '@angular/core';\r\nimport { MatDialog } from '@angular/material/dialog';\r\n\r\nimport { UploadService } from './../../services/upload.service';\r\nimport { UploadDialogComponent } from './../upload-dialog/upload-dialog.component';\r\n\r\n@Component({\r\n selector: 'cp-upload',\r\n template: '<button mat-raised-button (click)=\"openUploadDialog()\">{{ uploadButtonText }}</button>'\r\n})\r\nexport class UploadComponent implements OnInit {\r\n //#region Services\r\n public dialog = inject(MatDialog);\r\n public uploadService = inject(UploadService);\r\n //#endregion\r\n\r\n @Output() dialogClosed = new EventEmitter();\r\n uploadButtonText!: string;\r\n\r\n ngOnInit(): void {\r\n this.uploadButtonText = this.uploadService.config.uploadButtonText ?\r\n this.uploadService.config.uploadButtonText :\r\n 'Upload';\r\n }\r\n\r\n public openUploadDialog() {\r\n this.dialog.open(UploadDialogComponent, { width: '50%' })\r\n .afterClosed().subscribe(() => this.dialogClosed.emit());\r\n }\r\n}\r\n","import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\n\r\nimport { MatButtonModule } from '@angular/material/button';\r\nimport { MatDialogModule } from '@angular/material/dialog';\r\nimport { MatListModule } from '@angular/material/list';\r\nimport { MatProgressBarModule } from '@angular/material/progress-bar';\r\n\r\nimport { ServiceConfig } from './model/service-config';\r\n\r\nimport { UploadService } from './services/upload.service';\r\n\r\nimport { UploadComponent } from './components/upload/upload.component';\r\nimport { UploadDialogComponent } from './components/upload-dialog/upload-dialog.component';\r\n\r\n@NgModule({\r\n declarations: [\r\n UploadComponent,\r\n UploadDialogComponent\r\n ],\r\n imports: [\r\n CommonModule,\r\n MatButtonModule,\r\n MatDialogModule,\r\n MatListModule,\r\n MatProgressBarModule\r\n ],\r\n exports: [\r\n UploadComponent,\r\n UploadDialogComponent\r\n ]\r\n})\r\nexport class UploadModule {\r\n static forRoot(uploadConfig: ServiceConfig): ModuleWithProviders<UploadModule> {\r\n return {\r\n ngModule: UploadModule,\r\n providers: [\r\n UploadService,\r\n { provide: ServiceConfig, useValue: uploadConfig }\r\n ]\r\n };\r\n }\r\n\r\n constructor(@Optional() @SkipSelf() parentModule: UploadModule) {\r\n if (parentModule) {\r\n throw new Error(\r\n 'UploadModule is already loaded. Import it in the AppModule only');\r\n }\r\n }\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":["NgxLibServiceConfig"],"mappings":"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"}
|