Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Raphael Ochsenbein
openid-connect-playground
Commits
3fb03cff
Verified
Commit
3fb03cff
authored
Feb 21, 2019
by
Raphael Ochsenbein
Browse files
Simple Toast Service
parent
d0138816
Pipeline
#635
failed with stages
in 55 seconds
Changes
14
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
api/server.js
View file @
3fb03cff
// from: https://auth0.com/docs/multifactor-authentication/step-up-authentication/step-up-for-apis
// set dependencies
const
express
=
require
(
'
express
'
);
const
app
=
express
();
...
...
package.json
View file @
3fb03cff
...
...
@@ -4,8 +4,8 @@
"scripts"
:
{
"ng"
:
"ng"
,
"start"
:
"ng serve --aot"
,
"build"
:
"ng build"
,
"test"
:
"ng test"
,
"build"
:
"ng build
--prod --progress=false
"
,
"test"
:
"ng test
--source-map=false --no-watch
"
,
"lint"
:
"ng lint && npm run lint:sass"
,
"api"
:
"node api/server.js"
,
"lint:sass"
:
"sass-lint -c .sass-lint.yml -v -q"
,
...
...
src/app/app.component.html
View file @
3fb03cff
...
...
@@ -4,14 +4,12 @@
</h1>
</div>
<h2>
Log In / Log Out
</h2>
<!--<button [ibmButton]="'primary'" [size]="'normal'" (click)="showToast()">Toast</button><span> </span>-->
<button
[ibmButton]=
"'primary'"
[size]=
"'normal'"
(click)=
"loginPopup()"
>
Log In
</button>
<button
[ibmButton]=
"'danger--primary'"
[size]=
"'normal'"
(click)=
"logoutPopup()"
>
Log Out
</button>
<div
class=
"notification-container"
></div>
<ibm-toast
[notificationObj]=
"{
type: 'error',
title: 'Sample toast',
subtitle: 'Sample subtitle message',
caption: 'Sample caption'
}"
></ibm-toast>
<hr/>
<button
[ibmButton]=
"'primary'"
[size]=
"'normal'"
(click)=
"loginPopup()"
>
Call 1FA API
</button>
<button
[ibmButton]=
"'danger--primary'"
[size]=
"'normal'"
(click)=
"loginPopup()"
>
Call 2FA API
</button>
<hr/>
<button
[ibmButton]=
"'primary'"
[size]=
"'normal'"
(click)=
"loginPopup()"
>
Check 2FA
</button>
<button
[ibmButton]=
"'danger--primary'"
[size]=
"'normal'"
(click)=
"loginPopup()"
>
Login Request 2FA
</button>
src/app/app.component.scss
View file @
3fb03cff
...
...
@@ -3,6 +3,7 @@ h2 {
color
:
whitesmoke
;
}
.notification-container
{
button
{
margin-right
:
4px
;
}
src/app/app.component.ts
View file @
3fb03cff
import
{
Component
}
from
'
@angular/core
'
;
import
{
OidcFacade
}
from
'
ng-oidc-client
'
;
import
{
Notification
Service
}
from
'
carbon-components-angular
'
;
import
{
Toast
Service
}
from
'
./toast
'
;
@
Component
({
selector
:
'
app-root
'
,
...
...
@@ -10,26 +10,35 @@ import { NotificationService } from 'carbon-components-angular';
export
class
AppComponent
{
title
=
'
openid-connect-playground
'
;
constructor
(
private
oidcFacade
:
OidcFacade
,
private
notifications
:
NotificationService
)
{}
constructor
(
private
oidcFacade
:
OidcFacade
,
private
toast
:
ToastService
,
)
{}
loginPopup
()
{
this
.
notifications
.
showNotification
({
this
.
toast
.
show
({
type
:
'
info
'
,
title
:
'
Log In
'
,
message
:
'
Logging in.
'
,
target
:
'
.notification-container
'
,
caption
:
'
Logging in.
'
,
});
this
.
oidcFacade
.
signinPopup
();
}
logoutPopup
()
{
this
.
notifications
.
showNotification
({
this
.
toast
.
show
({
type
:
'
warn
'
,
title
:
'
Log Out
'
,
message
:
'
Logging out.
'
,
target
:
'
.notification-container
'
,
caption
:
'
Logging out.
'
,
});
this
.
oidcFacade
.
signoutPopup
();
}
showToast
()
{
this
.
toast
.
show
({
type
:
'
info
'
,
title
:
'
Test
'
,
caption
:
'
Testing
'
,
});
}
}
src/app/app.module.ts
View file @
3fb03cff
...
...
@@ -13,6 +13,9 @@ import {OidcInterceptorService} from './oidc-interceptor.service';
import
{
OidcEffectsService
}
from
'
./oidc-effects.service
'
;
import
{
metaReducers
}
from
'
./logout.metareducer
'
;
import
{
ButtonModule
,
NotificationModule
,
NotificationService
}
from
'
carbon-components-angular
'
;
import
{
ToastModule
}
from
'
./toast
'
;
import
{
FormsModule
}
from
'
@angular/forms
'
;
import
{
BrowserAnimationsModule
}
from
'
@angular/platform-browser/animations
'
;
// Setup done according to https://www.npmjs.com/package/ng-oidc-client
...
...
@@ -33,6 +36,10 @@ export const rootStore: ActionReducerMap<State> = {
],
imports
:
[
BrowserModule
,
FormsModule
,
BrowserAnimationsModule
,
ButtonModule
,
ToastModule
.
forRoot
(),
StoreModule
.
forRoot
(
rootStore
,
{
metaReducers
}),
EffectsModule
.
forRoot
([
OidcEffectsService
]),
NgOidcClientModule
.
forRoot
({
...
...
@@ -53,8 +60,6 @@ export const rootStore: ActionReducerMap<State> = {
// level: 0,
// },
}),
ButtonModule
,
NotificationModule
,
],
providers
:
[
OidcGuardService
,
...
...
@@ -64,7 +69,6 @@ export const rootStore: ActionReducerMap<State> = {
multi
:
true
},
OidcEffectsService
,
NotificationService
,
],
bootstrap
:
[
AppComponent
]
})
...
...
src/app/oidc-effects.service.ts
View file @
3fb03cff
...
...
@@ -3,25 +3,36 @@ import {OidcActions} from 'ng-oidc-client';
import
{
Actions
,
Effect
,
ofType
}
from
'
@ngrx/effects
'
;
import
{
Action
}
from
'
@ngrx/store
'
;
import
{
Observable
}
from
'
rxjs
'
;
import
{
Notification
Service
}
from
'
carbon-components-angular
'
;
import
{
Toast
Service
}
from
'
./toast
'
;
export
class
OidcEffectsService
{
constructor
(
private
actions$
:
Actions
,
private
notifications
:
Notification
Service
,
private
toast
:
Toast
Service
,
)
{}
@
Effect
({
dispatch
:
false
})
onUserSignedOut$
:
Observable
<
Action
>
=
this
.
actions$
.
pipe
(
ofType
(
OidcActions
.
OidcActionTypes
.
OnUserSignedOut
),
tap
(
args
=>
{
this
.
notifications
.
showNotification
({
this
.
toast
.
show
({
type
:
'
warn
'
,
title
:
'
Log Out
'
,
message
:
'
You have been logged out
'
,
target
:
'
.notification-container
'
,
caption
:
'
You have been logged out
'
,
});
// this.router.navigate(['/home']);
})
);
@
Effect
({
dispatch
:
false
})
onUserLoaded$
:
Observable
<
Action
>
=
this
.
actions$
.
pipe
(
ofType
(
OidcActions
.
OidcActionTypes
.
OnUserLoaded
),
tap
(
args
=>
{
this
.
toast
.
show
({
type
:
'
info
'
,
title
:
'
Log In
'
,
caption
:
'
You have been logged in
'
,
});
})
);
}
src/app/toast/index.ts
0 → 100644
View file @
3fb03cff
export
*
from
'
./toast.module
'
;
export
*
from
'
./toast.service
'
;
// https://blog.angularindepth.com/creating-a-toast-service-with-angular-cdk-a0d35fd8cc12
// https://stackblitz.com/edit/angular-toast-service?file=src%2Fapp%2Ftoast%2Ftoast.component.ts
src/app/toast/toast.animation.ts
0 → 100644
View file @
3fb03cff
import
{
AnimationTriggerMetadata
,
trigger
,
state
,
transition
,
style
,
animate
,
}
from
'
@angular/animations
'
;
export
const
toastAnimations
:
{
readonly
fadeToast
:
AnimationTriggerMetadata
;
}
=
{
fadeToast
:
trigger
(
'
fadeAnimation
'
,
[
state
(
'
default
'
,
style
({
opacity
:
1
})),
transition
(
'
void => *
'
,
[
style
({
opacity
:
0
}),
animate
(
'
{{ fadeIn }}ms
'
)]),
transition
(
'
default => closing
'
,
animate
(
'
{{ fadeOut }}ms
'
,
style
({
opacity
:
0
})),
),
]),
};
export
type
ToastAnimationState
=
'
default
'
|
'
closing
'
;
src/app/toast/toast.component.ts
0 → 100644
View file @
3fb03cff
import
{
Component
,
OnInit
,
OnDestroy
,
Inject
}
from
'
@angular/core
'
;
import
{
AnimationEvent
}
from
'
@angular/animations
'
;
import
{
ToastData
,
_TOAST_CONFIG_TOKEN
,
MyToastConfig
,
defaultToastConfig
}
from
'
./toast.config
'
;
import
{
ToastRef
}
from
'
./toast.ref
'
;
import
{
toastAnimations
,
ToastAnimationState
}
from
'
./toast.animation
'
;
@
Component
({
selector
:
'
app-toast
'
,
template
:
`
<ibm-toast [notificationObj]="data"
[@fadeAnimation]="{value: animationState, params:
{ fadeIn: toastConfig.animation.fadeIn, fadeOut: toastConfig.animation.fadeOut }}"
(@fadeAnimation.done)="onFadeFinished($event)">
</ibm-toast>
`
,
animations
:
[
toastAnimations
.
fadeToast
],
})
export
class
ToastComponent
implements
OnInit
,
OnDestroy
{
animationState
:
ToastAnimationState
=
'
default
'
;
private
intervalId
:
number
;
constructor
(
readonly
data
:
ToastData
,
readonly
ref
:
ToastRef
,
@
Inject
(
_TOAST_CONFIG_TOKEN
)
public
toastConfig
:
MyToastConfig
)
{
// this.iconType = data.type === 'success' ? 'done' : data.type;
// somehow empty injection of the config... maybe issue with carbon?
this
.
toastConfig
=
{...
defaultToastConfig
,
...
this
.
toastConfig
};
}
ngOnInit
()
{
this
.
intervalId
=
setTimeout
(()
=>
this
.
animationState
=
'
closing
'
,
5000
);
}
ngOnDestroy
()
{
clearTimeout
(
this
.
intervalId
);
}
close
()
{
this
.
ref
.
close
();
}
onFadeFinished
(
event
:
AnimationEvent
)
{
const
{
toState
}
=
event
;
const
isFadeOut
=
(
toState
as
ToastAnimationState
)
===
'
closing
'
;
const
itFinished
=
this
.
animationState
===
'
closing
'
;
if
(
isFadeOut
&&
itFinished
)
{
this
.
close
();
}
}
}
src/app/toast/toast.config.ts
0 → 100644
View file @
3fb03cff
import
{
InjectionToken
,
TemplateRef
}
from
'
@angular/core
'
;
export
class
ToastData
{
type
:
string
;
title
:
string
;
caption
:
string
;
subtitle
?:
string
;
template
?:
TemplateRef
<
any
>
;
templateContext
?:
{};
}
// export class ToastData {
// type: ToastType;
// text?: string;
// template?: TemplateRef<any>;
// templateContext?: {};
// }
export
type
ToastType
=
'
warning
'
|
'
info
'
|
'
success
'
;
export
interface
MyToastConfig
{
position
?:
{
top
:
number
;
right
:
number
;
};
animation
?:
{
fadeOut
:
number
;
fadeIn
:
number
;
};
}
export
const
defaultToastConfig
:
MyToastConfig
=
{
position
:
{
top
:
20
,
right
:
20
,
},
animation
:
{
fadeOut
:
2500
,
fadeIn
:
300
,
},
};
export
const
_TOAST_CONFIG_TOKEN
=
new
InjectionToken
(
'
_toast-config
'
);
src/app/toast/toast.module.ts
0 → 100644
View file @
3fb03cff
import
{
ModuleWithProviders
,
NgModule
}
from
'
@angular/core
'
;
import
{
OverlayModule
}
from
'
@angular/cdk/overlay
'
;
import
{
NotificationModule
}
from
'
carbon-components-angular
'
;
import
{
ToastComponent
}
from
'
./toast.component
'
;
import
{
defaultToastConfig
,
_TOAST_CONFIG_TOKEN
}
from
'
./toast.config
'
;
@
NgModule
({
imports
:
[
OverlayModule
,
NotificationModule
],
declarations
:
[
ToastComponent
],
entryComponents
:
[
ToastComponent
]
})
export
class
ToastModule
{
public
static
forRoot
(
config
=
defaultToastConfig
):
ModuleWithProviders
{
return
{
ngModule
:
ToastModule
,
providers
:
[
{
provide
:
_TOAST_CONFIG_TOKEN
,
useValue
:
{
...
defaultToastConfig
,
...
config
},
},
],
};
}
}
src/app/toast/toast.ref.ts
0 → 100644
View file @
3fb03cff
import
{
OverlayRef
}
from
'
@angular/cdk/overlay
'
;
export
class
ToastRef
{
constructor
(
private
readonly
overlay
:
OverlayRef
)
{
}
close
()
{
this
.
overlay
.
dispose
();
}
isVisible
()
{
return
this
.
overlay
&&
this
.
overlay
.
overlayElement
;
}
getPosition
()
{
return
this
.
overlay
.
overlayElement
.
getBoundingClientRect
();
}
}
src/app/toast/toast.service.ts
0 → 100644
View file @
3fb03cff
import
{
Injectable
,
Injector
,
Inject
}
from
'
@angular/core
'
;
import
{
Overlay
,
OverlayRef
}
from
'
@angular/cdk/overlay
'
;
import
{
ComponentPortal
,
PortalInjector
}
from
'
@angular/cdk/portal
'
;
import
{
ToastComponent
}
from
'
./toast.component
'
;
import
{
ToastData
,
_TOAST_CONFIG_TOKEN
,
MyToastConfig
,
defaultToastConfig
}
from
'
./toast.config
'
;
import
{
ToastRef
}
from
'
./toast.ref
'
;
@
Injectable
({
providedIn
:
'
root
'
})
export
class
ToastService
{
private
lastToast
:
ToastRef
;
constructor
(
private
overlay
:
Overlay
,
private
parentInjector
:
Injector
,
@
Inject
(
_TOAST_CONFIG_TOKEN
)
private
toastConfig
:
MyToastConfig
,
)
{
// console.log(parentInjector, this.toastConfig);
// somehow empty injection of the config... maybe issue with carbon?
this
.
toastConfig
=
{...
defaultToastConfig
,
...
this
.
toastConfig
};
}
show
(
data
:
ToastData
)
{
const
positionStrategy
=
this
.
getPositionStrategy
();
const
overlayRef
=
this
.
overlay
.
create
({
positionStrategy
});
const
toastRef
=
new
ToastRef
(
overlayRef
);
this
.
lastToast
=
toastRef
;
const
injector
=
this
.
getInjector
(
data
,
toastRef
,
this
.
parentInjector
);
const
toastPortal
=
new
ComponentPortal
(
ToastComponent
,
null
,
injector
);
overlayRef
.
attach
(
toastPortal
);
return
toastRef
;
}
getPositionStrategy
()
{
return
this
.
overlay
.
position
()
.
global
()
.
top
(
this
.
getPosition
())
.
right
(
this
.
toastConfig
.
position
.
right
+
'
px
'
);
}
getPosition
()
{
const
lastToastIsVisible
=
this
.
lastToast
&&
this
.
lastToast
.
isVisible
();
const
position
=
lastToastIsVisible
?
this
.
lastToast
.
getPosition
().
bottom
:
this
.
toastConfig
.
position
.
top
;
return
position
+
'
px
'
;
}
getInjector
(
data
:
ToastData
,
toastRef
:
ToastRef
,
parentInjector
:
Injector
)
{
const
tokens
=
new
WeakMap
();
tokens
.
set
(
ToastData
,
data
);
tokens
.
set
(
ToastRef
,
toastRef
);
return
new
PortalInjector
(
parentInjector
,
tokens
);
}
}
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment