Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
U
utils
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
EIT-SWE
ux
utils
Commits
9766a141
Commit
9766a141
authored
Jun 01, 2020
by
Ryan Diehl
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'develop' into 'master'
Develop See merge request
!30
parents
dfe186a7
888e0f1f
Pipeline
#103105
passed with stages
in 7 minutes and 11 seconds
Changes
88
Pipelines
2
Hide whitespace changes
Inline
Side-by-side
Showing
88 changed files
with
2435 additions
and
38 deletions
+2435
-38
angular.json
angular.json
+85
-1
libs/utils/analytics/README.md
libs/utils/analytics/README.md
+20
-0
libs/utils/analytics/jest.config.js
libs/utils/analytics/jest.config.js
+9
-0
libs/utils/analytics/ng-package.json
libs/utils/analytics/ng-package.json
+5
-0
libs/utils/analytics/src/index.ts
libs/utils/analytics/src/index.ts
+5
-0
libs/utils/analytics/src/lib/analytics.model.ts
libs/utils/analytics/src/lib/analytics.model.ts
+13
-0
libs/utils/analytics/src/lib/analytics.service.ts
libs/utils/analytics/src/lib/analytics.service.ts
+24
-0
libs/utils/analytics/src/lib/google-analytics.service.ts
libs/utils/analytics/src/lib/google-analytics.service.ts
+85
-0
libs/utils/analytics/src/lib/google-tag-manager/google-tag-manager.service.ts
.../src/lib/google-tag-manager/google-tag-manager.service.ts
+51
-0
libs/utils/analytics/src/lib/interceptor/error.interceptor.spec.ts
...s/analytics/src/lib/interceptor/error.interceptor.spec.ts
+123
-0
libs/utils/analytics/src/lib/interceptor/error.interceptor.ts
.../utils/analytics/src/lib/interceptor/error.interceptor.ts
+49
-0
libs/utils/analytics/src/test-setup.ts
libs/utils/analytics/src/test-setup.ts
+2
-0
libs/utils/analytics/tsconfig.json
libs/utils/analytics/tsconfig.json
+7
-0
libs/utils/analytics/tsconfig.lib.json
libs/utils/analytics/tsconfig.lib.json
+20
-0
libs/utils/analytics/tsconfig.spec.json
libs/utils/analytics/tsconfig.spec.json
+10
-0
libs/utils/analytics/tslint.json
libs/utils/analytics/tslint.json
+7
-0
libs/utils/browser/src/lib/tracing/request-tracing.config.ts
libs/utils/browser/src/lib/tracing/request-tracing.config.ts
+1
-1
libs/utils/cdn/README.md
libs/utils/cdn/README.md
+104
-0
libs/utils/cdn/jest.config.js
libs/utils/cdn/jest.config.js
+9
-0
libs/utils/cdn/ng-package.json
libs/utils/cdn/ng-package.json
+5
-0
libs/utils/cdn/src/index.ts
libs/utils/cdn/src/index.ts
+5
-0
libs/utils/cdn/src/lib/cdn.config.ts
libs/utils/cdn/src/lib/cdn.config.ts
+20
-0
libs/utils/cdn/src/lib/cdn.model.spec.ts
libs/utils/cdn/src/lib/cdn.model.spec.ts
+26
-0
libs/utils/cdn/src/lib/cdn.model.ts
libs/utils/cdn/src/lib/cdn.model.ts
+4
-0
libs/utils/cdn/src/lib/cdn.module.ts
libs/utils/cdn/src/lib/cdn.module.ts
+10
-0
libs/utils/cdn/src/lib/cdn.pipe.spec.ts
libs/utils/cdn/src/lib/cdn.pipe.spec.ts
+31
-0
libs/utils/cdn/src/lib/cdn.pipe.ts
libs/utils/cdn/src/lib/cdn.pipe.ts
+13
-0
libs/utils/cdn/src/lib/cdn.service.spec.ts
libs/utils/cdn/src/lib/cdn.service.spec.ts
+271
-0
libs/utils/cdn/src/lib/cdn.service.ts
libs/utils/cdn/src/lib/cdn.service.ts
+115
-0
libs/utils/cdn/src/test-setup.ts
libs/utils/cdn/src/test-setup.ts
+2
-0
libs/utils/cdn/tsconfig.json
libs/utils/cdn/tsconfig.json
+7
-0
libs/utils/cdn/tsconfig.lib.json
libs/utils/cdn/tsconfig.lib.json
+20
-0
libs/utils/cdn/tsconfig.spec.json
libs/utils/cdn/tsconfig.spec.json
+10
-0
libs/utils/cdn/tslint.json
libs/utils/cdn/tslint.json
+7
-0
libs/utils/form/README.md
libs/utils/form/README.md
+4
-0
libs/utils/form/jest.config.js
libs/utils/form/jest.config.js
+9
-0
libs/utils/form/ng-package.json
libs/utils/form/ng-package.json
+5
-0
libs/utils/form/src/index.ts
libs/utils/form/src/index.ts
+4
-0
libs/utils/form/src/lib/disable-control/disable-control.directive.spec.ts
...src/lib/disable-control/disable-control.directive.spec.ts
+57
-0
libs/utils/form/src/lib/disable-control/disable-control.directive.ts
...form/src/lib/disable-control/disable-control.directive.ts
+15
-0
libs/utils/form/src/lib/disable-control/disable-control.module.ts
...ls/form/src/lib/disable-control/disable-control.module.ts
+11
-0
libs/utils/form/src/lib/utils/form.utils.spec.ts
libs/utils/form/src/lib/utils/form.utils.spec.ts
+17
-0
libs/utils/form/src/lib/utils/form.utils.ts
libs/utils/form/src/lib/utils/form.utils.ts
+23
-0
libs/utils/form/src/lib/validators/email.validator.spec.ts
libs/utils/form/src/lib/validators/email.validator.spec.ts
+36
-0
libs/utils/form/src/lib/validators/email.validator.ts
libs/utils/form/src/lib/validators/email.validator.ts
+26
-0
libs/utils/form/src/lib/validators/length.validators.spec.ts
libs/utils/form/src/lib/validators/length.validators.spec.ts
+70
-0
libs/utils/form/src/lib/validators/length.validators.ts
libs/utils/form/src/lib/validators/length.validators.ts
+57
-0
libs/utils/form/src/lib/validators/non-psu-email.validator.spec.ts
...s/form/src/lib/validators/non-psu-email.validator.spec.ts
+28
-0
libs/utils/form/src/lib/validators/non-psu-email.validator.ts
.../utils/form/src/lib/validators/non-psu-email.validator.ts
+6
-0
libs/utils/form/src/lib/validators/not-email.validator.spec.ts
...utils/form/src/lib/validators/not-email.validator.spec.ts
+36
-0
libs/utils/form/src/lib/validators/not-email.validator.ts
libs/utils/form/src/lib/validators/not-email.validator.ts
+9
-0
libs/utils/form/src/lib/validators/office365-email.validator.spec.ts
...form/src/lib/validators/office365-email.validator.spec.ts
+30
-0
libs/utils/form/src/lib/validators/office365-email.validator.ts
...tils/form/src/lib/validators/office365-email.validator.ts
+13
-0
libs/utils/form/src/lib/validators/psu-email.validator.spec.ts
...utils/form/src/lib/validators/psu-email.validator.spec.ts
+112
-0
libs/utils/form/src/lib/validators/psu-email.validator.ts
libs/utils/form/src/lib/validators/psu-email.validator.ts
+25
-0
libs/utils/form/src/lib/validators/psu.validators.spec.ts
libs/utils/form/src/lib/validators/psu.validators.spec.ts
+67
-0
libs/utils/form/src/lib/validators/psu.validators.ts
libs/utils/form/src/lib/validators/psu.validators.ts
+56
-0
libs/utils/form/src/lib/validators/required.validator.spec.ts
.../utils/form/src/lib/validators/required.validator.spec.ts
+58
-0
libs/utils/form/src/lib/validators/required.validator.ts
libs/utils/form/src/lib/validators/required.validator.ts
+9
-0
libs/utils/form/src/lib/validators/ssn-pattern.validator.spec.ts
...ils/form/src/lib/validators/ssn-pattern.validator.spec.ts
+30
-0
libs/utils/form/src/lib/validators/ssn-pattern.validator.ts
libs/utils/form/src/lib/validators/ssn-pattern.validator.ts
+11
-0
libs/utils/form/src/lib/validators/ssn.validator.spec.ts
libs/utils/form/src/lib/validators/ssn.validator.spec.ts
+58
-0
libs/utils/form/src/lib/validators/ssn.validator.ts
libs/utils/form/src/lib/validators/ssn.validator.ts
+16
-0
libs/utils/form/src/test-setup.ts
libs/utils/form/src/test-setup.ts
+2
-0
libs/utils/form/tsconfig.json
libs/utils/form/tsconfig.json
+7
-0
libs/utils/form/tsconfig.lib.json
libs/utils/form/tsconfig.lib.json
+20
-0
libs/utils/form/tsconfig.spec.json
libs/utils/form/tsconfig.spec.json
+10
-0
libs/utils/form/tslint.json
libs/utils/form/tslint.json
+7
-0
libs/utils/ngrx/README.md
libs/utils/ngrx/README.md
+8
-4
libs/utils/ngrx/src/index.ts
libs/utils/ngrx/src/index.ts
+10
-1
libs/utils/ngrx/src/lib/ngrx.module.ts
libs/utils/ngrx/src/lib/ngrx.module.ts
+7
-1
libs/utils/ngrx/src/lib/progress/progress.actions.ts
libs/utils/ngrx/src/lib/progress/progress.actions.ts
+6
-0
libs/utils/ngrx/src/lib/progress/progress.interceptor.spec.ts
.../utils/ngrx/src/lib/progress/progress.interceptor.spec.ts
+89
-0
libs/utils/ngrx/src/lib/progress/progress.interceptor.ts
libs/utils/ngrx/src/lib/progress/progress.interceptor.ts
+20
-0
libs/utils/ngrx/src/lib/progress/progress.reducer.spec.ts
libs/utils/ngrx/src/lib/progress/progress.reducer.spec.ts
+114
-0
libs/utils/ngrx/src/lib/progress/progress.reducer.ts
libs/utils/ngrx/src/lib/progress/progress.reducer.ts
+41
-0
libs/utils/ngrx/src/lib/window/index.ts
libs/utils/ngrx/src/lib/window/index.ts
+0
-1
libs/utils/package.json
libs/utils/package.json
+1
-0
libs/utils/properties/src/lib/properties.config.ts
libs/utils/properties/src/lib/properties.config.ts
+1
-1
libs/utils/rx/src/index.ts
libs/utils/rx/src/index.ts
+0
-1
libs/utils/rx/src/lib/reducer-utils.spec.ts
libs/utils/rx/src/lib/reducer-utils.spec.ts
+0
-11
libs/utils/rx/src/lib/reducer-utils.ts
libs/utils/rx/src/lib/reducer-utils.ts
+0
-9
libs/utils/rx/tslint.json
libs/utils/rx/tslint.json
+2
-2
libs/utils/security/tslint.json
libs/utils/security/tslint.json
+2
-2
libs/utils/theming/src/lib/style-manager.ts
libs/utils/theming/src/lib/style-manager.ts
+1
-1
nx.json
nx.json
+9
-0
package.json
package.json
+1
-1
tsconfig.json
tsconfig.json
+4
-1
No files found.
angular.json
View file @
9766a141
...
@@ -262,7 +262,7 @@
...
@@ -262,7 +262,7 @@
"projectType"
:
"library"
,
"projectType"
:
"library"
,
"root"
:
"libs/utils/theming"
,
"root"
:
"libs/utils/theming"
,
"sourceRoot"
:
"libs/utils/theming/src"
,
"sourceRoot"
:
"libs/utils/theming/src"
,
"prefix"
:
"
psu
"
,
"prefix"
:
"
ut
"
,
"architect"
:
{
"architect"
:
{
"lint"
:
{
"lint"
:
{
"builder"
:
"@angular-devkit/build-angular:tslint"
,
"builder"
:
"@angular-devkit/build-angular:tslint"
,
...
@@ -392,6 +392,90 @@
...
@@ -392,6 +392,90 @@
"styleext"
:
"scss"
"styleext"
:
"scss"
}
}
}
}
},
"utils-cdn"
:
{
"projectType"
:
"library"
,
"root"
:
"libs/utils/cdn"
,
"sourceRoot"
:
"libs/utils/cdn/src"
,
"prefix"
:
"ut"
,
"architect"
:
{
"lint"
:
{
"builder"
:
"@angular-devkit/build-angular:tslint"
,
"options"
:
{
"tsConfig"
:
[
"libs/utils/cdn/tsconfig.lib.json"
,
"libs/utils/cdn/tsconfig.spec.json"
],
"exclude"
:
[
"**/node_modules/**"
,
"!libs/utils/cdn/**"
]
}
},
"test"
:
{
"builder"
:
"@nrwl/jest:jest"
,
"options"
:
{
"jestConfig"
:
"libs/utils/cdn/jest.config.js"
,
"tsConfig"
:
"libs/utils/cdn/tsconfig.spec.json"
,
"setupFile"
:
"libs/utils/cdn/src/test-setup.ts"
}
}
},
"schematics"
:
{
"@nrwl/angular:component"
:
{
"styleext"
:
"scss"
}
}
},
"utils-form"
:
{
"projectType"
:
"library"
,
"root"
:
"libs/utils/form"
,
"sourceRoot"
:
"libs/utils/form/src"
,
"prefix"
:
"ut"
,
"architect"
:
{
"lint"
:
{
"builder"
:
"@angular-devkit/build-angular:tslint"
,
"options"
:
{
"tsConfig"
:
[
"libs/utils/form/tsconfig.lib.json"
,
"libs/utils/form/tsconfig.spec.json"
],
"exclude"
:
[
"**/node_modules/**"
,
"!libs/utils/form/**"
]
}
},
"test"
:
{
"builder"
:
"@nrwl/jest:jest"
,
"options"
:
{
"jestConfig"
:
"libs/utils/form/jest.config.js"
,
"tsConfig"
:
"libs/utils/form/tsconfig.spec.json"
,
"setupFile"
:
"libs/utils/form/src/test-setup.ts"
}
}
},
"schematics"
:
{
"@nrwl/angular:component"
:
{
"styleext"
:
"scss"
}
}
},
"utils-analytics"
:
{
"projectType"
:
"library"
,
"root"
:
"libs/utils/analytics"
,
"sourceRoot"
:
"libs/utils/analytics/src"
,
"prefix"
:
"ut"
,
"architect"
:
{
"lint"
:
{
"builder"
:
"@angular-devkit/build-angular:tslint"
,
"options"
:
{
"tsConfig"
:
[
"libs/utils/analytics/tsconfig.lib.json"
,
"libs/utils/analytics/tsconfig.spec.json"
],
"exclude"
:
[
"**/node_modules/**"
,
"!libs/utils/analytics/**"
]
}
},
"test"
:
{
"builder"
:
"@nrwl/jest:jest"
,
"options"
:
{
"jestConfig"
:
"libs/utils/analytics/jest.config.js"
,
"tsConfig"
:
"libs/utils/analytics/tsconfig.spec.json"
,
"setupFile"
:
"libs/utils/analytics/src/test-setup.ts"
}
}
},
"schematics"
:
{
"@nrwl/angular:component"
:
{
"styleext"
:
"scss"
}
}
}
}
},
},
"cli"
:
{
"cli"
:
{
...
...
libs/utils/analytics/README.md
0 → 100644
View file @
9766a141
# @psu/utils/analytics
Provides integration with Google Analytics
## Setup
1.
Setup Google Tag Manager and generate a container ID for your app (usually non-prod + prod)
1.
Provide
`ANALYTICS_CONFIG`
injection token and initialize it in your app initializer
1.
Inject
`GoogleTagManagerService`
into your
`AppComponent`
## ErrorInterceptor
There is an optional
`ErrorInterceptor`
HTTP interceptor that can log any type of network errors to Google Analytics.
There is a custom report/dashboard that you can then view to see a summary of errors.
This has been helpful to debug specific customer problems - CORS errors, anti-virus software
that disabled PUT requests, etc.
## Custom Events
`AnalyticsService`
can record page views and custom analytics events.
libs/utils/analytics/jest.config.js
0 → 100644
View file @
9766a141
module
.
exports
=
{
name
:
'
utils-analytics
'
,
preset
:
'
../../../jest.config.js
'
,
coverageDirectory
:
'
../../../coverage/libs/utils/analytics
'
,
snapshotSerializers
:
[
'
jest-preset-angular/AngularSnapshotSerializer.js
'
,
'
jest-preset-angular/HTMLCommentSerializer.js
'
]
};
libs/utils/analytics/ng-package.json
0 → 100644
View file @
9766a141
{
"lib"
:
{
"entryFile"
:
"src/index.ts"
}
}
libs/utils/analytics/src/index.ts
0 → 100644
View file @
9766a141
export
*
from
'
./lib/analytics.model
'
;
export
{
AnalyticsService
}
from
'
./lib/analytics.service
'
;
export
{
GoogleAnalyticsService
}
from
'
./lib/google-analytics.service
'
;
export
*
from
'
./lib/google-tag-manager/google-tag-manager.service
'
;
export
{
ErrorStatusInterceptor
}
from
'
./lib/interceptor/error.interceptor
'
;
libs/utils/analytics/src/lib/analytics.model.ts
0 → 100644
View file @
9766a141
import
{
InjectionToken
}
from
'
@angular/core
'
;
export
interface
AnalyticsSource
{
pageView
(
url
:
string
):
void
;
recordEvent
(
category
:
string
,
label
:
string
,
action
:
string
,
value
:
any
):
void
;
}
export
interface
AnalyticsConfig
{
trackingId
?:
string
;
tagManagerContainerId
?:
string
;
}
export
const
ANALYTICS_CONFIG
=
new
InjectionToken
<
AnalyticsConfig
>
(
'
psu.utils.analytics.config
'
);
libs/utils/analytics/src/lib/analytics.service.ts
0 → 100644
View file @
9766a141
import
{
Injectable
}
from
'
@angular/core
'
;
import
{
NavigationEnd
,
Router
}
from
'
@angular/router
'
;
import
{
filter
,
tap
}
from
'
rxjs/operators
'
;
import
{
GoogleAnalyticsService
}
from
'
./google-analytics.service
'
;
@
Injectable
({
providedIn
:
'
root
'
})
export
class
AnalyticsService
{
constructor
(
private
router
:
Router
,
private
google
:
GoogleAnalyticsService
)
{
this
.
router
.
events
.
pipe
(
filter
(
event
=>
event
instanceof
NavigationEnd
),
tap
(
event
=>
this
.
google
.
pageView
((
event
as
NavigationEnd
).
urlAfterRedirects
))
)
.
subscribe
(
event
=>
{});
}
public
recordEvent
(
action
:
string
,
category
?:
string
,
label
?:
string
):
void
{
this
.
google
.
recordEvent
(
action
,
category
,
label
);
}
public
recordError
(
exceptionMsg
:
string
):
void
{
this
.
google
.
recordException
(
exceptionMsg
);
}
}
libs/utils/analytics/src/lib/google-analytics.service.ts
0 → 100644
View file @
9766a141
import
{
isPlatformBrowser
}
from
'
@angular/common
'
;
import
{
Inject
,
Injectable
,
PLATFORM_ID
}
from
'
@angular/core
'
;
import
{
AnalyticsConfig
,
AnalyticsSource
,
ANALYTICS_CONFIG
}
from
'
./analytics.model
'
;
declare
global
{
interface
Window
{
dataLayer
:
unknown
[];
gtag
:
Function
;
}
}
@
Injectable
({
providedIn
:
'
root
'
})
export
class
GoogleAnalyticsService
implements
AnalyticsSource
{
private
gtag
:
Function
;
private
scriptLoaded
=
false
;
constructor
(
@
Inject
(
PLATFORM_ID
)
private
platform
:
Object
,
@
Inject
(
ANALYTICS_CONFIG
)
private
config
:
AnalyticsConfig
)
{
this
.
gtag
=
this
.
loadGoogleAnalytics
();
this
.
gtag
(
'
config
'
,
this
.
config
.
trackingId
,
{
send_page_view
:
false
});
}
private
getReady
():
void
{
if
(
!
this
.
scriptLoaded
)
{
this
.
scriptLoaded
=
true
;
if
(
typeof
window
!==
'
undefined
'
)
{
window
.
dataLayer
=
window
.
dataLayer
||
[];
window
.
gtag
=
function
():
void
{
window
.
dataLayer
.
push
(
arguments
);
};
window
.
gtag
(
'
js
'
,
new
Date
());
}
const
doc
=
<
HTMLDivElement
>
document
.
body
;
const
script
=
document
.
createElement
(
'
script
'
);
script
.
innerHTML
=
''
;
script
.
src
=
`https://www.googletagmanager.com/gtag/js?id=
${
this
.
config
.
trackingId
}
`
;
script
.
async
=
true
;
script
.
defer
=
true
;
doc
.
appendChild
(
script
);
}
}
public
pageView
(
url
:
string
):
void
{
this
.
gtag
(
'
config
'
,
this
.
config
.
trackingId
,
{
page_path
:
url
});
}
public
recordEvent
(
action
:
string
,
category
?:
string
,
label
?:
string
):
void
{
this
.
gtag
(
'
event
'
,
action
,
{
event_category
:
category
,
event_label
:
label
});
}
public
recordException
(
exceptionMsg
:
string
):
void
{
this
.
gtag
(
'
event
'
,
'
exception
'
,
{
method
:
'
Angular
'
,
event_category
:
'
exception
'
,
event_label
:
'
Network Error in From User
'
,
description
:
exceptionMsg
});
}
private
loadGoogleAnalytics
():
Function
{
let
ret
:
Function
;
if
(
isPlatformBrowser
(
this
.
platform
))
{
this
.
getReady
();
ret
=
(
<
any
>
window
).
gtag
;
if
(
!
ret
)
{
console
.
warn
(
'
Unable to find Google Analytics function (window.gtag). Returning empty function.
'
);
ret
=
()
=>
{};
}
}
else
{
ret
=
()
=>
{};
}
return
ret
;
}
}
libs/utils/analytics/src/lib/google-tag-manager/google-tag-manager.service.ts
0 → 100644
View file @
9766a141
import
{
isPlatformBrowser
}
from
'
@angular/common
'
;
import
{
Inject
,
Injectable
,
PLATFORM_ID
}
from
'
@angular/core
'
;
import
{
Logger
}
from
'
@psu/utils/logger
'
;
import
{
AnalyticsConfig
,
ANALYTICS_CONFIG
}
from
'
../analytics.model
'
;
@
Injectable
({
providedIn
:
'
root
'
})
export
class
GoogleTagManagerService
{
private
scriptLoaded
=
false
;
constructor
(
@
Inject
(
PLATFORM_ID
)
private
platform
:
Object
,
@
Inject
(
ANALYTICS_CONFIG
)
private
config
:
AnalyticsConfig
,
private
logger
:
Logger
)
{
this
.
loadGoogleTagManager
();
}
private
loadGoogleTagManager
():
void
{
if
(
isPlatformBrowser
(
this
.
platform
))
{
if
(
!
this
.
scriptLoaded
)
{
if
(
this
.
config
.
tagManagerContainerId
)
{
this
.
scriptLoaded
=
true
;
try
{
const
head
=
document
.
head
;
const
script
=
document
.
createElement
(
'
script
'
);
script
.
innerHTML
=
`(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','
${
this
.
config
.
tagManagerContainerId
}
');`
;
head
.
appendChild
(
script
);
const
doc
=
document
.
body
;
const
noscript
=
document
.
createElement
(
'
noscript
'
);
noscript
.
innerHTML
=
`<iframe src="https://www.googletagmanager.com/ns.html?id=
${
this
.
config
.
tagManagerContainerId
}
"height="0" width="0" style="display:none;visibility:hidden"></iframe>`
;
doc
.
appendChild
(
script
);
}
catch
(
err
)
{
this
.
scriptLoaded
=
false
;
this
.
logger
.
error
(
`Error loading GoogleTagManager scripts:
${
err
}
`
);
}
}
else
{
this
.
logger
.
error
(
`You have injected the GoogleTagManagerService but it did not find tagManagerContainerId in
the ANALYTICS_CONFIG InjectionToken. Possible race condition?`
);
}
}
}
}
}
libs/utils/analytics/src/lib/interceptor/error.interceptor.spec.ts
0 → 100644
View file @
9766a141
import
{
HttpClient
,
HttpHeaders
,
HTTP_INTERCEPTORS
}
from
'
@angular/common/http
'
;
import
{
HttpClientTestingModule
,
HttpTestingController
}
from
'
@angular/common/http/testing
'
;
import
{
TestBed
}
from
'
@angular/core/testing
'
;
import
{
NavigationEnd
,
Router
}
from
'
@angular/router
'
;
import
{
RouterTestingModule
}
from
'
@angular/router/testing
'
;
import
{
of
}
from
'
rxjs
'
;
import
{
catchError
}
from
'
rxjs/operators
'
;
import
{
Mock
}
from
'
ts-mocks
'
;
import
{
AnalyticsConfig
,
ANALYTICS_CONFIG
}
from
'
../..
'
;
import
{
AnalyticsService
}
from
'
../analytics.service
'
;
import
{
ErrorStatusInterceptor
}
from
'
./error.interceptor
'
;
describe
(
'
ErrorStatusInterceptor
'
,
()
=>
{
let
gtag
:
Mock
<
AnalyticsService
>
;
let
mockRouter
:
Mock
<
Router
>
;
const
config
:
AnalyticsConfig
=
{};
const
end
:
NavigationEnd
=
{
urlAfterRedirects
:
''
,
id
:
1
,
url
:
''
};
let
backend
:
HttpTestingController
;
let
http
:
HttpClient
;
beforeEach
(()
=>
{
gtag
=
new
Mock
<
AnalyticsService
>
({
recordError
:
()
=>
{}
});
mockRouter
=
new
Mock
<
Router
>
({
events
:
of
(
end
)
});
TestBed
.
configureTestingModule
({
imports
:
[
RouterTestingModule
,
HttpClientTestingModule
],
providers
:
[
{
provide
:
Router
,
useValue
:
mockRouter
.
Object
},
{
provide
:
AnalyticsService
,
useValue
:
gtag
.
Object
},
{
provide
:
ANALYTICS_CONFIG
,
useFactory
:
()
=>
config
},
{
provide
:
HTTP_INTERCEPTORS
,
useClass
:
ErrorStatusInterceptor
,
multi
:
true
}
]
});
backend
=
TestBed
.
get
(
HttpTestingController
);
http
=
TestBed
.
get
(
HttpClient
);
});
afterEach
(()
=>
{
backend
.
verify
();
});
it
(
'
should create
'
,
()
=>
{
expect
(
TestBed
.
get
(
HTTP_INTERCEPTORS
)[
0
]).
toBeDefined
();
});
describe
(
'
intercepting http calls
'
,
()
=>
{
function
makeRequest
(
method
=
'
GET
'
,
url
=
'
/data
'
,
headers
?:
HttpHeaders
)
{
http
.
request
(
method
,
url
,
{
headers
})
.
pipe
(
catchError
(
err
=>
of
(
null
)))
.
subscribe
();
}
describe
(
'
when request has no headers
'
,
()
=>
{
beforeEach
(()
=>
{
makeRequest
();
});
describe
(
'
when http response is error
'
,
()
=>
{
beforeEach
(()
=>
{
backend
.
expectOne
(
'
/data
'
).
flush
({
errorMessage
:
'
Uh oh!
'
},
{
status
:
500
,
statusText
:
'
Server Error
'
});
});
it
(
'
should call recordError with no request ID
'
,
()
=>
{
expect
(
gtag
.
Object
.
recordError
).
toHaveBeenCalledWith
(
jasmine
.
stringMatching
(
/^
((?!
xRequestId
)
.
)
*$/
));
expect
(
gtag
.
Object
.
recordError
).
toHaveBeenCalledWith
(
jasmine
.
stringMatching
(
/^HTTP 500: Server Error/
));
expect
(
gtag
.
Object
.
recordError
).
toHaveBeenCalledWith
(
jasmine
.
stringMatching
(
/requestMethod: GET/
));
expect
(
gtag
.
Object
.
recordError
).
toHaveBeenCalledWith
(
jasmine
.
stringMatching
(
/fullRequestUrl:
\/
data/
));
expect
(
gtag
.
Object
.
recordError
).
toHaveBeenCalledWith
(
jasmine
.
stringMatching
(
/Uh oh!/
));
});
});
describe
(
'
when http error response has request ID header
'
,
()
=>
{
beforeEach
(()
=>
{
backend
.
expectOne
(
'
/data
'
)
.
flush
({},
{
status
:
500
,
statusText
:
'
No
'
,
headers
:
{
'
X-Request-Id
'
:
'
server-request
'
}
});
});
it
(
'
should record event with request id from server
'
,
()
=>
{
expect
(
gtag
.
Object
.
recordError
).
toHaveBeenCalledWith
(
jasmine
.
stringMatching
(
/xRequestId: server-request/
));
});
});
});
describe
(
'
when request has requestid header
'
,
()
=>
{
beforeEach
(()
=>
{
makeRequest
(
'
PUT
'
,
'
/other/data?id=1
'
,
new
HttpHeaders
().
append
(
'
X-Request-Id
'
,
'
client-request
'
));
});
it
(
'
should record event with request id from client
'
,
()
=>
{
backend
.
expectOne
(
'
/other/data?id=1
'
)
.
flush
({
errorMessage
:
'
Uh oh!
'
},
{
status
:
404
,
statusText
:
'
Not Found
'
});
expect
(
gtag
.
Object
.
recordError
).
toHaveBeenCalledWith
(
jasmine
.
stringMatching
(
/xRequestId: client-request/
));
expect
(
gtag
.
Object
.
recordError
).
toHaveBeenCalledWith
(
jasmine
.
stringMatching
(
/requestMethod: PUT/
));
expect
(
gtag
.
Object
.
recordError
).
toHaveBeenCalledWith
(
jasmine
.
stringMatching
(
/fullRequestUrl:
\/
other
\/
data
\?
id=1/
)
);
});
it
(
'
should log client errors differently
'
,
()
=>
{
backend
.
expectOne
(
'
/other/data?id=1
'
).
error
(
new
ErrorEvent
(
'
CORS error
'
,
{
message
:
'
not allowed
'
}));
expect
(
gtag
.
Object
.
recordError
).
toHaveBeenCalledWith
(
jasmine
.
stringMatching
(
/xRequestId: client-request/
));
expect
(
gtag
.
Object
.
recordError
).
toHaveBeenCalledWith
(
jasmine
.
stringMatching
(
/Client
\/
Network Error: CORS error -> not allowed/
)
);
});
});
});
});
libs/utils/analytics/src/lib/interceptor/error.interceptor.ts
0 → 100644
View file @
9766a141
import
{
HttpErrorResponse
,
HttpEvent
,
HttpHandler
,
HttpInterceptor
,
HttpRequest
}
from
'
@angular/common/http
'
;
import
{
Injectable
}
from
'
@angular/core
'
;
import
{
Observable
,
throwError
}
from
'
rxjs
'
;
import
{
catchError
}
from
'
rxjs/operators
'
;
import
{
AnalyticsService
}
from
'
../analytics.service
'
;
const
X_REQUEST_ID
=
'
x-request-id
'
;
@
Injectable
({
providedIn
:
'
root
'
})
export
class
ErrorStatusInterceptor
implements
HttpInterceptor
{
constructor
(
private
aService
:
AnalyticsService
)
{}
public
intercept
(
request
:
HttpRequest
<
any
>
,
next
:
HttpHandler
):
Observable
<
HttpEvent
<
any
>>
{
return
next
.
handle
(
request
).
pipe
(
catchError
((
error
:
HttpErrorResponse
)
=>
{
let
errorMsg
=
'
not provided
'
;
// capture the request ID either from the error response or the original request
let
xRequestId
=
''
;
if
(
error
.
headers
.
has
(
X_REQUEST_ID
))
{
xRequestId
=
error
.
headers
.
get
(
X_REQUEST_ID
);
}
else
if
(
request
.
headers
.
has
(
X_REQUEST_ID
))
{
xRequestId
=
request
.
headers
.
get
(
X_REQUEST_ID
);
}
if
(
error
.
error
&&
error
.
error
.
errorMessage
)
{
errorMsg
=
error
.
error
.
errorMessage
;
}
// there are 2 possible types of errors: client side and server side HTTP errors
// CORS errors fall into client side errors, they will have ErrorCode 0 in chrome and you will not see the real response code.
if
(
error
.
error
instanceof
ErrorEvent
)
{
// client error
errorMsg
=
`Client/Network Error:
${
error
.
error
.
type
}
->
${
error
.
error
.
message
}
`
;
}
else
{
// server error, pull out HTTP response status and message
errorMsg
=
`HTTP
${
error
.
status
}
:
${
error
.
statusText
}
, message: [
${
errorMsg
}
]`
;
}
this
.
aService
.
recordError
(
`
${
errorMsg
}
time: [
${
new
Date
().
toISOString
()}
] from [
${
error
.
url
}
] requestMethod:
${
request
.
method
}
fullRequestUrl:
${
request
.
urlWithParams
}
${
!!
xRequestId
?
`xRequestId:
${
xRequestId
}
`
:
''
}
`
);
return
throwError
(
error
);
})
);
}
}
libs/utils/analytics/src/test-setup.ts
0 → 100644
View file @
9766a141
import
'
jest-preset-angular
'
;
import
'
../../../../jestGlobalMocks
'
;
libs/utils/analytics/tsconfig.json
0 → 100644
View file @
9766a141
{
"extends"
:
"../../../tsconfig.json"
,
"compilerOptions"
:
{
"types"
:
[
"node"
,
"jest"
]
},
"include"
:
[
"**/*.ts"
]
}
libs/utils/analytics/tsconfig.lib.json
0 → 100644
View file @
9766a141
{
"extends"
:
"./tsconfig.json"
,
"compilerOptions"
:
{
"outDir"
:
"../../../dist/out-tsc"
,
"target"
:
"es2015"
,
"declaration"
:
true
,
"inlineSources"
:
true
,
"types"
:
[],
"lib"
:
[
"dom"
,
"es2018"
]
},
"angularCompilerOptions"
:
{
"annotateForClosureCompiler"
:
true
,
"skipTemplateCodegen"
:
true
,
"strictMetadataEmit"
:
true
,
"fullTemplateTypeCheck"
:
true
,
"strictInjectionParameters"
:
true
,
"enableResourceInlining"
:
true
},
"exclude"
:
[
"src/test-setup.ts"
,
"**/*.spec.ts"
]
}
libs/utils/analytics/tsconfig.spec.json
0 → 100644
View file @
9766a141
{
"extends"
:
"./tsconfig.json"
,
"compilerOptions"
:
{
"outDir"
:
"../../../dist/out-tsc"
,
"module"
:
"commonjs"
,
"types"
:
[
"jest"
,
"node"
]
},
"files"
:
[
"src/test-setup.ts"
],
"include"
:
[
"**/*.spec.ts"
,
"**/*.d.ts"
]
}
libs/utils/analytics/tslint.json
0 → 100644
View file @
9766a141
{