added athena health client.
fixed header. added a logout/signout function.
This commit is contained in:
parent
a2b77e6182
commit
564fee9e90
|
@ -7,6 +7,7 @@ const (
|
||||||
SourceTypeManual SourceType = "manual"
|
SourceTypeManual SourceType = "manual"
|
||||||
|
|
||||||
SourceTypeAetna SourceType = "aetna"
|
SourceTypeAetna SourceType = "aetna"
|
||||||
|
SourceTypeAthena SourceType = "athena"
|
||||||
SourceTypeAnthem SourceType = "anthem"
|
SourceTypeAnthem SourceType = "anthem"
|
||||||
SourceTypeCedarSinai SourceType = "cedarssinai"
|
SourceTypeCedarSinai SourceType = "cedarssinai"
|
||||||
SourceTypeCerner SourceType = "cerner"
|
SourceTypeCerner SourceType = "cerner"
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/fastenhealth/fastenhealth-onprem/backend/pkg"
|
"github.com/fastenhealth/fastenhealth-onprem/backend/pkg"
|
||||||
"github.com/fastenhealth/fastenhealth-onprem/backend/pkg/config"
|
"github.com/fastenhealth/fastenhealth-onprem/backend/pkg/config"
|
||||||
"github.com/fastenhealth/fastenhealth-onprem/backend/pkg/hub/internal/fhir/aetna"
|
"github.com/fastenhealth/fastenhealth-onprem/backend/pkg/hub/internal/fhir/aetna"
|
||||||
|
"github.com/fastenhealth/fastenhealth-onprem/backend/pkg/hub/internal/fhir/athena"
|
||||||
"github.com/fastenhealth/fastenhealth-onprem/backend/pkg/hub/internal/fhir/base"
|
"github.com/fastenhealth/fastenhealth-onprem/backend/pkg/hub/internal/fhir/base"
|
||||||
"github.com/fastenhealth/fastenhealth-onprem/backend/pkg/hub/internal/fhir/cerner"
|
"github.com/fastenhealth/fastenhealth-onprem/backend/pkg/hub/internal/fhir/cerner"
|
||||||
"github.com/fastenhealth/fastenhealth-onprem/backend/pkg/hub/internal/fhir/cigna"
|
"github.com/fastenhealth/fastenhealth-onprem/backend/pkg/hub/internal/fhir/cigna"
|
||||||
|
@ -25,6 +26,8 @@ func NewClient(sourceType pkg.SourceType, ctx context.Context, appConfig config.
|
||||||
switch sourceType {
|
switch sourceType {
|
||||||
case pkg.SourceTypeAetna:
|
case pkg.SourceTypeAetna:
|
||||||
sourceClient, updatedSource, err = aetna.NewClient(ctx, appConfig, globalLogger, credentials, testHttpClient...)
|
sourceClient, updatedSource, err = aetna.NewClient(ctx, appConfig, globalLogger, credentials, testHttpClient...)
|
||||||
|
case pkg.SourceTypeAthena:
|
||||||
|
sourceClient, updatedSource, err = athena.NewClient(ctx, appConfig, globalLogger, credentials, testHttpClient...)
|
||||||
case pkg.SourceTypeAnthem:
|
case pkg.SourceTypeAnthem:
|
||||||
sourceClient, updatedSource, err = cigna.NewClient(ctx, appConfig, globalLogger, credentials, testHttpClient...)
|
sourceClient, updatedSource, err = cigna.NewClient(ctx, appConfig, globalLogger, credentials, testHttpClient...)
|
||||||
case pkg.SourceTypeCerner:
|
case pkg.SourceTypeCerner:
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
package athena
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"github.com/fastenhealth/fastenhealth-onprem/backend/pkg/config"
|
||||||
|
"github.com/fastenhealth/fastenhealth-onprem/backend/pkg/database"
|
||||||
|
"github.com/fastenhealth/fastenhealth-onprem/backend/pkg/hub/internal/fhir/base"
|
||||||
|
"github.com/fastenhealth/fastenhealth-onprem/backend/pkg/models"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AthenaClient struct {
|
||||||
|
*base.FHIR401Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewClient(ctx context.Context, appConfig config.Interface, globalLogger logrus.FieldLogger, source models.Source, testHttpClient ...*http.Client) (base.Client, *models.Source, error) {
|
||||||
|
baseClient, updatedSource, err := base.NewFHIR401Client(ctx, appConfig, globalLogger, source, testHttpClient...)
|
||||||
|
return AthenaClient{
|
||||||
|
baseClient,
|
||||||
|
}, updatedSource, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c AthenaClient) SyncAll(db database.DatabaseRepository) error {
|
||||||
|
|
||||||
|
supportedResources := []string{
|
||||||
|
"AllergyIntolerance",
|
||||||
|
"CarePlan",
|
||||||
|
"CareTeam",
|
||||||
|
"Condition",
|
||||||
|
"Device",
|
||||||
|
"DiagnosticReport",
|
||||||
|
"DocumentReference",
|
||||||
|
"Encounter",
|
||||||
|
"Goal",
|
||||||
|
"Immunization",
|
||||||
|
"Location",
|
||||||
|
"Medication",
|
||||||
|
"MedicationRequest",
|
||||||
|
"Observation",
|
||||||
|
"Organization",
|
||||||
|
"Patient",
|
||||||
|
"Practitioner",
|
||||||
|
"Procedure",
|
||||||
|
"Provenance",
|
||||||
|
}
|
||||||
|
for _, resourceType := range supportedResources {
|
||||||
|
bundle, err := c.GetResourceBundle(fmt.Sprintf("%s?patient=%s", resourceType, c.Source.PatientId))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
wrappedResourceModels, err := c.ProcessBundle(bundle)
|
||||||
|
if err != nil {
|
||||||
|
c.Logger.Infof("An error occurred while processing %s bundle %s", resourceType, c.Source.PatientId)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
//todo, create the resources in dependency order
|
||||||
|
|
||||||
|
for _, apiModel := range wrappedResourceModels {
|
||||||
|
err = db.UpsertResource(context.Background(), apiModel)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
|
@ -13,6 +13,7 @@ func GetMetadataSource(c *gin.Context) {
|
||||||
string(pkg.SourceTypeLogica): {Display: "Logica (Sandbox)", SourceType: pkg.SourceTypeLogica, Category: []string{"Sandbox"}, Supported: true},
|
string(pkg.SourceTypeLogica): {Display: "Logica (Sandbox)", SourceType: pkg.SourceTypeLogica, Category: []string{"Sandbox"}, Supported: true},
|
||||||
string(pkg.SourceTypeEpic): {Display: "Epic (Sandbox)", SourceType: pkg.SourceTypeEpic, Category: []string{"Sandbox"}, Supported: true},
|
string(pkg.SourceTypeEpic): {Display: "Epic (Sandbox)", SourceType: pkg.SourceTypeEpic, Category: []string{"Sandbox"}, Supported: true},
|
||||||
string(pkg.SourceTypeCerner): {Display: "Cerner (Sandbox)", SourceType: pkg.SourceTypeCerner, Category: []string{"Sandbox"}, Supported: true},
|
string(pkg.SourceTypeCerner): {Display: "Cerner (Sandbox)", SourceType: pkg.SourceTypeCerner, Category: []string{"Sandbox"}, Supported: true},
|
||||||
|
string(pkg.SourceTypeAthena): {Display: "Athena (Sandbox)", SourceType: pkg.SourceTypeAthena, Category: []string{"Sandbox"}, Supported: true},
|
||||||
|
|
||||||
// enabled
|
// enabled
|
||||||
string(pkg.SourceTypeAetna): {Display: "Aetna", SourceType: pkg.SourceTypeAetna, Category: []string{"Insurance"}, Supported: true},
|
string(pkg.SourceTypeAetna): {Display: "Aetna", SourceType: pkg.SourceTypeAetna, Category: []string{"Insurance"}, Supported: true},
|
||||||
|
|
|
@ -35,24 +35,8 @@ func CreateSource(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// after creating the source, we should do a bulk import
|
// after creating the source, we should do a bulk import
|
||||||
sourceClient, updatedSource, err := hub.NewClient(sourceCred.SourceType, c, nil, logger, sourceCred)
|
err = syncSourceResources(c, logger, databaseRepo, sourceCred)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Errorln("An error occurred while initializing hub client using source credential", err)
|
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"success": false})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if updatedSource != nil {
|
|
||||||
err := databaseRepo.CreateSource(c, updatedSource)
|
|
||||||
if err != nil {
|
|
||||||
logger.Errorln("An error occurred while updating source credential", err)
|
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"success": false})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = sourceClient.SyncAll(databaseRepo)
|
|
||||||
if err != nil {
|
|
||||||
logger.Errorln("An error occurred while bulk import of resources from source", err)
|
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"success": false})
|
c.JSON(http.StatusInternalServerError, gin.H{"success": false})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -60,6 +44,28 @@ func CreateSource(c *gin.Context) {
|
||||||
c.JSON(http.StatusOK, gin.H{"success": true, "data": sourceCred})
|
c.JSON(http.StatusOK, gin.H{"success": true, "data": sourceCred})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SourceSync(c *gin.Context) {
|
||||||
|
logger := c.MustGet("LOGGER").(*logrus.Entry)
|
||||||
|
databaseRepo := c.MustGet("REPOSITORY").(database.DatabaseRepository)
|
||||||
|
|
||||||
|
logger.Infof("Get Source Credentials: %v", c.Param("sourceId"))
|
||||||
|
|
||||||
|
sourceCred, err := databaseRepo.GetSource(c, c.Param("sourceId"))
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorln("An error occurred while retrieving source credential", err)
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"success": false})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// after creating the source, we should do a bulk import
|
||||||
|
err = syncSourceResources(c, logger, databaseRepo, *sourceCred)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"success": false})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, gin.H{"success": true, "data": sourceCred})
|
||||||
|
}
|
||||||
|
|
||||||
func CreateManualSource(c *gin.Context) {
|
func CreateManualSource(c *gin.Context) {
|
||||||
logger := c.MustGet("LOGGER").(*logrus.Entry)
|
logger := c.MustGet("LOGGER").(*logrus.Entry)
|
||||||
databaseRepo := c.MustGet("REPOSITORY").(database.DatabaseRepository)
|
databaseRepo := c.MustGet("REPOSITORY").(database.DatabaseRepository)
|
||||||
|
@ -200,3 +206,27 @@ func RawRequestSource(c *gin.Context) {
|
||||||
}
|
}
|
||||||
c.JSON(http.StatusOK, gin.H{"success": true, "data": resp})
|
c.JSON(http.StatusOK, gin.H{"success": true, "data": resp})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////// private functions
|
||||||
|
func syncSourceResources(c *gin.Context, logger *logrus.Entry, databaseRepo database.DatabaseRepository, sourceCred models.Source) error {
|
||||||
|
// after creating the source, we should do a bulk import
|
||||||
|
sourceClient, updatedSource, err := hub.NewClient(sourceCred.SourceType, c, nil, logger, sourceCred)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorln("An error occurred while initializing hub client using source credential", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if updatedSource != nil {
|
||||||
|
err := databaseRepo.CreateSource(c, updatedSource)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorln("An error occurred while updating source credential", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = sourceClient.SyncAll(databaseRepo)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorln("An error occurred while bulk import of resources from source", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@ func (ae *AppEngine) Setup(logger *logrus.Entry) *gin.Engine {
|
||||||
secure.POST("/source/manual", handler.CreateManualSource)
|
secure.POST("/source/manual", handler.CreateManualSource)
|
||||||
secure.GET("/source", handler.ListSource)
|
secure.GET("/source", handler.ListSource)
|
||||||
secure.GET("/source/:sourceId", handler.GetSource)
|
secure.GET("/source/:sourceId", handler.GetSource)
|
||||||
|
secure.POST("/source/:sourceId/sync", handler.SourceSync)
|
||||||
secure.GET("/source/:sourceId/summary", handler.GetSourceSummary)
|
secure.GET("/source/:sourceId/summary", handler.GetSourceSummary)
|
||||||
secure.GET("/resource/fhir", handler.ListResourceFhir) //
|
secure.GET("/resource/fhir", handler.ListResourceFhir) //
|
||||||
secure.GET("/resource/fhir/:resourceId", handler.GetResourceFhir)
|
secure.GET("/resource/fhir/:resourceId", handler.GetResourceFhir)
|
||||||
|
|
|
@ -65,24 +65,21 @@
|
||||||
</div><!-- dropdown-menu -->
|
</div><!-- dropdown-menu -->
|
||||||
</div><!-- az-header-notification -->
|
</div><!-- az-header-notification -->
|
||||||
<div class="dropdown az-profile-menu" ngbDropdown>
|
<div class="dropdown az-profile-menu" ngbDropdown>
|
||||||
<a class="az-img-user" id="profileDropdown" ngbDropdownToggle><img src="assets/images/img1.jpg" alt="user"></a>
|
<a class="az-img-user" id="profileDropdown" ngbDropdownToggle><img src="assets/logo/logo-text.png" alt="user"></a>
|
||||||
<div class="dropdown-menu" ngbDropdownMenu aria-labelledby="profileDropdown">
|
<div class="dropdown-menu" ngbDropdownMenu aria-labelledby="profileDropdown">
|
||||||
<div class="az-dropdown-header d-sm-none">
|
<div class="az-dropdown-header d-sm-none">
|
||||||
<a class="az-header-arrow" (click)="closeMenu($event)"><i class="icon ion-md-arrow-back"></i></a>
|
<a class="az-header-arrow" (click)="closeMenu($event)"><i class="icon ion-md-arrow-back"></i></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="az-header-profile">
|
<div class="az-header-profile">
|
||||||
<div class="az-img-user">
|
<div class="az-img-user">
|
||||||
<img src="assets/images/img1.jpg" alt="">
|
<img src="assets/logo/logo-text.png" alt="">
|
||||||
</div><!-- az-img-user -->
|
</div><!-- az-img-user -->
|
||||||
<h6>Aziana Pechon</h6>
|
<h6>John Doe</h6>
|
||||||
<span>Premium Member</span>
|
<span>Adminstrator</span>
|
||||||
</div><!-- az-header-profile -->
|
</div><!-- az-header-profile -->
|
||||||
|
|
||||||
<a routerLink="/general-pages/profile" class="dropdown-item"><i class="typcn typcn-user-outline"></i> My Profile</a>
|
|
||||||
<a routerLink="/general-pages/profile" class="dropdown-item"><i class="typcn typcn-edit"></i> Edit Profile</a>
|
|
||||||
<a routerLink="/general-pages/profile" class="dropdown-item"><i class="typcn typcn-time"></i> Activity Logs</a>
|
<a routerLink="/general-pages/profile" class="dropdown-item"><i class="typcn typcn-time"></i> Activity Logs</a>
|
||||||
<a routerLink="/general-pages/profile" class="dropdown-item"><i class="typcn typcn-cog-outline"></i> Account Settings</a>
|
<a (click)="signOut($event)" class="dropdown-item"><i class="typcn typcn-power-outline"></i> Sign Out</a>
|
||||||
<a routerLink="/general-pages/signin" class="dropdown-item"><i class="typcn typcn-power-outline"></i> Sign Out</a>
|
|
||||||
</div><!-- dropdown-menu -->
|
</div><!-- dropdown-menu -->
|
||||||
</div>
|
</div>
|
||||||
</div><!-- az-header-right -->
|
</div><!-- az-header-right -->
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import {FastenApiService} from '../../services/fasten-api.service';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-header',
|
selector: 'app-header',
|
||||||
templateUrl: './header.component.html',
|
templateUrl: './header.component.html',
|
||||||
|
@ -7,7 +8,7 @@ import { Component, OnInit } from '@angular/core';
|
||||||
})
|
})
|
||||||
export class HeaderComponent implements OnInit {
|
export class HeaderComponent implements OnInit {
|
||||||
|
|
||||||
constructor() { }
|
constructor(private fastenApi: FastenApiService, private router: Router) { }
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
}
|
}
|
||||||
|
@ -22,4 +23,8 @@ export class HeaderComponent implements OnInit {
|
||||||
document.querySelector('body').classList.toggle('az-header-menu-show');
|
document.querySelector('body').classList.toggle('az-header-menu-show');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signOut(e) {
|
||||||
|
this.fastenApi.logout()
|
||||||
|
this.router.navigate(['auth/signin']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,9 +76,8 @@ export class ResourceListComponent implements OnInit, OnChanges {
|
||||||
|
|
||||||
getResources(): Observable<ResourceFhir[]>{
|
getResources(): Observable<ResourceFhir[]>{
|
||||||
|
|
||||||
if(!this.resourceListCache[this.resourceListType]){
|
if(this.resourceListType && !this.resourceListCache[this.resourceListType]){
|
||||||
// this resource type list has not been downloaded yet, do so now
|
// this resource type list has not been downloaded yet, do so now
|
||||||
|
|
||||||
return this.fastenApi.getResources(this.resourceListType, this.source.id)
|
return this.fastenApi.getResources(this.resourceListType, this.source.id)
|
||||||
.pipe(map((resourceList: ResourceFhir[]) => {
|
.pipe(map((resourceList: ResourceFhir[]) => {
|
||||||
//cache this response so we can skip the request next time
|
//cache this response so we can skip the request next time
|
||||||
|
@ -86,7 +85,7 @@ export class ResourceListComponent implements OnInit, OnChanges {
|
||||||
return resourceList
|
return resourceList
|
||||||
}))
|
}))
|
||||||
} else {
|
} else {
|
||||||
return of(this.resourceListCache[this.resourceListType])
|
return of(this.resourceListCache[this.resourceListType] || [])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,10 +9,10 @@
|
||||||
<h2 class="az-content-title">Connected Sources</h2>
|
<h2 class="az-content-title">Connected Sources</h2>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div *ngFor="let sourceData of connectedSourceList" (click)="connect($event, sourceData['source_type'])" class="col-sm-3 mg-b-20 px-3">
|
<div *ngFor="let sourceInfo of connectedSourceList" class="col-sm-3 mg-b-20 px-3">
|
||||||
<div class="card h-100 d-flex align-items-center justify-content-center p-3 rounded-0 cursor-pointer">
|
<div class="card h-100 d-flex align-items-center justify-content-center p-3 rounded-0 cursor-pointer">
|
||||||
<div class="card-body">
|
<div (click)="openModal(contentModalRef, sourceInfo)" class="card-body">
|
||||||
<img [src]="'assets/sources/'+sourceData['source_type']+'.png'" alt="client" class="img-fluid">
|
<img [src]="'assets/sources/'+sourceInfo.metadata['source_type']+'.png'" alt="client" class="img-fluid">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -62,3 +62,29 @@
|
||||||
</div><!-- az-content-body -->
|
</div><!-- az-content-body -->
|
||||||
</div><!-- container -->
|
</div><!-- container -->
|
||||||
</div><!-- az-content -->
|
</div><!-- az-content -->
|
||||||
|
|
||||||
|
<ng-template #contentModalRef let-modal>
|
||||||
|
<div class="modal-header">
|
||||||
|
<h4 class="modal-title" id="modal-basic-title">{{modalSourceInfo.metadata["display"]}}</h4>
|
||||||
|
<button type="button" class="btn-close" aria-label="Close" (click)="modal.dismiss('Cross click')">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-body">
|
||||||
|
<h6>Manage Source</h6>
|
||||||
|
<p>Existing connections can be "Synced", "Reconnected" or "Deleted"</p>
|
||||||
|
<ul>
|
||||||
|
<li><p><strong>Sync</strong> - Download all resources from this healthcare provider, storing them securely in Fasten</p></li>
|
||||||
|
<li><p><strong>Reconnect</strong> - If your healthcare connection has expired, you can use this button to reconnect</p></li>
|
||||||
|
<li><p><strong>Delete</strong> - Delete all resources for this healthcare provider. This will ONLY effect data stored in Fasten</p></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button (click)="syncSource(modalSourceInfo.source)" type="button" class="btn btn-indigo">Sync</button>
|
||||||
|
<button type="button" class="btn btn-outline-light">Reconnect</button>
|
||||||
|
<button type="button" class="btn btn-outline-danger">Delete</button>
|
||||||
|
<button type="button" class="btn btn-outline-light">Close</button>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
|
|
@ -11,6 +11,7 @@ import {Observable, of, throwError} from 'rxjs';
|
||||||
import {concatMap, delay, retryWhen} from 'rxjs/operators';
|
import {concatMap, delay, retryWhen} from 'rxjs/operators';
|
||||||
import * as FHIR from "fhirclient"
|
import * as FHIR from "fhirclient"
|
||||||
import {MetadataSource} from '../../models/fasten/metadata-source';
|
import {MetadataSource} from '../../models/fasten/metadata-source';
|
||||||
|
import {NgbModal, ModalDismissReasons} from '@ng-bootstrap/ng-bootstrap';
|
||||||
|
|
||||||
export const retryCount = 24; //wait 2 minutes (5 * 24 = 120)
|
export const retryCount = 24; //wait 2 minutes (5 * 24 = 120)
|
||||||
export const retryWaitMilliSeconds = 5000; //wait 5 seconds
|
export const retryWaitMilliSeconds = 5000; //wait 5 seconds
|
||||||
|
@ -25,16 +26,20 @@ export class MedicalSourcesComponent implements OnInit {
|
||||||
constructor(
|
constructor(
|
||||||
private lighthouseApi: LighthouseService,
|
private lighthouseApi: LighthouseService,
|
||||||
private fastenApi: FastenApiService,
|
private fastenApi: FastenApiService,
|
||||||
|
private modalService: NgbModal,
|
||||||
) { }
|
) { }
|
||||||
status: { [name: string]: string } = {}
|
status: { [name: string]: string } = {}
|
||||||
|
|
||||||
metadataSources: {[name:string]: MetadataSource} = {}
|
metadataSources: {[name:string]: MetadataSource} = {}
|
||||||
|
|
||||||
connectedSourceList = []
|
connectedSourceList:any[] = []
|
||||||
availableSourceList = []
|
availableSourceList:MetadataSource[] = []
|
||||||
|
|
||||||
uploadedFile: File[] = []
|
uploadedFile: File[] = []
|
||||||
|
|
||||||
|
closeResult = '';
|
||||||
|
modalSourceInfo:any = null;
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.fastenApi.getMetadataSources().subscribe((metadataSources: {[name:string]: MetadataSource}) => {
|
this.fastenApi.getMetadataSources().subscribe((metadataSources: {[name:string]: MetadataSource}) => {
|
||||||
this.metadataSources = metadataSources
|
this.metadataSources = metadataSources
|
||||||
|
@ -46,7 +51,7 @@ export class MedicalSourcesComponent implements OnInit {
|
||||||
let isConnected = false
|
let isConnected = false
|
||||||
for(const connectedSource of sourceList){
|
for(const connectedSource of sourceList){
|
||||||
if(connectedSource.source_type == sourceType){
|
if(connectedSource.source_type == sourceType){
|
||||||
this.connectedSourceList.push({"source_type": sourceType, "display": this.metadataSources[sourceType]["display"], "enabled": this.metadataSources[sourceType]["enabled"]})
|
this.connectedSourceList.push({source: connectedSource, metadata: this.metadataSources[sourceType]})
|
||||||
isConnected = true
|
isConnected = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -54,7 +59,7 @@ export class MedicalSourcesComponent implements OnInit {
|
||||||
|
|
||||||
if(!isConnected){
|
if(!isConnected){
|
||||||
//this source has not been found in the connected list, lets add it to the available list.
|
//this source has not been found in the connected list, lets add it to the available list.
|
||||||
this.availableSourceList.push({"source_type": sourceType, "display": this.metadataSources[sourceType]["display"], "enabled": this.metadataSources[sourceType]["enabled"]})
|
this.availableSourceList.push(this.metadataSources[sourceType])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,6 +146,7 @@ export class MedicalSourcesComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
//Create FHIR Client
|
//Create FHIR Client
|
||||||
|
|
||||||
const sourceCredential: Source = {
|
const sourceCredential: Source = {
|
||||||
source_type: sourceType,
|
source_type: sourceType,
|
||||||
oauth_authorization_endpoint: connectData.oauth_authorization_endpoint,
|
oauth_authorization_endpoint: connectData.oauth_authorization_endpoint,
|
||||||
|
@ -156,9 +162,12 @@ export class MedicalSourcesComponent implements OnInit {
|
||||||
access_token: payload.access_token,
|
access_token: payload.access_token,
|
||||||
refresh_token: payload.refresh_token,
|
refresh_token: payload.refresh_token,
|
||||||
id_token: payload.id_token,
|
id_token: payload.id_token,
|
||||||
expires_at: getAccessTokenExpiration(payload, new BrowserAdapter()),
|
|
||||||
code_challenge: codeChallenge,
|
code_challenge: codeChallenge,
|
||||||
code_verifier: codeVerifier,
|
code_verifier: codeVerifier,
|
||||||
|
|
||||||
|
// @ts-ignore - in some cases the getAccessTokenExpiration is a string, which cases failures to store Source in db.
|
||||||
|
expires_at: parseInt(getAccessTokenExpiration(payload, new BrowserAdapter())),
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.fastenApi.createSource(sourceCredential).subscribe(
|
await this.fastenApi.createSource(sourceCredential).subscribe(
|
||||||
|
@ -189,13 +198,54 @@ export class MedicalSourcesComponent implements OnInit {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
event.origin);
|
event.origin);
|
||||||
}, 5000);
|
}, 5000);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uploadSourceBundle(event) {
|
||||||
|
this.uploadedFile = [event.addedFiles[0]]
|
||||||
|
this.fastenApi.createManualSource(event.addedFiles[0]).subscribe(
|
||||||
|
(respData) => {
|
||||||
|
console.log("source manual source create response:", respData)
|
||||||
|
},
|
||||||
|
(err) => {console.log(err)},
|
||||||
|
() => {
|
||||||
|
this.uploadedFile = []
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
openModal(contentModalRef, sourceInfo: any) {
|
||||||
|
this.modalSourceInfo = sourceInfo
|
||||||
|
let modalSourceInfo = this.modalSourceInfo
|
||||||
|
this.modalService.open(contentModalRef, {ariaLabelledBy: 'modal-basic-title'}).result.then((result) => {
|
||||||
|
modalSourceInfo = null
|
||||||
|
this.closeResult = `Closed with: ${result}`;
|
||||||
|
}, (reason) => {
|
||||||
|
modalSourceInfo = null
|
||||||
|
this.closeResult = `Dismissed ${this.getDismissReason(reason)}`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
waitForClaimOrTimeout(sourceType: string, state: string): Observable<AuthorizeClaim> {
|
syncSource(source: Source){
|
||||||
|
this.modalService.dismissAll()
|
||||||
|
this.fastenApi.syncSource(source.id).subscribe(
|
||||||
|
(respData) => {
|
||||||
|
console.log("source sync response:", respData)
|
||||||
|
},
|
||||||
|
(err) => {console.log(err)},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private getDismissReason(reason: any): string {
|
||||||
|
if (reason === ModalDismissReasons.ESC) {
|
||||||
|
return 'by pressing ESC';
|
||||||
|
} else if (reason === ModalDismissReasons.BACKDROP_CLICK) {
|
||||||
|
return 'by clicking on a backdrop';
|
||||||
|
} else {
|
||||||
|
return `with: ${reason}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private waitForClaimOrTimeout(sourceType: string, state: string): Observable<AuthorizeClaim> {
|
||||||
return this.lighthouseApi.getSourceAuthorizeClaim(sourceType, state).pipe(
|
return this.lighthouseApi.getSourceAuthorizeClaim(sourceType, state).pipe(
|
||||||
retryWhen(error =>
|
retryWhen(error =>
|
||||||
error.pipe(
|
error.pipe(
|
||||||
|
@ -211,21 +261,7 @@ export class MedicalSourcesComponent implements OnInit {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private uuidV4(){
|
||||||
uploadSourceBundle(event) {
|
|
||||||
this.uploadedFile = [event.addedFiles[0]]
|
|
||||||
this.fastenApi.createManualSource(event.addedFiles[0]).subscribe(
|
|
||||||
(respData) => {
|
|
||||||
console.log("source manual source create response:", respData)
|
|
||||||
},
|
|
||||||
(err) => {console.log(err)},
|
|
||||||
() => {
|
|
||||||
this.uploadedFile = []
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
uuidV4(){
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
|
return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
|
||||||
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
|
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
|
||||||
|
|
|
@ -132,6 +132,16 @@ export class FastenApiService {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
syncSource(sourceId: string): Observable<any> {
|
||||||
|
return this._httpClient.post<any>(`${this.getBasePath()}/api/secure/source/${sourceId}/sync`, {})
|
||||||
|
.pipe(
|
||||||
|
map((response: ResponseWrapper) => {
|
||||||
|
console.log("SOURCE RESPONSE", response)
|
||||||
|
return response.data
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
getResources(sourceResourceType?: string, sourceID?: string): Observable<ResourceFhir[]> {
|
getResources(sourceResourceType?: string, sourceID?: string): Observable<ResourceFhir[]> {
|
||||||
let queryParams = {}
|
let queryParams = {}
|
||||||
if(sourceResourceType){
|
if(sourceResourceType){
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 6.9 KiB |
Binary file not shown.
After Width: | Height: | Size: 9.4 KiB |
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
|
@ -1,6 +1,439 @@
|
||||||
/* ###### 4.7 Modal ###### */
|
/* ###### 4.7 Modal ###### */
|
||||||
|
|
||||||
// MODAL EFFECTS
|
// MODAL EFFECTS
|
||||||
.modal {
|
|
||||||
|
|
||||||
}
|
.modal {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 1055;
|
||||||
|
display: none;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
outline: 0; }
|
||||||
|
|
||||||
|
.modal-dialog {
|
||||||
|
position: relative;
|
||||||
|
width: auto;
|
||||||
|
margin: 0.5rem;
|
||||||
|
pointer-events: none; }
|
||||||
|
.modal.fade .modal-dialog {
|
||||||
|
transition: transform 0.3s ease-out;
|
||||||
|
transform: translate(0, -50px); }
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
.modal.fade .modal-dialog {
|
||||||
|
transition: none; } }
|
||||||
|
.modal.show .modal-dialog {
|
||||||
|
transform: none; }
|
||||||
|
.modal.modal-static .modal-dialog {
|
||||||
|
transform: scale(1.02); }
|
||||||
|
|
||||||
|
.modal-dialog-scrollable {
|
||||||
|
height: calc(100% - 1rem); }
|
||||||
|
.modal-dialog-scrollable .modal-content {
|
||||||
|
max-height: 100%;
|
||||||
|
overflow: hidden; }
|
||||||
|
.modal-dialog-scrollable .modal-body {
|
||||||
|
overflow-y: auto; }
|
||||||
|
|
||||||
|
.modal-dialog-centered {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
min-height: calc(100% - 1rem); }
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
pointer-events: auto;
|
||||||
|
background-color: #fff;
|
||||||
|
background-clip: padding-box;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.2);
|
||||||
|
border-radius: 0.3rem;
|
||||||
|
outline: 0; }
|
||||||
|
|
||||||
|
.modal-backdrop {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 1050;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
background-color: #000; }
|
||||||
|
.modal-backdrop.fade {
|
||||||
|
opacity: 0; }
|
||||||
|
.modal-backdrop.show {
|
||||||
|
opacity: 0.5; }
|
||||||
|
|
||||||
|
.modal-header {
|
||||||
|
display: flex;
|
||||||
|
flex-shrink: 0;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 1rem 1rem;
|
||||||
|
border-bottom: 1px solid #cdd4e0;
|
||||||
|
border-top-left-radius: calc(0.3rem - 1px);
|
||||||
|
border-top-right-radius: calc(0.3rem - 1px); }
|
||||||
|
.modal-header .btn-close {
|
||||||
|
padding: 0.5rem 0.5rem;
|
||||||
|
margin: -0.5rem -0.5rem -0.5rem auto; }
|
||||||
|
|
||||||
|
.modal-title {
|
||||||
|
margin-bottom: 0;
|
||||||
|
line-height: 1.5; }
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
position: relative;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
padding: 1rem; }
|
||||||
|
|
||||||
|
.modal-footer {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
flex-shrink: 0;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
padding: 0.75rem;
|
||||||
|
border-top: 1px solid #cdd4e0;
|
||||||
|
border-bottom-right-radius: calc(0.3rem - 1px);
|
||||||
|
border-bottom-left-radius: calc(0.3rem - 1px); }
|
||||||
|
.modal-footer > * {
|
||||||
|
margin: 0.25rem; }
|
||||||
|
|
||||||
|
@media (min-width: 576px) {
|
||||||
|
.modal-dialog {
|
||||||
|
max-width: 500px;
|
||||||
|
margin: 1.75rem auto; }
|
||||||
|
.modal-dialog-scrollable {
|
||||||
|
height: calc(100% - 3.5rem); }
|
||||||
|
.modal-dialog-centered {
|
||||||
|
min-height: calc(100% - 3.5rem); }
|
||||||
|
.modal-sm {
|
||||||
|
max-width: 300px; } }
|
||||||
|
|
||||||
|
@media (min-width: 992px) {
|
||||||
|
.modal-lg,
|
||||||
|
.modal-xl {
|
||||||
|
max-width: 800px; } }
|
||||||
|
|
||||||
|
@media (min-width: 1200px) {
|
||||||
|
.modal-xl {
|
||||||
|
max-width: 1140px; } }
|
||||||
|
|
||||||
|
.modal-fullscreen {
|
||||||
|
width: 100vw;
|
||||||
|
max-width: none;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0; }
|
||||||
|
.modal-fullscreen .modal-content {
|
||||||
|
height: 100%;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 0; }
|
||||||
|
.modal-fullscreen .modal-header {
|
||||||
|
border-radius: 0; }
|
||||||
|
.modal-fullscreen .modal-body {
|
||||||
|
overflow-y: auto; }
|
||||||
|
.modal-fullscreen .modal-footer {
|
||||||
|
border-radius: 0; }
|
||||||
|
|
||||||
|
@media (max-width: 575.98px) {
|
||||||
|
.modal-fullscreen-sm-down {
|
||||||
|
width: 100vw;
|
||||||
|
max-width: none;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0; }
|
||||||
|
.modal-fullscreen-sm-down .modal-content {
|
||||||
|
height: 100%;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 0; }
|
||||||
|
.modal-fullscreen-sm-down .modal-header {
|
||||||
|
border-radius: 0; }
|
||||||
|
.modal-fullscreen-sm-down .modal-body {
|
||||||
|
overflow-y: auto; }
|
||||||
|
.modal-fullscreen-sm-down .modal-footer {
|
||||||
|
border-radius: 0; } }
|
||||||
|
|
||||||
|
@media (max-width: 767.98px) {
|
||||||
|
.modal-fullscreen-md-down {
|
||||||
|
width: 100vw;
|
||||||
|
max-width: none;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0; }
|
||||||
|
.modal-fullscreen-md-down .modal-content {
|
||||||
|
height: 100%;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 0; }
|
||||||
|
.modal-fullscreen-md-down .modal-header {
|
||||||
|
border-radius: 0; }
|
||||||
|
.modal-fullscreen-md-down .modal-body {
|
||||||
|
overflow-y: auto; }
|
||||||
|
.modal-fullscreen-md-down .modal-footer {
|
||||||
|
border-radius: 0; } }
|
||||||
|
|
||||||
|
@media (max-width: 991.98px) {
|
||||||
|
.modal-fullscreen-lg-down {
|
||||||
|
width: 100vw;
|
||||||
|
max-width: none;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0; }
|
||||||
|
.modal-fullscreen-lg-down .modal-content {
|
||||||
|
height: 100%;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 0; }
|
||||||
|
.modal-fullscreen-lg-down .modal-header {
|
||||||
|
border-radius: 0; }
|
||||||
|
.modal-fullscreen-lg-down .modal-body {
|
||||||
|
overflow-y: auto; }
|
||||||
|
.modal-fullscreen-lg-down .modal-footer {
|
||||||
|
border-radius: 0; } }
|
||||||
|
|
||||||
|
@media (max-width: 1199.98px) {
|
||||||
|
.modal-fullscreen-xl-down {
|
||||||
|
width: 100vw;
|
||||||
|
max-width: none;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0; }
|
||||||
|
.modal-fullscreen-xl-down .modal-content {
|
||||||
|
height: 100%;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 0; }
|
||||||
|
.modal-fullscreen-xl-down .modal-header {
|
||||||
|
border-radius: 0; }
|
||||||
|
.modal-fullscreen-xl-down .modal-body {
|
||||||
|
overflow-y: auto; }
|
||||||
|
.modal-fullscreen-xl-down .modal-footer {
|
||||||
|
border-radius: 0; } }
|
||||||
|
|
||||||
|
@media (max-width: 1399.98px) {
|
||||||
|
.modal-fullscreen-xxl-down {
|
||||||
|
width: 100vw;
|
||||||
|
max-width: none;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0; }
|
||||||
|
.modal-fullscreen-xxl-down .modal-content {
|
||||||
|
height: 100%;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 0; }
|
||||||
|
.modal-fullscreen-xxl-down .modal-header {
|
||||||
|
border-radius: 0; }
|
||||||
|
.modal-fullscreen-xxl-down .modal-body {
|
||||||
|
overflow-y: auto; }
|
||||||
|
.modal-fullscreen-xxl-down .modal-footer {
|
||||||
|
border-radius: 0; } }
|
||||||
|
|
||||||
|
/* ###### 3.12 Modal ###### */
|
||||||
|
.modal-backdrop {
|
||||||
|
background-color: #0c1019; }
|
||||||
|
.modal-backdrop.show {
|
||||||
|
opacity: .8; }
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
border-radius: 0;
|
||||||
|
border-width: 0; }
|
||||||
|
.modal-content .close {
|
||||||
|
font-size: 28px;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
line-height: .5;
|
||||||
|
border: none;
|
||||||
|
box-shadow: none;
|
||||||
|
background: transparent;
|
||||||
|
float: right; }
|
||||||
|
|
||||||
|
.modal-header {
|
||||||
|
align-items: center;
|
||||||
|
padding: 15px; }
|
||||||
|
@media (min-width: 576px) {
|
||||||
|
.modal-header {
|
||||||
|
padding: 15px 20px; } }
|
||||||
|
@media (min-width: 992px) {
|
||||||
|
.modal-header {
|
||||||
|
padding: 20px; } }
|
||||||
|
@media (min-width: 1200px) {
|
||||||
|
.modal-header {
|
||||||
|
padding: 20px 25px; } }
|
||||||
|
.modal-header .modal-title {
|
||||||
|
margin-bottom: 0; }
|
||||||
|
|
||||||
|
.modal-title {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #1c273c;
|
||||||
|
line-height: 1; }
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
padding: 25px; }
|
||||||
|
|
||||||
|
|
||||||
|
/* ###### 4.7 Modal ###### */
|
||||||
|
.modal.animated .modal-dialog {
|
||||||
|
transform: translate(0, 0); }
|
||||||
|
|
||||||
|
.modal.effect-scale .modal-dialog {
|
||||||
|
transform: scale(0.7);
|
||||||
|
opacity: 0;
|
||||||
|
transition: all 0.3s; }
|
||||||
|
|
||||||
|
.modal.effect-scale.show .modal-dialog {
|
||||||
|
transform: scale(1);
|
||||||
|
opacity: 1; }
|
||||||
|
|
||||||
|
.modal.effect-slide-in-right .modal-dialog {
|
||||||
|
transform: translateX(20%);
|
||||||
|
opacity: 0;
|
||||||
|
transition: all 0.3s cubic-bezier(0.25, 0.5, 0.5, 0.9); }
|
||||||
|
|
||||||
|
.modal.effect-slide-in-right.show .modal-dialog {
|
||||||
|
transform: translateX(0);
|
||||||
|
opacity: 1; }
|
||||||
|
|
||||||
|
.modal.effect-slide-in-bottom .modal-dialog {
|
||||||
|
transform: translateY(20%);
|
||||||
|
opacity: 0;
|
||||||
|
transition: all 0.3s; }
|
||||||
|
|
||||||
|
.modal.effect-slide-in-bottom.show .modal-dialog {
|
||||||
|
transform: translateY(0);
|
||||||
|
opacity: 1; }
|
||||||
|
|
||||||
|
.modal.effect-newspaper .modal-dialog {
|
||||||
|
transform: scale(0) rotate(720deg);
|
||||||
|
opacity: 0; }
|
||||||
|
|
||||||
|
.modal.effect-newspaper.show ~ .modal-backdrop,
|
||||||
|
.modal.effect-newspaper .modal-dialog {
|
||||||
|
transition: all 0.5s; }
|
||||||
|
|
||||||
|
.modal.effect-newspaper.show .modal-dialog {
|
||||||
|
transform: scale(1) rotate(0deg);
|
||||||
|
opacity: 1; }
|
||||||
|
|
||||||
|
.modal.effect-fall {
|
||||||
|
-webkit-perspective: 1300px;
|
||||||
|
-moz-perspective: 1300px;
|
||||||
|
perspective: 1300px; }
|
||||||
|
.modal.effect-fall .modal-dialog {
|
||||||
|
-moz-transform-style: preserve-3d;
|
||||||
|
transform-style: preserve-3d;
|
||||||
|
transform: translateZ(600px) rotateX(20deg);
|
||||||
|
opacity: 0; }
|
||||||
|
.modal.effect-fall.show .modal-dialog {
|
||||||
|
transition: all 0.3s ease-in;
|
||||||
|
transform: translateZ(0px) rotateX(0deg);
|
||||||
|
opacity: 1; }
|
||||||
|
|
||||||
|
.modal.effect-flip-horizontal {
|
||||||
|
perspective: 1300px; }
|
||||||
|
.modal.effect-flip-horizontal .modal-dialog {
|
||||||
|
-moz-transform-style: preserve-3d;
|
||||||
|
transform-style: preserve-3d;
|
||||||
|
transform: rotateY(-70deg);
|
||||||
|
transition: all 0.3s;
|
||||||
|
opacity: 0; }
|
||||||
|
.modal.effect-flip-horizontal.show .modal-dialog {
|
||||||
|
transform: rotateY(0deg);
|
||||||
|
opacity: 1; }
|
||||||
|
|
||||||
|
.modal.effect-flip-vertical {
|
||||||
|
perspective: 1300px; }
|
||||||
|
.modal.effect-flip-vertical .modal-dialog {
|
||||||
|
-moz-transform-style: preserve-3d;
|
||||||
|
transform-style: preserve-3d;
|
||||||
|
transform: rotateX(-70deg);
|
||||||
|
transition: all 0.3s;
|
||||||
|
opacity: 0; }
|
||||||
|
.modal.effect-flip-vertical.show .modal-dialog {
|
||||||
|
transform: rotateX(0deg);
|
||||||
|
opacity: 1; }
|
||||||
|
|
||||||
|
.modal.effect-super-scaled .modal-dialog {
|
||||||
|
transform: scale(2);
|
||||||
|
opacity: 0;
|
||||||
|
transition: all 0.3s; }
|
||||||
|
|
||||||
|
.modal.effect-super-scaled.show .modal-dialog {
|
||||||
|
transform: scale(1);
|
||||||
|
opacity: 1; }
|
||||||
|
|
||||||
|
.modal.effect-sign {
|
||||||
|
perspective: 1300px; }
|
||||||
|
.modal.effect-sign .modal-dialog {
|
||||||
|
-moz-transform-style: preserve-3d;
|
||||||
|
transform-style: preserve-3d;
|
||||||
|
transform: rotateX(-60deg);
|
||||||
|
transform-origin: 50% 0;
|
||||||
|
opacity: 0;
|
||||||
|
transition: all 0.3s; }
|
||||||
|
.modal.effect-sign.show .modal-dialog {
|
||||||
|
transform: rotateX(0deg);
|
||||||
|
opacity: 1; }
|
||||||
|
|
||||||
|
.modal.effect-rotate-bottom {
|
||||||
|
perspective: 1300px; }
|
||||||
|
.modal.effect-rotate-bottom .modal-dialog {
|
||||||
|
-moz-transform-style: preserve-3d;
|
||||||
|
transform-style: preserve-3d;
|
||||||
|
transform: translateY(100%) rotateX(90deg);
|
||||||
|
transform-origin: 0 100%;
|
||||||
|
opacity: 0;
|
||||||
|
transition: all 0.3s ease-out; }
|
||||||
|
.modal.effect-rotate-bottom.show .modal-dialog {
|
||||||
|
transform: translateY(0%) rotateX(0deg);
|
||||||
|
opacity: 1; }
|
||||||
|
|
||||||
|
.modal.effect-rotate-left {
|
||||||
|
perspective: 1300px; }
|
||||||
|
.modal.effect-rotate-left .modal-dialog {
|
||||||
|
-moz-transform-style: preserve-3d;
|
||||||
|
transform-style: preserve-3d;
|
||||||
|
transform: translateZ(100px) translateX(-30%) rotateY(90deg);
|
||||||
|
transform-origin: 0 100%;
|
||||||
|
opacity: 0;
|
||||||
|
transition: all 0.3s; }
|
||||||
|
.modal.effect-rotate-left.show .modal-dialog {
|
||||||
|
transform: translateZ(0px) translateX(0%) rotateY(0deg);
|
||||||
|
opacity: 1; }
|
||||||
|
|
||||||
|
.modal.effect-just-me .modal-dialog {
|
||||||
|
transform: scale(0.8);
|
||||||
|
opacity: 0;
|
||||||
|
transition: all 0.3s; }
|
||||||
|
|
||||||
|
.modal.effect-just-me .modal-content {
|
||||||
|
background-color: transparent; }
|
||||||
|
|
||||||
|
.modal.effect-just-me .close {
|
||||||
|
text-shadow: none;
|
||||||
|
color: #fff; }
|
||||||
|
|
||||||
|
.modal.effect-just-me .modal-header {
|
||||||
|
background-color: transparent;
|
||||||
|
border-bottom-color: rgba(255, 255, 255, 0.1);
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0; }
|
||||||
|
.modal.effect-just-me .modal-header h6, .modal.effect-just-me .modal-header .h6 {
|
||||||
|
color: #fff;
|
||||||
|
font-weight: 500; }
|
||||||
|
|
||||||
|
.modal.effect-just-me .modal-body {
|
||||||
|
color: rgba(255, 255, 255, 0.8);
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0; }
|
||||||
|
.modal.effect-just-me .modal-body h6, .modal.effect-just-me .modal-body .h6 {
|
||||||
|
color: #fff; }
|
||||||
|
|
||||||
|
.modal.effect-just-me .modal-footer {
|
||||||
|
background-color: transparent;
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0;
|
||||||
|
border-top-color: rgba(255, 255, 255, 0.1); }
|
||||||
|
|
||||||
|
.modal.effect-just-me.show ~ .modal-backdrop {
|
||||||
|
opacity: .96; }
|
||||||
|
|
||||||
|
.modal.effect-just-me.show .modal-dialog {
|
||||||
|
transform: scale(1);
|
||||||
|
opacity: 1; }
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 4.0 KiB |
|
@ -143,6 +143,7 @@
|
||||||
@import "./assets/scss/custom/variables";
|
@import "./assets/scss/custom/variables";
|
||||||
@import "./assets/scss/custom/mixins";
|
@import "./assets/scss/custom/mixins";
|
||||||
|
|
||||||
|
|
||||||
/* ########## BOOTSTRAP OVERRIDES ########## */
|
/* ########## BOOTSTRAP OVERRIDES ########## */
|
||||||
@import "./assets/scss/bootstrap/accordion";
|
@import "./assets/scss/bootstrap/accordion";
|
||||||
@import "./assets/scss/bootstrap/alerts";
|
@import "./assets/scss/bootstrap/alerts";
|
||||||
|
@ -167,6 +168,7 @@
|
||||||
@import "./assets/scss/custom/image";
|
@import "./assets/scss/custom/image";
|
||||||
@import "./assets/scss/custom/list";
|
@import "./assets/scss/custom/list";
|
||||||
@import "./assets/scss/custom/nav";
|
@import "./assets/scss/custom/nav";
|
||||||
|
@import "./assets/scss/custom/modal";
|
||||||
|
|
||||||
/* ############### CUSTOM VENDOR STYLES ############### */
|
/* ############### CUSTOM VENDOR STYLES ############### */
|
||||||
@import "./assets/scss/lib/select2";
|
@import "./assets/scss/lib/select2";
|
||||||
|
@ -228,3 +230,4 @@
|
||||||
@import '~@swimlane/ngx-datatable/index.css';
|
@import '~@swimlane/ngx-datatable/index.css';
|
||||||
@import '~@swimlane/ngx-datatable/themes/bootstrap.css';
|
@import '~@swimlane/ngx-datatable/themes/bootstrap.css';
|
||||||
@import '~@swimlane/ngx-datatable/assets/icons.css';
|
@import '~@swimlane/ngx-datatable/assets/icons.css';
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue