Commit 8a9e379b authored by ctorres's avatar ctorres

Initial commit

parents
Pipeline #315 failed with stages
# Editor configuration, see https://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
max_line_length = off
trim_trailing_whitespace = false
# See http://help.github.com/ignore-files/ for more about ignoring files.
# compiled output
/dist
/tmp
/out-tsc
# Only exists if Bazel was run
/bazel-out
# dependencies
/node_modules
# profiling files
chrome-profiler-events*.json
speed-measure-plugin*.json
# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*
# misc
/.sass-cache
/connect.lock
/coverage
/libpeerconnection.log
npm-debug.log
yarn-error.log
testem.log
/typings
# System Files
.DS_Store
Thumbs.db
FROM nginx:1.17-alpine
LABEL maintainer "mortiz@bytesw.com"
RUN apk --no-cache add curl
RUN curl -L https://github.com/a8m/envsubst/releases/download/v1.1.0/envsubst-`uname -s`-`uname -m` -o envsubst && \
chmod +x envsubst && \
mv envsubst /usr/local/bin
EXPOSE 80
COPY ./nginx.config /etc/nginx/nginx.template
CMD ["/bin/sh", "-c", "envsubst < /etc/nginx/nginx.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"]
COPY dist/bytebot-html /usr/share/nginx/html
pipeline {
environment {
imagename = "bytesw/bytebot-html"
url = "http://192.168.27.148:5000"
tag_name = "192.168.27.148:5000"
credentials = "admin-docker-hub"
dockerImage = ''
PACKAGE_VERSION = '2.5.0'
}
agent any
parameters {
string(defaultValue: 'no', description: 'Ejecuta los procesos docker', name: 'include_docker')
}
stages {
stage('Install') {
steps {
echo "Branch is ${env.BRANCH_NAME}..."
nodejs(nodeJSInstallationName: 'NodeJS13', configId: '77600a18-f968-4cca-83e4-a9f76d165336') {
sh 'PACKAGE_VERSION=$(node -p -e "require(\'./package.json\').version")'
sh 'npm config ls'
sh 'npm install'
sh 'npm i -D typescript@3.4.3'
}
}
}
stage('Test') {
parallel {
stage('Static code analysis') {
steps {
nodejs(nodeJSInstallationName: 'NodeJS13', configId: '77600a18-f968-4cca-83e4-a9f76d165336') {
sh 'npm run-script lint'
}
}
}
}
}
stage('Build') {
steps {
nodejs(nodeJSInstallationName: 'NodeJS13', configId: '77600a18-f968-4cca-83e4-a9f76d165336') {
sh 'ng build'
}
}
}
stage('Build Docker Image') {
when {
expression { params.include_docker == 'yes' }
}
steps {
nodejs(nodeJSInstallationName: 'NodeJS13', configId: '77600a18-f968-4cca-83e4-a9f76d165336') {
sh 'PACKAGE_VERSION=$(node -p -e "require(\'./package.json\').version")'
}
script {
dockerImage = docker.build imagename
}
}
}
stage('Deploy Image') {
when {
expression { params.include_docker == 'yes' }
}
steps{
script {
docker.withRegistry(url, credentials ) {
dockerImage.push("$PACKAGE_VERSION")
dockerImage.push('latest')
}
}
}
}
stage('Remove Unused docker image') {
when {
expression { params.include_docker == 'yes' }
}
steps{
sh "docker rmi $tag_name/$imagename:$PACKAGE_VERSION"
sh "docker rmi $tag_name/$imagename:latest"
}
}
}
post {
always {
echo 'Confirmación de ejecución!'
emailext body: "${currentBuild.currentResult}: Job ${env.JOB_NAME} build ${env.BUILD_NUMBER}\n More info at: ${env.BUILD_URL}",
recipientProviders: [[$class: 'DevelopersRecipientProvider'], [$class: 'RequesterRecipientProvider']],
subject: "Jenkins Build ${currentBuild.currentResult}: Job ${env.JOB_NAME}",
to: '$DEFAULT_RECIPIENTS'
}
}
}
# ByteBot
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.3.24.
## Development server
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
## Code scaffolding
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
## Build
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
## Running unit tests
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
## Running end-to-end tests
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
## Further help
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"bytebot-html": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"style": "scss"
}
},
"root": "projects/bytebot-html",
"sourceRoot": "projects/bytebot-html/src",
"prefix": "byte",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/bytebot-html",
"index": "projects/bytebot-html/src/index.html",
"main": "projects/bytebot-html/src/main.ts",
"polyfills": "projects/bytebot-html/src/polyfills.ts",
"tsConfig": "projects/bytebot-html/tsconfig.app.json",
"aot": false,
"assets": [
"projects/bytebot-html/src/favicon.ico",
"projects/bytebot-html/src/assets"
],
"styles": [
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
"./node_modules/material-icons/iconfont/material-icons.css",
"projects/bytebot-html/src/styles.scss",
"node_modules/font-awesome/scss/font-awesome.scss",
"node_modules/ngx-toastr/toastr.css",
"node_modules/ngx-bootstrap/datepicker/bs-datepicker.css"
],
"scripts": [
"node_modules/jquery/dist/jquery.min.js",
"vendor/metismenu/metisMenu.js",
"node_modules/popper.js/dist/umd/popper.js",
"node_modules/bootstrap/dist/js/bootstrap.min.js",
"node_modules/bootstrap/dist/js/bootstrap.bundle.min.js",
"node_modules/jquery-slimscroll/jquery.slimscroll.min.js",
"node_modules/marked/marked.min.js",
"node_modules/ace-builds/src-min/ace.js",
"node_modules/ace-builds/src-min/mode-markdown.js",
"node_modules/ace-builds/src-min/theme-eclipse.js",
"node_modules/ace-builds/src-min/mode-java.js",
"node_modules/peity/jquery.peity.min.js",
"node_modules/pace-js/pace.min.js",
"vendor/inspinia/inspinia.js"
]
},
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "projects/bytebot-html/src/environments/environment.ts",
"with": "projects/bytebot-html/src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "6kb",
"maximumError": "10kb"
}
]
}
}
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "bytebot-html:build"
},
"configurations": {
"production": {
"browserTarget": "bytebot-html:build:production"
}
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "bytebot-html:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "projects/bytebot-html/src/test.ts",
"polyfills": "projects/bytebot-html/src/polyfills.ts",
"tsConfig": "projects/bytebot-html/tsconfig.spec.json",
"karmaConfig": "projects/bytebot-html/karma.conf.js",
"assets": [
"projects/bytebot-html/src/favicon.ico",
"projects/bytebot-html/src/assets"
],
"styles": [
"projects/bytebot-html/src/styles.scss"
],
"scripts": []
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"projects/bytebot-html/tsconfig.app.json",
"projects/bytebot-html/tsconfig.spec.json",
"projects/bytebot-html/e2e/tsconfig.json"
],
"exclude": [
"**/node_modules/**"
]
}
},
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "projects/bytebot-html/e2e/protractor.conf.js",
"devServerTarget": "bytebot-html:serve"
},
"configurations": {
"production": {
"devServerTarget": "bytebot-html:serve:production"
}
}
}
}
}
},
"defaultProject": "bytebot-html"
}
\ No newline at end of file
server {
listen ${PORT:-80};
server_name _;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $$uri /index.html;
}
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; frame-ancestors 'none'; connect-src 'self' https://*.okta.com https://*.herokuapp.com";
add_header Referrer-Policy "no-referrer, strict-origin-when-cross-origin";
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains";
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options DENY;
add_header X-XSS-Protection "1; mode=block";
add_header Feature-Policy "accelerometer 'none'; camera 'none'; microphone 'none'";
}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"name": "bytebot-projects",
"version": "1.0.1",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
"private": true,
"dependencies": {
"@agm/core": "^1.1.0",
"@angular-material-components/datetime-picker": "^2.0.4",
"@angular/animations": "^8.2.14",
"@angular/cdk": "^8.2.3",
"@angular/common": "~8.2.14",
"@angular/compiler": "~8.2.14",
"@angular/core": "~8.2.14",
"@angular/forms": "~8.2.14",
"@angular/material": "^8.2.3",
"@angular/material-moment-adapter": "^9.2.0",
"@angular/platform-browser": "^8.2.14",
"@angular/platform-browser-dynamic": "^8.2.14",
"@angular/router": "~8.2.14",
"@babel/compat-data": "^7.8.0",
"@ng-bootstrap/ng-bootstrap": "^5.1.5",
"@ng-select/ng-select": "^3.7.3",
"@ngx-translate/core": "^12.1.2",
"@ngx-translate/http-loader": "^4.0.0",
"@swimlane/ngx-datatable": "^16.0.3",
"@swimlane/ngx-graph": "^6.2.0",
"@types/jquery": "^3.3.34",
"@xdf/commons": "^1.0.4",
"@xdf/gallery": "^1.0.18",
"@xdf/graph": "file:libs/xdf-graph-0.0.1.tgz",
"@xdf/layouts": "^1.0.3",
"@xdf/security": "^1.0.0",
"@xdf/settings": "^1.0.8",
"ace-builds": "^1.4.8",
"angular-gauge-chart": "^0.7.2",
"angular-highcharts": "^9.0.2",
"angular-marked": "^1.2.2",
"bootstrap": "^4.4.1",
"chart.js": "^2.9.3",
"dagre": "^0.8.5",
"date-fns": "^2.11.1",
"font-awesome": "^4.7.0",
"hammerjs": "^2.0.8",
"highcharts": "^8.0.4",
"jquery": "^3.4.1",
"jquery-slimscroll": "^1.3.8",
"material-design-icons": "^3.0.1",
"material-icons": "^0.3.1",
"metismenu": "^3.0.6",
"moment": "^2.22.1",
"moment-timezone": "^0.5.31",
"net": "^1.0.2",
"ng-circle-progress": "^1.5.1",
"ng-json-view": "^3.0.0",
"ng2-ace-editor": "^0.3.9",
"ng2-charts": "^2.3.0",
"ng2-data-table": "^1.4.0",
"ngx-bootstrap": "^4.3.0",
"ngx-color": "^4.1.1",
"ngx-echarts": "^4.2.2",
"ngx-material-file-input": "2.0.0",
"ngx-moment": "^3.5.0",
"ngx-scrollbar": "7.1.0",
"ngx-slick-carousel": "^0.5.1",
"ngx-toastr": "^10.0.4",
"ngx-translate-multi-http-loader": "^3.0.0",
"ngx-tribute": "^1.5.1",
"nomnoml": "^0.6.2",
"pace-js": "^1.0.2",
"peity": "^3.3.0",
"popper": "^1.0.1",
"popper.js": "^1.16.1",
"rxjs": "~6.4.0",
"stompjs": "^2.3.3",
"tributejs": "^5.1.3",
"tslib": "^1.10.0",
"zone.js": "~0.9.1"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.803.25",
"@angular/cli": "~8.3.24",
"@angular/compiler-cli": "~8.2.14",
"@angular/language-service": "~8.2.14",
"@types/jasmine": "~3.3.8",
"@types/jasminewd2": "~2.0.3",
"@types/node": "~8.9.4",
"codelyzer": "^5.0.0",
"jasmine-core": "~3.4.0",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~4.1.0",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage-istanbul-reporter": "~2.0.1",
"karma-jasmine": "~2.0.1",
"karma-jasmine-html-reporter": "^1.4.0",
"protractor": "~5.4.0",
"ts-node": "~7.0.0",
"tslint": "~5.15.0",
"typescript": "~3.5.3"
}
}
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries
# You can see what browsers were selected by your queries by running:
# npx browserslist
> 0.5%
last 2 versions
Firefox ESR
not dead
not IE 9-11 # For IE 9-11 support, remove 'not'.
\ No newline at end of file
// @ts-check
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts
const { SpecReporter } = require('jasmine-spec-reporter');
/**
* @type { import("protractor").Config }
*/
exports.config = {
allScriptsTimeout: 11000,
specs: [
'./src/**/*.e2e-spec.ts'
],
capabilities: {
browserName: 'chrome'
},
directConnect: true,
baseUrl: 'http://localhost:4200/',
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
},
onPrepare() {
require('ts-node').register({
project: require('path').join(__dirname, './tsconfig.json')
});
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
}
};
\ No newline at end of file
import { AppPage } from './app.po';
import { browser, logging } from 'protractor';
describe('workspace-project App', () => {
let page: AppPage;
beforeEach(() => {
page = new AppPage();
});
it('should display welcome message', () => {
page.navigateTo();
expect(page.getTitleText()).toEqual('bytebot-html app is running!');
});
afterEach(async () => {
// Assert that there are no errors emitted from the browser
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
expect(logs).not.toContain(jasmine.objectContaining({
level: logging.Level.SEVERE,
} as logging.Entry));
});
});
import { browser, by, element } from 'protractor';
export class AppPage {
navigateTo() {
return browser.get(browser.baseUrl) as Promise<any>;
}
getTitleText() {
return element(by.css('app-root .content span')).getText() as Promise<string>;
}
}
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"outDir": "../../../out-tsc/e2e",
"module": "commonjs",
"target": "es5",
"types": [
"jasmine",
"jasminewd2",
"node"
]
}
}
// Karma configuration file, see link for more information
// https://karma-runner.github.io/1.0/config/configuration-file.html
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular-devkit/build-angular'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('@angular-devkit/build-angular/plugins/karma')
],
client: {
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
coverageIstanbulReporter: {
dir: require('path').join(__dirname, '../../coverage/bytebot-html'),
reports: ['html', 'lcovonly', 'text-summary'],
fixWebpackSourcePaths: true
},
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false,
restartOnFileChange: true
});
};
import { NgModule } from "@angular/core";
import { Routes, RouterModule } from "@angular/router";
import { CustomLayoutComponent, NotFoundComponent } from "@xdf/layouts";
import { AuthGuard, LoginComponent } from "@xdf/security";
import { BytebotLayoutComponent } from "./modules/bytebot-layout/bytebot-layout/bytebot-layout.component";
import { HomeComponent } from "./views/home/home.component";
const routes: Routes = [
// Remover para SSO
{ path: "login", component: LoginComponent },
// Main redirect
{ path: "", redirectTo: "home", pathMatch: "full", canActivate: [AuthGuard] },
{
path: "",
component: CustomLayoutComponent,
children: [
{ path: "home", component: HomeComponent, data: { breadcrumb: "Home" } },
{
path: "security",
data: { breadcrumb: "Seguridad" },
canLoad: [AuthGuard],
loadChildren: () =>
import("./modules/security/security.module").then(
(m) => m.SecurityModule
),
},
{
path: "settings",
data: { breadcrumb: "Ajustes Generales" },
canLoad: [AuthGuard],
loadChildren: () =>
import("./modules/settings/settings.module").then(
(m) => m.SettingsModule
),
},
{
path: "configuration",
data: { breadcrumb: "Agentes" },
canLoad: [AuthGuard],
loadChildren: () =>
import("./modules/agent/agent.module").then((m) => m.AgentModule),
},
{
path: "reserva",
data: { breadcrumb: "Aeropuertos" },
canLoad: [AuthGuard],
loadChildren: () =>
import("./modules/aeropuerto/aeropuerto.module").then(
(m) => m.AeropuertoModule
),
},
],
canActivate: [AuthGuard],
},
{ path: "notpermitted", component: NotFoundComponent },
// Handle all other routes
{ path: "**", component: NotFoundComponent },
];
@NgModule({
imports: [
RouterModule.forRoot(routes, {
scrollPositionRestoration: "enabled",
anchorScrolling: "enabled",
onSameUrlNavigation: "ignore",
}),
],
exports: [RouterModule],
})
export class AppRoutingModule {}
<router-outlet></router-outlet>
\ No newline at end of file
import { TestBed, async } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule
],
declarations: [
AppComponent
],
}).compileComponents();
}));
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
});
it(`should have as title 'bytebot-html'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app.title).toEqual('bytebot-html');
});
it('should render title', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.debugElement.nativeElement;
expect(compiled.querySelector('.content span').textContent).toContain('bytebot-html app is running!');
});
});
import { Component } from '@angular/core';
@Component({
selector: 'byte-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'bytebot-html';
}
import { BrowserModule } from "@angular/platform-browser";
import { NgModule, APP_INITIALIZER } from "@angular/core";
import { AppRoutingModule } from "./app-routing.module";
import {
CommonModule,
HashLocationStrategy,
LocationStrategy,
registerLocaleData,
} from "@angular/common";
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
import {
HttpClientModule,
HttpClient,
HTTP_INTERCEPTORS,
} from "@angular/common/http";
import {
TranslateModule,
TranslateLoader,
TranslateService,
} from "@ngx-translate/core";
// XDF
import {
XdfLayoutsModule,
SettingsService,
ByteSettingsService,
SettingsFakeBackendInterceptor,
} from "@xdf/layouts";
import {
XdfSecurityModule,
ByteAuthenticationService,
AuthGuard,
OAuthGuard,
OAuthAuthenticationService,
} from "@xdf/security";
import {
ResourceAuthGuard,
AuthenticationFakeBackendInterceptor,
ProgramsFakeBackendInterceptor,
} from "@xdf/security";
import {
XdfCommonsModule,
NotificationService,
ToastNotificationService,
AuthenticationService,
} from "@xdf/commons";
import {
INITSERVICE_OPTIONS,
InitCommonsService,
ErrorsHandler,
} from "@xdf/commons";
// Components
import { AppComponent } from "./app.component";
import { HomeComponent } from "./views/home/home.component";
import { ToastrModule } from "ngx-toastr";
import localeEs from "@angular/common/locales/es-PE";
import localeEn from "@angular/common/locales/en";
import {
MAT_DATE_LOCALE,
MatDialog,
MatButtonModule,
MatDialogModule,
MatPaginatorIntl,
DateAdapter,
} from "@angular/material";
import { MAT_DATE_FORMATS, MatIconModule } from "@angular/material";
import {
XdfGalleryModule,
CustomMatPaginatorIntl,
DATERANGEPICKER_LOCALE,
DaterangepickerLocaleService,
} from "@xdf/gallery";
import {
ConflictErrorDialogService,
HttpErrorHandleInterceptor,
} from "@xdf/gallery";
import { BytebotSettingsService } from "./services/bytebot-settings-service";
import { MultiTranslateHttpLoader } from "ngx-translate-multi-http-loader";
import { AgentModule } from "./modules/agent/agent.module";
import {
MAT_MOMENT_DATE_FORMATS,
MomentDateAdapter,
MAT_MOMENT_DATE_ADAPTER_OPTIONS,
} from "@angular/material-moment-adapter";
import { CustomProgramsFakeBackendInterceptor } from "./interceptors/custom-programs-fake-backend.interceptor";
import { AgentFakeBackendInterceptor } from "./interceptors/agent-fake-backend.interceptor";
import { OperativeDashboardFakeBackendInterceptor } from "./interceptors/operative-dashboard-fake-backend.interceptor";
import { CustomErrorHandlerInterceptor } from "./interceptors/custom-error-handler.interceptor";
const INITIAL_LANGUAGE = "es";
registerLocaleData(localeEs, "es");
registerLocaleData(localeEn, "en");
export function createTranslateLoader(http: HttpClient) {
return new MultiTranslateHttpLoader(http, [
{ prefix: "./assets/i18n/", suffix: ".json" },
{ prefix: "./assets/i18n/menu/", suffix: ".json" },
{ prefix: "./assets/i18n/layouts/", suffix: ".json" },
{ prefix: "./assets/i18n/gallery/", suffix: ".json" },
{ prefix: "./assets/i18n/security/", suffix: ".json" },
{ prefix: "./assets/i18n/settings/", suffix: ".json" },
]);
}
@NgModule({
declarations: [AppComponent, HomeComponent],
imports: [
BrowserModule,
HttpClientModule,
AppRoutingModule,
CommonModule,
BrowserAnimationsModule,
FormsModule,
ReactiveFormsModule,
ToastrModule.forRoot(),
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: createTranslateLoader,
deps: [HttpClient],
},
}),
XdfCommonsModule.forRoot({
language: INITIAL_LANGUAGE,
}),
XdfLayoutsModule,
XdfSecurityModule,
XdfGalleryModule,
MatDialogModule,
MatButtonModule,
AgentModule,
MatIconModule,
],
providers: [
{ provide: MAT_DATE_LOCALE, useValue: INITIAL_LANGUAGE },
{
provide: DateAdapter,
useClass: MomentDateAdapter,
deps: [MAT_DATE_LOCALE, MAT_MOMENT_DATE_ADAPTER_OPTIONS],
},
{ provide: MAT_DATE_FORMATS, useValue: MAT_MOMENT_DATE_FORMATS },
{
provide: MatPaginatorIntl,
useClass: CustomMatPaginatorIntl,
deps: [TranslateService],
},
{ provide: DATERANGEPICKER_LOCALE, useValue: INITIAL_LANGUAGE },
{
provide: DaterangepickerLocaleService,
useClass: DaterangepickerLocaleService,
},
{ provide: LocationStrategy, useClass: HashLocationStrategy },
{ provide: NotificationService, useClass: ToastNotificationService },
{ provide: SettingsService, useClass: ByteSettingsService },
ConflictErrorDialogService,
{
provide: HTTP_INTERCEPTORS,
useClass: HttpErrorHandleInterceptor,
multi: true,
},
// { provide: HTTP_INTERCEPTORS, useClass: ErrorsHandler, multi: true},
{ provide: ResourceAuthGuard, useClass: ResourceAuthGuard },
// descomentar estas lineas para OAUTH
//{ provide: AuthGuard, useClass: OAuthGuard },
//{ provide: AuthenticationService, useClass: OAuthAuthenticationService },
//{ provide: APP_INITIALIZER, useFactory: loginLoaderFactory, deps: [AuthenticationService], multi: true },
// Para probar mantenimientos
// comentar estas lineas para OAUTH
{ provide: AuthGuard, useClass: AuthGuard },
{ provide: AuthenticationService, useClass: ByteAuthenticationService },
{
provide: HTTP_INTERCEPTORS,
useClass: AuthenticationFakeBackendInterceptor,
multi: true,
},
{
provide: HTTP_INTERCEPTORS,
useClass: SettingsFakeBackendInterceptor,
multi: true,
},
{
provide: HTTP_INTERCEPTORS,
useClass: CustomProgramsFakeBackendInterceptor,
multi: true,
},
{
provide: HTTP_INTERCEPTORS,
useClass: AgentFakeBackendInterceptor,
multi: true,
},
{
provide: HTTP_INTERCEPTORS,
useClass: OperativeDashboardFakeBackendInterceptor,
multi: true,
},
{
provide: APP_INITIALIZER,
useFactory: init_app,
deps: [InitCommonsService, TranslateService],
multi: true,
},
],
bootstrap: [AppComponent],
})
export class AppModule {}
export function init_app(appLoaderService: InitCommonsService) {
return () => appLoaderService.initializeApp();
}
// required for AOT compilation
// export function HttpLoaderFactory(http: HttpClient) {
// return new TranslateHttpLoader(http);
// }
// Para OAUTH
export function loginLoaderFactory(provider: OAuthAuthenticationService) {
return () => provider.login(null, null).toPromise();
}
import { HttpRequest, HttpResponse, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import { Observable, of, throwError } from 'rxjs';
import { delay, mergeMap, materialize, dematerialize } from 'rxjs/operators';
import { Injectable } from '@angular/core';
import { SortField, DIRECTION } from '@xdf/commons';
const basePath = '/service/agent';
const tableData: Array<any> = [
{
id: 361,
name: 'BANCO DE CREDITO DEL PERU',
version: '0.0.1',
status: 'Activo',
country: 'Perú',
timezone: 'GMT-5',
avatar: 'https://www.w3schools.com/howto/img_avatar.png'
},
{
id: 362,
name: 'BANCO CONTINENTAL',
version: '0.0.5',
status: 'Activo',
country: 'Perú',
timezone: 'GMT-5',
avatar: 'https://lh3.googleusercontent.com/VHB9bVB8cTcnqwnu0nJqKYbiutRclnbGxTpwnayKB4vMxZj8pk1220Rg-6oQ68DwAkqO=s180-rw'
},
{
id: 363,
name: 'JUAN DE ARONA',
version: '0.0.1',
status: 'Activo',
country: 'Perú',
timezone: 'GMT-5',
avatar: 'https://www.w3schools.com/howto/img_avatar.png'
},
{
id: 364,
name: 'JUAN DE ARONA 2',
version: '0.0.1',
status: 'Activo',
country: 'Perú',
timezone: 'GMT-5',
avatar: 'https://www.w3schools.com/howto/img_avatar.png'
}
];
const data: Array<any> = [
{
id: 361,
name: 'BANCO DE CREDITO DEL PERU',
version: '0.0.1',
status: 'Activo',
country: 'Perú',
timezone: 'GMT-5',
avatar: 'https://www.w3schools.com/howto/img_avatar.png'
}
];
const countries: Array<any> = [
{
id: 1,
name: 'Perú',
timezones: [
'GMT-5'
]
},
{
id: 2,
name: 'Argentina',
timezones: [
'GMT-3'
]
},
{
id: 3,
name: 'Brazil',
timezones: [
'GMT-5',
'GMT-4',
'GMT-3',
'GMT-2'
]
}
];
const fakeAgentData = {
id: 361,
name: 'BANCO DE CREDITO DEL PERU',
description: 'El mejor banco que te roba la plata con intereses',
version: '0.0.1',
status: 'Activo',
countryId: 1,
timezone: 'GMT-5',
avatar: '',
frequentQuestions: [
{
id: 1,
filename: 'questions-opt.xlsx',
description: 'primer archivo',
status: 'PS',
user: '',
uploadDate: ''
},
{
id: 2,
filename: 'questions-training.xlsx',
description: 'segundo archivo',
status: 'PS',
user: '',
uploadDate: ''
},
{
id: 3,
filename: 'questions-brainstorming.xlsx',
description: 'tercero archivo',
status: 'PS',
user: '',
uploadDate: ''
},
{
id: 4,
filename: 'questions-onu.xlsx',
description: 'cuarto archivo',
status: 'PS',
user: '',
uploadDate: ''
},
{
id: 5,
filename: 'questions-byte.xlsx',
description: 'quinto archivo',
status: 'PS',
user: '',
uploadDate: ''
}
]
};
const fakeAgentData2 = {
id: 361,
name: 'BANCO DE CREDITO DEL PERU',
description: 'El mejor banco que te roba la plata con intereses',
version: '0.0.1',
status: 'Activo',
countryId: 1,
timezone: 'GMT-5',
avatar: '',
frequentQuestions: []
};
const channels = [
{
id: 101,
name: 'Facebook Messenger',
image: 'https://img.icons8.com/color/452/facebook-messenger.png',
parameters: [
{
name: 'webhook',
label: 'webhook',
maxlength: 200,
type: 'text',
required: true,
traductions: { es: 'URL de devolución de llamada', en: 'Webhook' }
},
{
name: 'verification-token',
label: 'verification-token',
maxlength: 80,
type: 'text',
required: true,
traductions: { es: 'Token de verificación', en: 'Verification token' }
},
{
name: 'access-token',
label: 'access-token',
maxlength: 80,
type: 'text',
required: true,
traductions: { es: 'Token de acceso', en: 'Access token' }
}
]
},
{
id: 103,
name: 'WhatsApp',
image: 'https://img.icons8.com/color/452/whatsapp.png',
parameters: [
{
name: 'account-identifier',
label: 'account-identifier',
maxlength: 80,
type: 'text',
required: true,
traductions: { es: 'Identificador de cuenta', en: 'Account identifier' }
},
{
name: 'authentication-token',
label: 'authentication-token',
maxlength: 80,
type: 'text',
required: true,
traductions: { es: 'Token de autenticación', en: 'Authentication token' }
},
{
name: 'twillio-number',
label: 'twillio-number',
type: 'number',
required: true,
traductions: { es: 'Número de Twillio', en: 'Twillio number' }
}
]
}
];
const fileOK = {
uuid: '6850b631-5cb1-4614-8f0e-e43441d7bd35',
id: 100,
fileName: 'vacaciones-preguntas.xls',
description: 'Preguntas Vacaciones',
status: 'PS',
user: '',
uploadDate: ''
};
@Injectable()
export class AgentFakeBackendInterceptor implements HttpInterceptor {
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const { url, method, headers, body } = request;
return of(null)
.pipe(mergeMap(handleRoute))
.pipe(materialize())
.pipe(delay(10))
.pipe(dematerialize());
function handleRoute() {
switch (true) {
// case url.endsWith(basePath + '/page') && method === 'POST':
// return pagination(body);
// case url.indexOf(basePath + '/connection/data') !== -1 && method === 'GET ':
// return ok({});
// case url.indexOf(basePath + '/countries') !== -1 && method === 'GET':
// return ok(countries);
// case url.indexOf(basePath + '/channels') !== -1 && method === 'GET':
// return ok(channels);
// case url.indexOf(basePath + '/file-upload') !== -1 && method === 'POST':
// return ok(fileOK);
// case url.indexOf(basePath + '/') !== -1 && method === 'GET':
// return ok(fakeAgentData);
default:
// pass through any requests not handled above
return next.handle(request);
}
}
function pagination(dataRecibida: any) {
dataRecibida.totalItems = tableData.length;
const pageNumber = dataRecibida.currentPage;
const pageSize = dataRecibida.itemsPerPage ? dataRecibida.itemsPerPage : 5;
dataRecibida.totalPages = Math.ceil(dataRecibida.totalItems / pageSize);
if (dataRecibida.sortFields.length > 0) {
const sortField: any = dataRecibida.sortFields[0];
if (sortField.direction === DIRECTION.asc) {
tableData.sort((a, b) => {
if (JSON.stringify(a[sortField.field]) > JSON.stringify(b[sortField.field])) {
return 1;
} else if (JSON.stringify(a[sortField.field]) < JSON.stringify(b[sortField.field])) {
return -1;
}
return 0;
});
} else {
tableData.sort((a, b) => {
if (JSON.stringify(a[sortField.field]) < JSON.stringify(b[sortField.field])) {
return 1;
} else if (JSON.stringify(a[sortField.field]) > JSON.stringify(b[sortField.field])) {
return -1;
}
return 0;
});
}
}
dataRecibida.data = tableData.slice(pageNumber * pageSize, (pageNumber + 1) * pageSize);
return ok(dataRecibida);
}
function ok(bodyContent?: any) {
return of(new HttpResponse({ status: 200, body: bodyContent }));
}
function error(message: string) {
return throwError({ error: { message } });
}
}
}
import {
HttpRequest,
HttpResponse,
HttpHandler,
HttpEvent,
HttpInterceptor,
HttpErrorResponse
} from '@angular/common/http';
import { Observable, throwError, of, EMPTY } from 'rxjs';
import { Injectable } from '@angular/core';
import { catchError, tap, map } from 'rxjs/operators';
import { TranslateService } from '@ngx-translate/core';
import { NotificationService, NotificationType, AuthenticationService } from '@xdf/commons';
import { Router } from '@angular/router';
import { ConflictErrorDialogService } from '@xdf/gallery';
@Injectable()
export class CustomErrorHandlerInterceptor implements HttpInterceptor {
constructor(
private router: Router,
private translate: TranslateService,
private authenticationService: AuthenticationService,
private notificationService: NotificationService,
private conflictErrorDialogService: ConflictErrorDialogService) {
}
intercept(
req: HttpRequest<any>, next: HttpHandler): Observable<any> {
return next.handle(req).pipe(
catchError((error: HttpErrorResponse) => {
switch (error.status) {
case 401:
const message = this.translate.instant('message.error.unauthorized');
this.notificationService.showMessage(message, this.translate.instant('title.error'), NotificationType.error);
break;
case 404:
const messageError = error.error ? error.error : error.message;
this.notificationService.showMessage(messageError, this.translate.instant('title.error'), NotificationType.error);
break;
case 409:
const messageDuplicate = this.translate.instant('message.error.duplicated');
this.notificationService.showMessage(messageDuplicate, this.translate.instant('title.error'), NotificationType.error);
break;
case 419: // validar cual es el código correcto
this.conflictErrorDialogService.loadComponent(
null,
'title.error.conflict',
'message.error.conflict',
error.error);
break;
default:
if (error.status === 0) {
this.authenticationService.login(null, null).subscribe(
data => {
window.location.href = './';
});
} else {
let messageDefault = '';
if (error.error) {
if (error.error.params) {
const params = [];
error.error.params.forEach(element => {
params.push(this.translate.instant(element));
});
messageDefault = this.translate.instant(error.error.message, params);
} else {
if (error.error.message) {
messageDefault = this.translate.instant(error.error.message);
} else {
messageDefault = this.translate.instant(error.error);
}
}
} else {
messageDefault = this.translate.instant(error.message);
}
this.notificationService.showMessage(messageDefault, this.translate.instant('title.error'), NotificationType.error);
}
}
return throwError(error);
})
);
}
}
import { HttpRequest, HttpResponse, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import { Observable, of, throwError } from 'rxjs';
import { delay, mergeMap, materialize, dematerialize } from 'rxjs/operators';
import { Injectable } from '@angular/core';
import * as source from '../../assets/fake-data/programs-data.json';
import * as controlsSource from '../../assets/fake-data/controls-data.json';
const basePath = '/service/security/programs';
const basePathCotnrols = '/service/security/controls';
@Injectable()
export class CustomProgramsFakeBackendInterceptor implements HttpInterceptor {
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const { url, method, headers, body } = request;
const data = (source as any).default;
const dataControls = (controlsSource as any).default;
return of(null)
.pipe(mergeMap(handleRoute))
.pipe(materialize())
.pipe(delay(50))
.pipe(dematerialize());
function handleRoute() {
switch (true) {
case url.match('.*' + basePath) && method === 'GET':
return getList();
case url.match('.*' + basePathCotnrols + '.*') && method === 'GET':
return getControls();
default:
// pass through any requests not handled above
return next.handle(request);
}
}
function getList() {
return ok(data);
}
function getControls() {
return ok(dataControls);
}
// helper functions
function ok(bodyContent?) {
return of(new HttpResponse({ status: 200, body: bodyContent }));
}
function error(message: string) {
return throwError({ error: { message } });
}
}
}
import { HttpRequest, HttpResponse, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import { Observable, of, throwError } from 'rxjs';
import { delay, mergeMap, materialize, dematerialize } from 'rxjs/operators';
import { Injectable } from '@angular/core';
import * as source from '../../assets/fake-data/operative-dashboard-data.json';
const basePath = '/test';
@Injectable()
export class OperativeDashboardFakeBackendInterceptor implements HttpInterceptor {
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const { url, method, headers, body } = request;
const data = (source as any).default;
return of(null)
.pipe(mergeMap(handleRoute))
.pipe(materialize())
.pipe(delay(50))
.pipe(dematerialize());
function handleRoute() {
switch (true) {
case url.match('.*' + basePath) && method === 'POST':
return getData();
default:
// pass through any requests not handled above
return next.handle(request);
}
}
function getData() {
return ok(data);
}
// helper functions
function ok(bodyContent?) {
return of(new HttpResponse({ status: 200, body: bodyContent }));
}
function error(message: string) {
return throwError({ error: { message } });
}
}
}
import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import { RouterModule, Routes } from "@angular/router";
import { AeropuertoListComponent } from "./view/aeropuerto-list/aeropuerto-list.component";
import { AuthGuard, ResourceAuthGuard } from "@xdf/security";
const routes: Routes = [
{
path: "airport",
component: AeropuertoListComponent,
canActivate: [AuthGuard, ResourceAuthGuard],
data: {
program: "CONVERSATIONAL_AIRPORT",
// breadcrumb: ''
},
},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class AeropuertoRoutingModule {}
import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import { AeropuertoListComponent } from "./view/aeropuerto-list/aeropuerto-list.component";
import { AeropuertoRoutingModule } from "./aeropuerto-routing.module";
@NgModule({
declarations: [AeropuertoListComponent],
imports: [CommonModule, AeropuertoRoutingModule],
})
export class AeropuertoModule {}
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { AeropuertoListComponent } from './aeropuerto-list.component';
describe('AeropuertoListComponent', () => {
let component: AeropuertoListComponent;
let fixture: ComponentFixture<AeropuertoListComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ AeropuertoListComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(AeropuertoListComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'byte-aeropuerto-list',
templateUrl: './aeropuerto-list.component.html',
styleUrls: ['./aeropuerto-list.component.scss']
})
export class AeropuertoListComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AuthGuard, ResourceAuthGuard } from '@xdf/security';
import { DirtyGuard } from '@xdf/gallery';
import { AgentComponent } from './view/agent/agent.component';
import { AgentDetailComponent } from './view/agent-detail/agent-detail.component';
import { AgentDataForWizardResolver } from './resolver/agent-data-wizard.resolver';
import { AgentDetailResolver } from './resolver/agent-detail.resolver';
import { AgentListComponent } from './view/agent-list/agent-list.component';
import { CountryDataForWizardResolver } from './resolver/country-data-wizard.resolver';
const routes: Routes = [
{
path: 'agent', component: AgentListComponent, canActivate: [AuthGuard, ResourceAuthGuard],
data: {
program: 'CONVERSATIONAL_AGENT',
// breadcrumb: ''
}
},
{
path: 'agent/detail/new',
// component: AgentDetailComponent,
component: AgentComponent,
resolve: {
countryData : CountryDataForWizardResolver
},
canActivate: [AuthGuard, ResourceAuthGuard], canDeactivate: [DirtyGuard],
data:
{
mode: 'create',
program: 'CONVERSATIONAL_AGENT',
breadcrumb: 'Agentes',
backButton: true
}
},
{
path: 'agent/detail/edit/:code',
// component: AgentDetailComponent,
component: AgentComponent,
resolve: {
agentDetail: AgentDetailResolver,
countryData : CountryDataForWizardResolver
},
canActivate: [AuthGuard, ResourceAuthGuard], canDeactivate: [DirtyGuard],
data:
{
mode: 'edit',
program: 'CONVERSATIONAL_AGENT',
breadcrumb: 'Agentes',
backButton: true
}
}, {
path: 'agent/detail/view/:code',
// component: AgentDetailComponent,
component: AgentComponent,
resolve: {
agentDetail: AgentDetailResolver,
countryData : CountryDataForWizardResolver
},
canActivate: [AuthGuard, ResourceAuthGuard],
data:
{
mode: 'view',
program: 'CONVERSATIONAL_AGENT',
breadcrumb: 'Agentes',
backButton: true
}
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class AgentRoutingModule { }
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { TranslateModule } from '@ngx-translate/core';
import {NgxTributeModule} from 'ngx-tribute';
import { MaterialFileInputModule } from 'ngx-material-file-input';
import { XdfGalleryModule } from '@xdf/gallery';
import { MatProgressSpinnerModule, MatDividerModule, MatSidenavModule, MatListModule } from '@angular/material';
import { MatStepperModule, MatDialogModule, MatMenuModule, MatIconModule } from '@angular/material';
import { MatSlideToggleModule, MatCheckboxModule, MatRippleModule, MatNativeDateModule } from '@angular/material';
import { MatChipsModule, MatExpansionModule, MatTooltipModule, MatToolbarModule } from '@angular/material';
import { MatTabsModule, MatTableModule, MatSortModule, MatSelectModule, MatRadioModule } from '@angular/material';
import { MatPaginatorModule, MatInputModule, MatFormFieldModule, MatButtonToggleModule } from '@angular/material';
import { MatButtonModule, MatCardModule, MatAutocompleteModule, MatSnackBarModule } from '@angular/material';
import { MatProgressBarModule } from '@angular/material';
import { SlickCarouselModule } from 'ngx-slick-carousel';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { AgentRoutingModule } from './agent-routing.module';
import { AceEditorModule } from 'ng2-ace-editor';
import { AgentComponent } from './view/agent/agent.component';
import { AgentDetailComponent } from './view/agent-detail/agent-detail.component';
import { DynamicTranslatePipe } from './pipe/dynamic-translate.pipe';
import { CaGeneralInformationComponent } from './view/components/ca-general-information/ca-general-information.component';
import { CaFrequentQuestionsComponent } from './view/components/ca-frequent-questions/ca-frequent-questions.component';
import { CaDeploymentChannelsComponent } from './view/components/ca-deployment-channels/ca-deployment-channels.component';
import { AgentListComponent } from './view/agent-list/agent-list.component';
import { CaDeploymentChannelsModalComponent } from './view/components/ca-deployment-channels-modal/ca-deployment-channels-modal.component';
import { AgentStatusPipe } from './pipe/agent-status.pipe';
import { CaFileUploadModalComponent } from './view/components/ca-file-upload-modal/ca-file-upload-modal.component';
@NgModule({
entryComponents: [
CaDeploymentChannelsModalComponent,
CaFileUploadModalComponent
],
declarations: [
AgentComponent,
AgentListComponent,
AgentDetailComponent,
DynamicTranslatePipe,
CaGeneralInformationComponent,
CaFrequentQuestionsComponent,
CaDeploymentChannelsComponent,
CaDeploymentChannelsModalComponent,
AgentStatusPipe,
CaFileUploadModalComponent
],
imports: [
FormsModule,
ReactiveFormsModule,
MatAutocompleteModule,
MatCardModule,
MatButtonModule,
MatButtonToggleModule,
MatFormFieldModule,
MatInputModule,
MatPaginatorModule,
MatProgressSpinnerModule,
MatRadioModule,
MatSelectModule,
MatSortModule,
MatTabsModule,
MatTableModule,
MatToolbarModule,
MatTooltipModule,
MatExpansionModule,
MatChipsModule,
MatNativeDateModule,
MatRippleModule,
MatCheckboxModule,
MatSlideToggleModule,
MatIconModule,
MatMenuModule,
MatDialogModule,
MatStepperModule,
MatListModule,
MatSidenavModule,
MatDividerModule,
MatSnackBarModule,
NgbModule,
SlickCarouselModule,
TranslateModule,
XdfGalleryModule,
AgentRoutingModule,
CommonModule,
AceEditorModule,
NgxTributeModule,
MatProgressBarModule,
MaterialFileInputModule
],
exports: [
]
})
export class AgentModule { }
import { AgentStatusPipe } from './agent-status.pipe';
describe('AgentStatusPipe', () => {
it('create an instance', () => {
const pipe = new AgentStatusPipe();
expect(pipe).toBeTruthy();
});
});
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'agentStatus'
})
export class AgentStatusPipe implements PipeTransform {
transform(value: any, ...args: any[]): any {
if (value) {
switch (value) {
case 'CR':
return 'label.created';
case 'DP':
return 'label.deployed';
case 'PS':
return 'label.sync-pending';
}
}
return value;
}
}
import { DynamicTranslatePipe } from './dynamic-translate.pipe';
describe('DynamicTranslatePipe', () => {
it('create an instance', () => {
const pipe = new DynamicTranslatePipe();
expect(pipe).toBeTruthy();
});
});
import { Pipe, PipeTransform } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
@Pipe({
name: 'dynamicTranslate'
})
export class DynamicTranslatePipe implements PipeTransform {
constructor(private translateService: TranslateService) {
}
transform(value: any, ...args: any[]): any {
const lang = this.translateService.currentLang ? this.translateService.currentLang : this.translateService.defaultLang;
let traductions;
if (args[0].param) {
if (typeof args[0].param === 'string') {
traductions = JSON.parse(args[0].param);
} else {
traductions = args[0].param;
}
}
if (traductions && traductions[lang]) {
return traductions[lang];
} else {
return value;
}
}
}
import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { AgentService } from '../service/agent.service';
import { Observable } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class AgentDataForWizardResolver implements Resolve<any> {
constructor(private service: AgentService) {}
resolve(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<any>|Promise<any>|any {
const code = route.paramMap.get('code');
return this.service.getDataForWizard(parseInt(code, 10));
}
}
import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { AgentService } from '../service/agent.service';
import { Observable } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class AgentDetailResolver implements Resolve<any> {
constructor(private service: AgentService) {}
resolve(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<any>|Promise<any>|any {
const code = route.paramMap.get('code');
return this.service.getResult(code);
}
}
import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { AgentService } from '../service/agent.service';
import { Observable } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class CountryDataForWizardResolver implements Resolve<any> {
constructor(private service: AgentService) {}
resolve(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<any>|Promise<any>|any {
return this.service.getCountryDataForWizard();
}
}
import { TestBed } from '@angular/core/testing';
import { AgentService } from './agent.service';
describe('AgentService', () => {
beforeEach(() => TestBed.configureTestingModule({}));
it('should be created', () => {
const service: AgentService = TestBed.get(AgentService);
expect(service).toBeTruthy();
});
});
import { Injectable } from '@angular/core';
import { DynaDataService } from '@xdf/gallery';
import { HttpClient } from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class AgentService extends DynaDataService {
serviceURL = './service/agent';
constructor(private httpClient: HttpClient) {
super(httpClient);
}
getDataForWizard(agentId: number) {
let params = {};
if (agentId) {
params = {
id: agentId
};
}
return this.httpClient.get(this.serviceURL + '/connection/data', {
params
});
}
getCountryDataForWizard() {
return this.httpClient.get(this.serviceURL + '/countries');
}
upload(formData) {
return this.httpClient.post<any>(this.serviceURL + '/file-upload', formData, {
reportProgress: true,
observe: 'events'
});
}
getChannelDatForWizard() {
return this.httpClient.get(this.serviceURL + '/channels');
}
synchronize(id: number, user: string) {
return this.httpClient.get(this.serviceURL + '/synchronize/' + id, {
params: {
user
}
});
}
}
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { AgentDetailComponent } from './agent-detail.component';
describe('AgentDetailComponent', () => {
let component: AgentDetailComponent;
let fixture: ComponentFixture<AgentDetailComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ AgentDetailComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(AgentDetailComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'byte-agent-detail',
templateUrl: './agent-detail.component.html',
styleUrls: ['./agent-detail.component.scss']
})
export class AgentDetailComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-lg-12">
<div class="ibox float-e-margins">
<div class="ibox-title">
<h5>{{'label.agent' | translate}}</h5>
</div>
<div class="ibox-content">
<div class="content">
<div class="grid-ibox-content">
<div class="filter-panel mat-elevation-z3">
<xdf-ngx-tags-input name="name" class="input-lg" [fields]="fieldFilters"
(filterEvent)="onFilter($event)"></xdf-ngx-tags-input>
</div>
<br />
<div class="grid-container mat-elevation-z3">
<div class="spinner-container" *ngIf="dataSource?.loading$ | async">
<mat-spinner diameter="40"></mat-spinner>
</div>
<table class="crud-table table table-striped table-hover" mat-table
[dataSource]="dataSource" matSort [matSortActive]="sortColumn"
[matSortDirection]="sortDirection" matSortDisableClear multiTemplateDataRows>
<ng-container matColumnDef="{{template.name}}"
*ngFor="let template of columnTemplateArray">
<div *ngIf="template.sortable">
<th mat-header-cell *matHeaderCellDef mat-sort-header
[ngClass]="{'th-avatar': template['name'] === 'avatar', 'text-right': template['name'] === 'id'}">
{{ template.title | translate }}
<mat-icon *ngIf="sortColumn===template?.name">
<i class="fa fa-sort-amount-desc"
*ngIf="sortDirection === 'desc'"></i>
<i class="fa fa-sort-amount-asc"
*ngIf="sortDirection === 'asc'"></i>
</mat-icon>
</th>
</div>
<div *ngIf="!template.sortable">
<th mat-header-cell *matHeaderCellDef>{{ template.title | translate }}
</th>
</div>
<td mat-cell *matCellDef="let item"
[style.width]="template.style.width ? template.style.width : ''"
[ngClass]="{'td-view': !this.resourceAuth['view'], 'text-right': template['name'] === 'id'}"
(click)="view(item)">
<div *ngIf="template['name'] !== 'avatar'">
<span class="label" [ngClass]="{'label-success': item[template['name']] === 'DP', 'label-default': item[template['name']] === 'CR',
'label-warning': item[template['name']] === 'PS' }"
*ngIf="template['name'] === 'status'">{{ item[template['name']] | agentStatus | translate }}</span>
<span
*ngIf="template['name'] !== 'status'">{{ item[template['name']] }}</span>
</div>
<img *ngIf="template['name'] === 'avatar'" [src]="item[template['name']]"
alt="Avatar" class="avatar">
</td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef></th>
<td class="text-center mat-cell cdk-column-actions mat-column-actions ng-star-inserted"
mat-cell="" role="gridcell" *matCellDef="let item">
<div class="btn-group btn-actions">
<!--
<button mat-icon-button [matMenuTriggerFor]="beforeMenu"
aria-label="Example icon-button with a menu">
<mat-icon>more_vert</mat-icon>
</button>
<mat-menu #beforeMenu="matMenu" xPosition="before">
<button mat-menu-item (click)="synchronize(item)"
*ngIf="item.status !== 'DP'">
<mat-icon>sync_alt</mat-icon>
<span>Sincronizar</span>
</button>
<button mat-menu-item (click)="edit(item)"
*ngIf="this.resourceAuth['edit']">
<mat-icon>edit</mat-icon>
<span>{{'btn.edit' | translate}}</span>
</button>
<button mat-menu-item color="warn" (click)="delete(item)"
*ngIf="this.resourceAuth['delete']">
<mat-icon>delete</mat-icon>
<span>{{'btn.delete' | translate}}</span>
</button>
</mat-menu>
-->
<button class="btn btn-default btn-sm" (click)="edit(item)"
*ngIf="this.resourceAuth['edit']" type="button">
<i class="fa fa-edit"></i>
<span class="visible-md-inline visible-lg-inline visible-xl-inline">
{{'btn.edit' | translate}}
</span>
</button>
<button class="btn btn-default btn-sm" (click)="delete(item)"
*ngIf="this.resourceAuth['delete']" type="button">
<i class="fa fa-trash"></i>
<span class="visible-md-inline visible-lg-inline visible-xl-inline">
{{'btn.delete' | translate}}
</span>
</button>
<button class="btn btn-default btn-sm dropdown-toggle" type="button"
[matMenuTriggerFor]="beforeMenu" [disabled]="item.status !== 'PS'">
<!-- <i class="fa fa-ellipsis-v"></i> -->
</button>
<mat-menu #beforeMenu="matMenu" xPosition="before">
<button mat-menu-item (click)="synchronize(item)"
*ngIf="item.status !== 'DP'">
<mat-icon>sync_alt</mat-icon>
<span>{{'btn.synchronize' | translate}}</span>
</button>
</mat-menu>
</div>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<div class="status-button-bar pull-left">
<button type="button" mat-icon-button
matTooltip="{{ 'action.grid.refresh' | translate }}" (click)="onRefresh()">
<i class="fa fa-refresh"></i>
</button>
</div>
<mat-paginator [length]="pagination?.totalItems" [pageSize]="pagination?.itemsPerPage"
[pageSizeOptions]="[5, 10, 15]" [pageIndex]="pagination?.currentPage">
</mat-paginator>
</div>
</div>
<!--Boton de Nuevo-->
<div class="toolbar-option">
<button color="default" mat-mini-fab="" class="mat-mini-fab"
matTooltip="{{'btn.new' | translate}}" (click)="create()"
*ngIf="this.resourceAuth['new']">
<span><i class="fa fa-file-o"></i></span>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
\ No newline at end of file
.toolbar-option {
margin-left: 10px;
margin-right: 10px;
}
$fontcolor: #676a6c;
.content {
width: 100%;
display: flex;
padding-right: 0px !important;
.grid-container,
.filter-panel {
.crud-table {
margin-bottom: 0px;
width: 100%;
}
.form {
padding: 10px 20px 10px 20px;
}
}
.filter-panel {
margin-bottom: 10px;
}
}
.grid-ibox-content {
width: 100%;
}
.btn-group {
.btn {
font-size: 10px;
}
}
.td-view {
cursor: auto !important;
}
.mat-row-auth:hover {
background-color: #f8f9fa;
cursor: pointer !important;
}
.spinner-container {
height: 100%;
width: 100%;
padding-top: 50px;
position: fixed;
}
.spinner-container {
height: 100%;
width: 100%;
padding-top: 50px;
position: fixed;
}
.spinner-container mat-spinner {
margin: -10px auto 0 auto;
}
td {
vertical-align: middle !important;
color: $fontcolor;
font-size: 12px;
}
th {
vertical-align: middle !important;
}
tr.mat-header-row {
height: 50px !important;
}
tr.mat-footer-row,
tr.mat-row {
height: 40px !important;
}
.table-toolbar {
right: 10px;
top: 10px;
button {
font-size: 12px;
}
}
.status-button-bar {
button {
font-size: 16px;
}
padding-top: 8px;
padding-left: 15px;
}
.mat-raised-button {
padding: 0px 10px;
}
.icon-centered-button span.mat-button-wrapper {
display: flex;
}
.icon-centered-button mat-icon {
font-size: 15px;
padding-top: 2px;
}
::ng-deep .mat-sort-header-arrow {
visibility: hidden;
}
::ng-deep .mat-sort-header-button {
.mat-icon {
padding-left: 10px;
font-size: 12px;
padding-top: 5px;
}
}
th {
background: rgb(242, 242, 242);
}
tr.example-detail-row {
height: 0 !important;
}
tr.example-element-row:not(.example-expanded-row):hover {
background: #dedede;
cursor: pointer;
}
tr.example-element-row:not(.example-expanded-row):active {
background: #efefef;
}
.example-element-row td {
border-bottom-width: 0;
}
.example-element-detail {
overflow: hidden;
display: flex;
}
.example-detail-row td {
padding-top: 0px;
padding-bottom: 0px;
border: none !important;
background-color: #f2f2f2;
}
i.state {
font-size: 1.3em;
}
i.fa-key.pull-left {
color: rgba(128, 128, 128, 0.33);
margin-right: 6px;
}
//////
table {
width: 100%;
}
tr.mat-header-row {
height: 25px;
}
tr.mat-footer-row,
tr.mat-row {
height: 40px;
}
.button-grid {
margin: 2px 5px;
mat-icon {
padding-top: 2px;
}
}
.btn-header-new {
margin-top: -4px;
}
.btn-grid-filter {
height: 36px;
width: 85px;
padding-left: 0px;
padding-top: 2px;
}
.mat-row:hover {
cursor: pointer;
background-color: #f8f9fa;
}
.spinner-container {
height: 100%;
width: 100%;
padding-top: 50px;
position: fixed;
}
.spinner-container mat-spinner {
margin: -10px auto 0 auto;
}
.mat-raised-button {
padding: 0px 10px;
}
.icon-centered-button span.mat-button-wrapper {
display: flex;
}
.icon-centered-button mat-icon {
font-size: 15px;
padding-top: 2px;
}
.ibox-content {
padding-right: 0px;
}
.content {
width: 100%;
display: flex;
padding-right: 0px !important;
}
.grid-ibox-content {
width: 100%;
}
.avatar {
vertical-align: middle;
width: 35px;
height: 35px;
border-radius: 50%;
}
::ng-deep .mat-menu-panel {
overflow: hidden !important;
}
.th-avatar {
width: 130px;
}
::ng-deep .text-right > .mat-sort-header-container {
justify-content: flex-end !important;
}
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { AgentListComponent } from './agent-list.component';
describe('AgentComponent', () => {
let component: AgentListComponent;
let fixture: ComponentFixture<AgentListComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ AgentListComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(AgentListComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit, ViewChild, ViewContainerRef, Input, AfterViewInit } from '@angular/core';
import { MatPaginator, MatSort } from '@angular/material';
import { ColumnTemplate, DynaDataSource, ConfirmationDialogService, extractRSQL, FieldFilter } from '@xdf/gallery';
import { Pagination, SortField, NotificationType, NotificationService, AuthenticationService } from '@xdf/commons';
import { Router, ActivatedRoute } from '@angular/router';
import { first, tap } from 'rxjs/operators';
import { TagFilter } from '@xdf/gallery/lib/views/gallery/ngx-tags-input/model/tag-filter';
import { TranslateService } from '@ngx-translate/core';
import { AgentService } from '../../service/agent.service';
const columnTemplateArray = [
{
name: 'avatar',
sortable: false,
title: 'agent_avatar',
visible: true,
filtable: true,
style: { width: 'auto' },
type: 'string',
aliasName: null,
queryName: null,
responsive: null,
styles: null,
values: null,
digitsInfo: null,
dateFormat: null,
colStyle: null
},
{
name: 'id',
sortable: true,
title: 'agent_code',
visible: true,
filtable: true,
style: { width: '75px' },
type: 'number',
aliasName: null,
queryName: null,
responsive: null,
styles: null,
values: null,
digitsInfo: null,
dateFormat: null,
colStyle: null
},
{
name: 'name',
sortable: true,
title: 'agent_name',
visible: true,
filtable: true,
style: { width: 'auto' },
type: 'string',
aliasName: null,
queryName: null,
responsive: null,
styles: null,
values: null,
digitsInfo: null,
dateFormat: null,
colStyle: null
},
{
name: 'version',
sortable: true,
title: 'agent_publish_version',
visible: true,
filtable: true,
style: { width: 'auto' },
type: 'string',
aliasName: null,
queryName: null,
responsive: null,
styles: null,
values: null,
digitsInfo: null,
dateFormat: null,
colStyle: null
},
{
name: 'status',
sortable: true,
title: 'agent_status',
visible: true,
filtable: true,
style: { width: 'auto' },
type: 'string',
aliasName: null,
queryName: null,
responsive: null,
styles: null,
values: null,
digitsInfo: null,
dateFormat: null,
colStyle: null
},
{
name: 'countryName',
sortable: true,
title: 'agent_country',
visible: true,
filtable: true,
style: { width: 'auto' },
type: 'string',
aliasName: null,
queryName: null,
responsive: null,
styles: null,
values: null,
digitsInfo: null,
dateFormat: null,
colStyle: null
},
{
name: 'timezone',
sortable: true,
title: 'agent_timezone',
visible: true,
filtable: true,
style: { width: 'auto' },
type: 'string',
aliasName: null,
queryName: null,
responsive: null,
styles: null,
values: null,
digitsInfo: null,
dateFormat: null,
colStyle: null
}
];
const fieldFilters = [
new FieldFilter('agent_code', 'id', 'id', 'number', undefined),
new FieldFilter('agent_name', 'name', 'name', 'string', undefined),
new FieldFilter('agent_status', 'status', 'status', 'valpos', (
{ DP: 'label.deployed', PS: 'label.sync-pending' }
) as any),
];
@Component({
selector: 'byte-agent-list',
templateUrl: './agent-list.component.html',
styleUrls: ['./agent-list.component.scss']
})
export class AgentListComponent implements OnInit, AfterViewInit {
@ViewChild(MatPaginator, { static: false }) paginator: MatPaginator;
@ViewChild(MatSort, { static: false }) sort: MatSort;
sortColumn: string;
sortDirection: string;
statusQuickFilter: string;
pagingSize = 10;
programIdentifier = 'agent';
columnTemplateArray: ColumnTemplate[];
dataSource: DynaDataSource;
displayedColumns = new Array<string>();
fieldFilters: Array<FieldFilter> = fieldFilters;
filterTags = [];
pagination: Pagination;
public resourceAuth: any;
constructor(
private router: Router,
private route: ActivatedRoute,
private agentService: AgentService,
private notificationService: NotificationService,
private translateService: TranslateService,
protected confirmationDialogService: ConfirmationDialogService,
private authenticationService: AuthenticationService,
protected vcRef: ViewContainerRef
) { }
ngAfterViewInit(): void {
this.sort.sortChange.subscribe(() => {
if (!this.sort.disabled && this.sort.active) {
this.pagination.sortFields = new Array();
const sortField: SortField = new SortField();
sortField.direction = this.sortDirection = this.sort.direction;
sortField.field = this.sortColumn = this.sort.active;
this.pagination.sortFields.push(sortField);
}
this.paginator.pageIndex = 0;
this.dataSource.load(this.pagination);
});
this.paginator.page
.pipe(
tap(() => {
this.pagination.currentPage = this.paginator.pageIndex;
this.pagination.itemsPerPage = this.paginator.pageSize;
this.dataSource.load(this.pagination);
})
)
.subscribe();
}
ngOnInit() {
this.sortColumn = 'id';
this.sortDirection = 'asc';
const authList = this.route.snapshot.paramMap['authorization'];
if (authList) {
this.resourceAuth = new Object();
authList.forEach(option => {
this.resourceAuth[option] = true;
});
}
this.columnTemplateArray = columnTemplateArray;
this.dataSource = new DynaDataSource(this.agentService);
const previousState = JSON.parse(localStorage.getItem(this.programIdentifier + '-state'));
if (previousState) {
const PAG = 'pagination';
const FILTERS = 'filtersTags';
this.pagination = previousState[PAG];
this.filterTags = previousState[FILTERS];
localStorage.removeItem(this.programIdentifier + '-state');
} else {
// Paginación
this.pagination = new Pagination();
this.pagination.currentPage = 0;
this.pagination.itemsPerPage = this.pagingSize;
this.pagination.filterExpression = 'id != 0';
// Ordenación por defecto
if (this.sortColumn && this.sortDirection) {
this.pagination.sortFields = new Array();
const sortField: SortField = new SortField();
sortField.direction = this.sortDirection;
sortField.field = this.sortColumn;
this.pagination.sortFields.push(sortField);
}
}
// calculando la columnas a pintar
this.columnTemplateArray.forEach(column => {
this.displayedColumns.push(column.name);
});
this.displayedColumns.push('actions');
this.dataSource.load(this.pagination);
}
onFilter(tags: Array<TagFilter>) {
this.filterTags = tags;
this.pagination.currentPage = 0;
// let tagsTemp = tags.slice();
const tagsTemp = tags.map(a => Object.assign({}, a));
for (let i = 0; i < tagsTemp.length; i++) {
if (tagsTemp[i].column !== 'id') {
tagsTemp[i].value = tags[i].value;
}
}
this.pagination.filterExpression = extractRSQL(tagsTemp);
if (this.pagination.filterExpression === null || this.pagination.filterExpression === undefined) {
this.pagination.filterExpression = 'id != 0';
}
this.dataSource.load(this.pagination);
}
onRefresh() {
this.dataSource.load(this.pagination);
}
delete(item) {
this.confirmationDialogService.loadComponent(
this.vcRef,
'title.delete.confirmation',
'message.delete.confirmation').subscribe(result => {
if (result) {
this.agentService.delete(item.id).subscribe((rslt: any) => {
if (rslt.statusCode !== 200) {
this.notificationService.showMessage(
this.translateService.instant(rslt.message), this.translateService.instant('label.error.message.title'),
NotificationType.error);
} else {
this.dataSource.load(this.pagination);
}
}
);
}
});
}
edit(item) {
this.router.navigate(['/configuration/agent/detail/edit/' + item.id]);
}
synchronize(item) {
const user = (this.authenticationService.currentUserValue ? this.authenticationService.currentUserValue.username : 'admin');
this.agentService.synchronize(item.id, user).pipe(first()).subscribe(() => {
this.notificationService.showMessage(this.translateService.instant('agent.synchronize.success'), undefined, NotificationType.success);
this.onRefresh();
});
}
view(item) {
this.router.navigate(['/configuration/agent/detail/view/' + item.id]);
}
create() {
this.router.navigate(['/configuration/agent/detail/new']);
}
}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-lg-12">
<div class="ibox float-e-margins">
<!-- <div class="ibox-title">
<h5>{{'reconciliation.title' | translate}}</h5>
</div> -->
<div class="ibox-content">
<mat-horizontal-stepper labelPosition="bottom" #stepper [linear]="true">
<mat-step state="info">
<ng-template matStepLabel>
<span class="font-bold">{{'label.general-information.title' | translate}}</span>
<div class="font-size-description" [title]="'label.general-information.description' | translate">
{{'label.general-information.description' | translate}}
</div>
</ng-template>
<byte-ca-general-information [stepper]="stepper" (nextPage)="updateDirtyStatus($event)"></byte-ca-general-information>
</mat-step>
<mat-step state="questions">
<ng-template matStepLabel>
<span class="font-bold">{{'label.questions.title' | translate}}</span>
<div class="font-size-description" [title]="'label.questions.description' | translate">
{{'label.questions.description' | translate}}
</div>
</ng-template>
<byte-ca-frequent-questions [stepper]="stepper" (nextPage)="updateDirtyStatus($event)"></byte-ca-frequent-questions>
</mat-step>
<mat-step state="deployment-channels">
<ng-template matStepLabel>
<span class="font-bold">{{'label.deployment-channels.title' | translate}}</span>
<div class="font-size-description" [title]="'label.deployment-channels.description' | translate">
{{'label.deployment-channels.description' | translate}}
</div>
</ng-template>
<byte-ca-deployment-channels [stepper]="stepper" [changes]="generalDirty"></byte-ca-deployment-channels>
</mat-step>
<!--
<mat-step state="summary">
<ng-template matStepLabel>
<span class="font-bold">{{'label.summary.title' | translate}}</span>
<div class="font-size-description" [title]="'label.summary.description' | translate">
{{'label.summary.description' | translate}}
</div>
</ng-template>
<byte-es-summary [stepper]="stepper"></byte-es-summary>
</mat-step>
-->
<ng-template matStepperIcon="info">
<mat-icon>info</mat-icon>
</ng-template>
<ng-template matStepperIcon="questions">
<mat-icon>dns</mat-icon>
</ng-template>
<ng-template matStepperIcon="deployment-channels">
<mat-icon>chat</mat-icon>
</ng-template>
<!--
<ng-template matStepperIcon="summary">
<mat-icon>done_all</mat-icon>
</ng-template>
-->
</mat-horizontal-stepper>
</div>
</div>
</div>
</div>
</div>
::ng-deep .info-block {
text-align: center;
vertical-align: middle;
line-height: 150px;
min-height: 300px;
}
::ng-deep .footer-bar {
margin: 0 10px 10px;
}
::ng-deep .border-all {
border: solid 1px #d0c9c9ab;
}
::ng-deep .panel-viewer-wrapper {
border: 1px solid rgba(0, 0, 0, 0.03);
box-shadow: 0 2px 1px -1px rgba(0, 0, 0, 0.2), 0 1px 1px 0 rgba(0, 0, 0, 0.14), 0 1px 3px 0 rgba(0, 0, 0, 0.12);
margin: 5px 5px 10px;
}
.font-size-description {
white-space: normal;
font-size: 11px;
}
::ng-deep .mat-step-header[aria-selected="true"] {
/*background: #c3ccff !important;*/
background: #c3ccff9e !important;
border: solid 1px #c3ccff80;
border-radius: 9px !important;
}
::ng-deep .mat-horizontal-stepper-header {
pointer-events: none !important;
}
::ng-deep .mat-card {
border-left: solid 0px #3f51b5;
transition: border-left 0.125s ease-in !important;
&.active {
border-left: solid 5px #3f51b5;
}
}
::ng-deep .panel-viewer-title > .mat-icon {
height: 0px;
width: 15px;
vertical-align: sub;
}
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { AgentComponent } from './agent.component';
describe('AgentComponent', () => {
let component: AgentComponent;
let fixture: ComponentFixture<AgentComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ AgentComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(AgentComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit, ViewChild, Input, AfterContentChecked, AfterViewInit } from '@angular/core';
import { ChangeDetectionStrategy, AfterContentInit, ViewContainerRef } from '@angular/core';
import { FormGroup, Validators, FormBuilder } from '@angular/forms';
import { CaGeneralInformationComponent } from '../components/ca-general-information/ca-general-information.component';
import { STEPPER_GLOBAL_OPTIONS } from '@angular/cdk/stepper';
import { ActivatedRoute, Router } from '@angular/router';
import { NavigationService } from '@xdf/layouts';
import { IDirty } from '@xdf/gallery';
import { CaFrequentQuestionsComponent } from '../components/ca-frequent-questions/ca-frequent-questions.component';
import { MatStepper } from '@angular/material';
import { CaDeploymentChannelsComponent } from '../components/ca-deployment-channels/ca-deployment-channels.component';
@Component({
selector: 'byte-agent',
templateUrl: './agent.component.html',
styleUrls: ['./agent.component.scss'],
providers: [{
provide: STEPPER_GLOBAL_OPTIONS, useValue: { displayDefaultIndicatorType: false }
}]
})
export class AgentComponent implements OnInit, IDirty {
@ViewChild(CaGeneralInformationComponent, { static: true })
generalInformationComponent: CaGeneralInformationComponent;
@ViewChild(CaFrequentQuestionsComponent, { static: true })
frequentQuestionsComponent: CaFrequentQuestionsComponent;
@ViewChild(CaDeploymentChannelsComponent, { static: true })
deploymentChannelsComponent: CaDeploymentChannelsComponent;
@ViewChild('stepper', { static: true }) stepper: MatStepper;
agentDetail: any;
isLinear = true;
isNew = true;
resourceAuth: any;
// dirty acumulado
generalDirty = false;
constructor(
private vcRef: ViewContainerRef,
private activatedRoute: ActivatedRoute,
private backService: NavigationService,
private router: Router
) {
this.backService.backAnnounced$.subscribe(data => {
this.router.navigate(['/configuration/agent']);
});
}
isDirty(): boolean {
let dirty = false;
dirty = this.generalInformationComponent.isDirty()
|| this.frequentQuestionsComponent.isDirty();
if (dirty) {
dirty = this.deploymentChannelsComponent.isDirty();
}
return dirty;
}
getRef(): ViewContainerRef {
return this.vcRef;
}
ngOnInit() {
this.stepper.selectedIndex = 0;
const authList = this.activatedRoute.snapshot.paramMap['authorization'];
this.resourceAuth = new Object();
if (authList) {
authList.forEach(option => {
this.resourceAuth[option] = true;
});
}
console.log(this.resourceAuth);
this.isNew = this.activatedRoute.snapshot.data.mode === 'create';
if (this.isNew) {
this.agentDetail = {
};
} else {
this.agentDetail = this.activatedRoute.snapshot.data.agentDetail;
}
this.generalInformationComponent.buildForm(this.agentDetail);
this.frequentQuestionsComponent.buildForm(this.agentDetail);
this.deploymentChannelsComponent.buildForm(this.agentDetail);
}
updateDirtyStatus(event: boolean) {
this.generalDirty = this.generalDirty || event;
}
}
<div class="title_section divider">
<div class="hidden-xs" *ngIf="applicationSettings?.logoBase64">
<img class="logo_header_popup"
src="data:image/{{applicationSettings.tipo}};base64,{{applicationSettings.logoBase64}}" />
</div>
<div class="title_header_popup">
<h2 mat-dialog-title>
<span> {{'label.deployment-channels.configuration' | translate}} </span>
</h2>
</div>
</div>
<mat-dialog-content>
<h4>
{{'label.deployment-channels.configuration.description' | translate}}
<!-- -->
</h4>
<div>
<ng-container *ngFor="let channel of channels">
<mat-card class="channel-card" (click)="selectChannel(channel)"
[ngClass]="{ 'active': selectedChannel === channel}" *ngIf="!channel.disabled">
<mat-card-header>
<img [src]="channel.image" mat-card-avatar>
<mat-card-title>{{channel.name}}</mat-card-title>
</mat-card-header>
</mat-card>
</ng-container>
</div>
</mat-dialog-content>
<mat-dialog-actions align="end">
<button mat-button mat-dialog-close>{{'btn.cancel' | translate}}</button>
<button mat-button (click)="ok()" cdkFocusInitial
[disabled]="!selectedChannel">{{'btn.accept' | translate}}</button>
</mat-dialog-actions>
\ No newline at end of file
.icon {
vertical-align: middle;
width: 20px;
height: 20px;
border-radius: 50%;
margin-right: 10px;
}
::ng-deep .mat-card-header .mat-card-title {
margin-bottom: 12px;
margin-top: 10px;
}
.channel-card {
cursor: pointer;
margin-bottom: 8px;
transition: border-left 0.125s ease-in;
border-left: solid 0px #3f51b5;
&.active {
border-left: solid 5px #3F51B5 !important;
}
}
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { CaDeploymentChannelsModalComponent } from './ca-deployment-channels-modal.component';
describe('CaDeploymentChannelsModalComponent', () => {
let component: CaDeploymentChannelsModalComponent;
let fixture: ComponentFixture<CaDeploymentChannelsModalComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ CaDeploymentChannelsModalComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(CaDeploymentChannelsModalComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit, Inject } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
@Component({
selector: 'byte-ca-deployment-channels-modal',
templateUrl: './ca-deployment-channels-modal.component.html',
styleUrls: ['./ca-deployment-channels-modal.component.scss']
})
export class CaDeploymentChannelsModalComponent implements OnInit {
channels: Array<any>;
selectedChannel: any;
applicationSettings: any;
constructor(
public dialogRef: MatDialogRef<CaDeploymentChannelsModalComponent>,
@Inject(MAT_DIALOG_DATA) public data: any) {
this.channels = data.channels;
}
ngOnInit() {
}
ok() {
this.dialogRef.close(this.selectedChannel);
}
selectChannel(channel: any) {
this.selectedChannel = channel;
}
}
<div class="panel-viewer-wrapper">
<div class="panel-viewer-title">
<mat-icon>chat</mat-icon>
{{'label.deployment-channels.title' | translate}}
</div>
<div class="panel-viewer-body">
<!-- <div class="row pb-2 text-center">
<div class="col-12">
<h1>{{'label.deployment-channels' | translate}}</h1>
</div>
</div> -->
<div class="row pb-2 justify-content-center">
<div class="col-md-6 col-sm-12">
<!-- <div class="alert alert-warning" *ngIf="!viewMode">
<i class="fa fa-warning"></i>&nbsp;&nbsp;<span
[innerHTML]="'label.summary.warning' | translate"></span>
</div> -->
<h4 class="mt-3">
<!-- <button class="pull-right" mat-icon-button (click)="addChannel()" *ngIf="!viewMode && isAvaliableChannels">
<i class="fa fa-plus"></i>
</button> -->
<button type="button" class="btn btn-outline-primary btn-sm pull-right" (click)="addChannel()"
*ngIf="!viewMode && (deploymentChannels && deploymentChannels.length) && isAvaliableChannels">
<i class="fa fa-file"></i>
<span class="visible-md-inline visible-lg-inline visible-xl-inline">
{{'Añadir canal' | translate}}
</span>
</button>
<b>{{'label.channels' | translate}}</b>
</h4>
<mat-accordion *ngIf="!isLoadingDataChannel">
<form [formGroup]="formGroup" novalidate autocomplete="off">
<mat-expansion-panel *ngFor="let channel of deploymentChannels; let i = index"
[expanded]="step === i" (opened)="setStep(i)">
<mat-expansion-panel-header class="right-aligned-header" [collapsedHeight]="'60px'">
<mat-panel-title>
<img [src]="channel.channelImage" class="icon">
<div>
<span style="margin-right: 8px;">{{ channel.channelName }}</span>
<ng-container *ngIf="channel?.suggestTitle && channel?.suggestDetail">
<ng-template #popContent><div [innerHTML]="channel?.suggestDetail"></div></ng-template>
<ng-template #popoverTitle><div [innerHTML]="channel?.suggestTitle"></div></ng-template>
<i class="fa fa-info-circle" placement="top" style="color: rgba(0, 0, 0, 0.54);"
[ngbPopover]="popContent"
[popoverTitle]="popoverTitle" triggers="hover"></i>
</ng-container>
<!-- <small class="text-muted">{{ channel.name }}</small> -->
</div>
</mat-panel-title>
<mat-panel-description>
<!-- <label class="label label-success"
*ngIf="channel.active">{{'label.active' | translate}}</label>
<label class="label label-default"
*ngIf="!channel.active">{{'label.inactive' | translate}}</label> -->
<mat-slide-toggle [(ngModel)]="channel.active" [disabled]="viewMode"
style="margin-top: 0;" [ngModelOptions]="{standalone: true}" color="primary"
(click)="$event.stopPropagation();">
<span *ngIf="channel.active">{{'label.active' | translate}}</span>
<span *ngIf="!channel.active">{{'label.inactive' | translate}}</span>
</mat-slide-toggle>
</mat-panel-description>
</mat-expansion-panel-header>
<div formGroupName="{{channel.channelName}}">
<div class="row">
<!-- <div class="col-6">
<mat-form-field class="amd-form-control">
<mat-label>{{'label.name' | translate}}</mat-label>
<input matInput maxlength="80" [type]="text" required="true"
[disabled]="viewMode" [(ngModel)]="channel.name"
[ngModelOptions]="{standalone: true}">
</mat-form-field>
</div> -->
<!-- <div class="col-6">
<mat-slide-toggle [(ngModel)]="channel.active" [disabled]="viewMode"
[ngModelOptions]="{standalone: true}" color="primary">
<span *ngIf="channel.active">{{'label.active' | translate}}</span>
<span *ngIf="!channel.active">{{'label.inactive' | translate}}</span>
</mat-slide-toggle>
</div> -->
</div>
<div class="row" *ngFor="let field of channel.parameters">
<div class="col-12">
<mat-form-field class="amd-form-control">
<mat-label>{{field.label | dynamicTranslate: {param: field.traductions } }}:
</mat-label>
<!--
[pattern]="field.regex"
-->
<input matInput [maxlength]="field.maxlength"
[disabled]="viewMode"
[type]="(field.type ? field.type : 'text')"
[required]="field.required"
[pattern]="field?.regex" [formControlName]="field.channelParamName">
<!-- <mat-error *ngIf="fieldForm.errors?.pattern">
{{ 'Formato inválido' | translate }}</mat-error> -->
<mat-error *ngFor="let error of getErrors(channel.channelName, field.channelParamName, field.label)">{{ 'message.error.' + error.name | translate : error.prop}}
</mat-error>
</mat-form-field>
</div>
</div>
</div>
<mat-action-row *ngIf="!viewMode">
<button mat-button color="warn" (click)="deleteChannel(i)">
<i
class="fa fa-trash"></i><span>&nbsp;&nbsp;{{'label.delete-channel' | translate}}</span>
</button>
</mat-action-row>
</mat-expansion-panel>
</form>
</mat-accordion>
<div *ngIf="!(deploymentChannels && deploymentChannels.length)" class="border-all text-center">
<button type="button" class="btn btn-outline-primary btn-sm" (click)="addChannel()"
*ngIf="!viewMode && isAvaliableChannels">
<i class="fa fa-file"></i>
<span class="visible-md-inline visible-lg-inline visible-xl-inline">
{{'Añadir canal' | translate}}
</span>
</button>
<!-- {{'label.delete-channel' | translate}} -->
</div>
</div>
</div>
</div>
<div class="footer-bar">
<div class="row">
<div class="col-12">
<button mat-stroked-button matStepperPrevious class="pull-left">
<i class="fa fa-chevron-left"></i>
<span class="pl-1">{{'btn.previous' | translate}}</span>
</button>
<button mat-stroked-button color="primary" type="submit" (click)="save()" class="pull-right"
*ngIf="!viewMode">
<span class="pr-1">{{'btn.save' | translate}}</span>
<i class="fa fa-chevron-right"></i>
</button>
<button mat-stroked-button (click)="exit()" class="pull-right" *ngIf="viewMode">
<span class="pr-1">{{'application.options.exit' | translate}}</span>
<i class="fa fa-logout"></i>
</button>
</div>
</div>
</div>
</div>
\ No newline at end of file
.icon {
vertical-align: middle;
width: 20px;
height: 20px;
border-radius: 50%;
margin-right: 10px;
}
::ng-deep .right-aligned-header > .mat-content {
justify-content: space-between;
}
::ng-deep .mat-content > mat-panel-title {
flex: 0 0 auto;
}
::ng-deep .mat-content > mat-panel-description {
flex: 0 0 auto;
}
::ng-deep .mat-expansion-indicator {
margin-bottom: 10px;
}
::ng-deep mat-slide-toggle {
margin-top: 14px;
}
.border-all.text-center {
padding: 50px;
border-radius: 4px;
}
.label.label-success {
background-color: #3f51b5;
}
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { CaDeploymentChannelsComponent } from './ca-deployment-channels.component';
describe('CaDeploymentChannelsComponent', () => {
let component: CaDeploymentChannelsComponent;
let fixture: ComponentFixture<CaDeploymentChannelsComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ CaDeploymentChannelsComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(CaDeploymentChannelsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit, Input, ViewChild } from '@angular/core';
import { MatStepper, MatDialog, ErrorStateMatcher, MatInput } from '@angular/material';
import { CaDeploymentChannelsModalComponent } from '../ca-deployment-channels-modal/ca-deployment-channels-modal.component';
import { AgentService } from '../../../service/agent.service';
import { first } from 'rxjs/operators';
import { NotificationType, NotificationService } from '@xdf/commons';
import { TranslateService } from '@ngx-translate/core';
import { Router, ActivatedRoute } from '@angular/router';
import { Form, FormArray, FormControl, FormGroup, FormGroupDirective, NgForm, Validators } from '@angular/forms';
import { ValidatorUtils } from '@xdf/gallery';
@Component({
selector: 'byte-ca-deployment-channels',
templateUrl: './ca-deployment-channels.component.html',
styleUrls: ['./ca-deployment-channels.component.scss']
})
export class CaDeploymentChannelsComponent implements OnInit {
@Input()
stepper: MatStepper;
@Input()
changes = false;
@ViewChild('fieldForm', {static: false})
fieldFormList: any;
agentDetail: any;
channels: Array<any>;
deploymentChannels: Array<any> = new Array<any>();
dirty = true;
step = -1;
viewMode = false;
isAvaliableChannels = false;
mode = 'new';
detailText = 'Detail';
titleText = 'Titulo';
isLoadingDataChannel = true;
formGroup: FormGroup;
constructor(
private activatedRoute: ActivatedRoute,
private agentService: AgentService,
private matDialog: MatDialog,
private translateService: TranslateService,
private notificationService: NotificationService,
private router: Router,
private validatorUtils: ValidatorUtils
) {
this.formGroup = new FormGroup({});
this.mode = this.activatedRoute.snapshot.data.mode;
this.viewMode = this.mode === 'view';
}
ngOnInit() {
this.agentService.getChannelDatForWizard().pipe(first()).subscribe((result: any) => {
if (result) {
this.channels = result;
} else {
this.channels = [];
}
this.buildList();
this.buildAvaliableChannels();
this.isLoadingDataChannel = false;
}, error => {
this.isLoadingDataChannel = false;
});
}
buildForm(agentDetail: any) {
this.agentDetail = agentDetail;
this.deploymentChannels = (agentDetail.deploymentChannels || []);
this.buildList();
}
buildList() {
if (this.channels && this.deploymentChannels) {
for (const deploymentChannel of this.deploymentChannels) {
for (const channel of this.channels) {
if (channel.id === deploymentChannel.channelId) {
deploymentChannel.channelName = channel.name;
deploymentChannel.channelImage = channel.image;
deploymentChannel.active = (deploymentChannel.status === 'AC');
deploymentChannel.suggestTitle = channel.suggestTitle;
deploymentChannel.suggestDetail = channel.suggestDetail;
this.formGroup.addControl(channel.name, new FormGroup({}));
for (const parameter of deploymentChannel.parameters) {
for (const field of channel.parameters) {
if (parameter.channelParamName === field.name) {
const formArray = this.formGroup.controls[channel.name] as FormGroup;
parameter.label = field.label;
parameter.type = field.type;
parameter.required = field.required;
parameter.traductions = field.traductions;
parameter.maxlength = field.maxlength;
parameter.regex = field.regex;
formArray.addControl(field.name, new FormControl('', field.required ? [Validators.required] : []));
break;
}
}
}
break;
}
}
}
}
console.log(this.formGroup);
}
buildAvaliableChannels() {
this.isAvaliableChannels = false;
mainLoop: for (const channel of this.channels) {
channel.disabled = false;
for (const deploymentChannel of this.deploymentChannels) {
if (channel.id === deploymentChannel.channelId) {
channel.disabled = true;
continue mainLoop;
}
}
if (!channel.disabled) {
this.isAvaliableChannels = true;
}
}
}
addChannel() {
const dialog = this.matDialog.open(CaDeploymentChannelsModalComponent, {
width: '500px',
data: {
message: '',
channels: this.channels
}
});
dialog.afterClosed().subscribe(result => {
if (result) {
const selectedChannel = { ...result };
selectedChannel.channelId = selectedChannel.id;
selectedChannel.channelName = selectedChannel.name;
selectedChannel.channelImage = selectedChannel.image;
selectedChannel.id = undefined;
selectedChannel.name = undefined;
this.deploymentChannels.push(selectedChannel);
this.setStep(this.deploymentChannels.length - 1);
this.buildAvaliableChannels();
}
});
}
deleteChannel(i) {
this.deploymentChannels.splice(i, 1);
this.buildAvaliableChannels();
}
exit() {
this.dirty = false;
this.router.navigate(['/configuration/agent']);
}
isDirty() {
return this.dirty;
}
save() {
const isValid: boolean = this.validate();
if (!isValid) {
if (this.fieldFormList && this.fieldFormList.control) {
this.fieldFormList.control.markAsTouched();
}
return;
}
const agent: any = {};
agent.id = this.agentDetail.id;
agent.name = this.agentDetail.name;
agent.description = this.agentDetail.description;
agent.version = this.agentDetail.version;
agent.countryId = this.agentDetail.countryId;
agent.timezone = this.agentDetail.timezone;
agent.avatar = this.agentDetail.avatar;
agent.language = this.agentDetail.language;
agent.type = this.agentDetail.type;
agent.status = this.agentDetail.status;
agent.deploymentChannels = [];
for (const deploymentChannel of this.deploymentChannels) {
const deploymentChannelTmp: any = {};
deploymentChannelTmp.id = deploymentChannel.id;
deploymentChannelTmp.name = deploymentChannel.name;
deploymentChannelTmp.status = deploymentChannel.active ? 'AC' : 'IN';
deploymentChannelTmp.channelId = deploymentChannel.channelId;
deploymentChannelTmp.parameters = [];
for (const parameter of deploymentChannel.parameters) {
const parameterTmp: any = {};
parameterTmp.id = parameter.id;
parameterTmp.value = parameter.value;
parameterTmp.channelParamName = parameter.channelParamName ? parameter.channelParamName : parameter.name;
deploymentChannelTmp.parameters.push(parameterTmp);
}
agent.deploymentChannels.push(deploymentChannelTmp);
}
agent.frequentQuestions = this.agentDetail.frequentQuestions;
this.agentService.update(agent.id, agent).pipe(first()).subscribe(() => {
if (agent.id) {
this.dirty = false;
this.notificationService.showMessage(this.translateService.instant('agent.edit.success'), null, NotificationType.success);
this.router.navigate(['/configuration/agent']);
} else {
this.dirty = false;
this.notificationService.showMessage(this.translateService.instant('agent.create.success'), null, NotificationType.success);
this.router.navigate(['/configuration/agent']);
}
});
}
onChange(fieldForm) {
if (!fieldForm.control.touched) {
fieldForm.control.markAsTouched();
}
}
setStep(step) {
this.step = step;
}
validate(): boolean {
let valid = true;
mainLoop: for (const deploymentChannel of this.deploymentChannels) {
const deploymentChannelTmp: any = {};
// if (!deploymentChannel.name) {
// valid = false;
// break;
// }
for (const parameter of deploymentChannel.parameters) {
parameter.error = false;
if (!parameter.value) {
valid = false;
break mainLoop;
}
if (parameter.regex) {
const regex = new RegExp(parameter.regex);
if (!regex.test(parameter.value)) {
parameter.error = true;
valid = false;
break mainLoop;
}
}
}
}
if (!valid) {
this.notificationService.showMessage(this.translateService.instant('error.message.complete-form'), undefined, NotificationType.error);
}
return valid;
}
getErrors(channelName: string, name: string, placeholder: string) {
const channelFormGroup = (this.formGroup.controls[channelName] as FormGroup);
return channelFormGroup ? this.validatorUtils.getErrors(channelFormGroup.controls[name] as FormControl, name, placeholder) : [];
}
}
<div class="title_section divider">
<div class="hidden-xs" *ngIf="applicationSettings?.logoBase64">
<img class="logo_header_popup"
src="data:image/{{applicationSettings.tipo}};base64,{{applicationSettings.logoBase64}}" />
</div>
<div class="title_header_popup">
<h2 mat-dialog-title>
<i class="fa fa-exclamation-triangle" [hidden]="!fileErrorDetail"></i><span> {{'label.file-upload.title' | translate}} </span>
</h2>
</div>
</div>
<mat-dialog-content class="none-overflow" [hidden]="fileErrorDetail">
<h4>
{{'label.file-upload.description' | translate}}
</h4>
<form [formGroup]="formGroup" autocomplete="off">
<div class="row pt-2">
<div class="col-12">
<mat-form-field class="amd-form-control">
<input matInput [placeholder]="'label.description' | translate" formControlName="description"
maxlength="50" required>
</mat-form-field>
</div>
</div>
<div class="row pt-2" *ngIf="createMode">
<div class="col-12">
<mat-form-field class="amd-form-control">
<ngx-mat-file-input formControlName="file" [placeholder]="'label.file' | translate"
[accept]="'.xls,.xlsx'" required (change)="uploadFile($event.target.files)">
</ngx-mat-file-input>
<mat-icon matSuffix>folder</mat-icon>
</mat-form-field>
</div>
</div>
<div class="row pt-2" *ngIf="fileErrorDetail">
<div class="col-12">
<h4>
<b>Detalle de error</b>
</h4>
</div>
<div class="col-12">
<div class="example-container mat-elevation-z8">
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
<!-- Position Column -->
<ng-container [matColumnDef]="column" *ngFor="let column of displayedColumns">
<th mat-header-cell *matHeaderCellDef> {{ 'header.' + column | translate}} </th>
<td mat-cell *matCellDef="let element"> {{element[column] | translate}}</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
</div>
</div>
<div class="row pt-2" *ngIf="!createMode">
<div class="col-12">
<mat-form-field class="amd-form-control">
<input matInput [placeholder]="'label.file' | translate" formControlName="filename" required>
<mat-icon matSuffix [matTooltip]="'label.file.tooltip' | translate" matTooltipPosition="above">
help_icon
</mat-icon>
</mat-form-field>
</div>
</div>
</form>
</mat-dialog-content>
<mat-dialog-content class="none-overflow" [hidden]="!fileErrorDetail">
<h4>
{{'label.file-upload.error.description' | translate}}
</h4>
<div class="row pt-2" *ngIf="fileErrorDetail">
<!-- <div class="col-12">
<h4>
<b>{{'label.file-upload.error.subtitle' | translate}}</b>
</h4>
</div> -->
<div class="col-12">
<div class="example-container mat-elevation-z8">
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
<!-- Position Column -->
<ng-container [matColumnDef]="column" *ngFor="let column of displayedColumns">
<th mat-header-cell *matHeaderCellDef> {{ 'header.' + column | translate}} </th>
<td mat-cell *matCellDef="let element"> {{element[column] | translate}}</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
</div>
</div>
</mat-dialog-content>
<!-- <mat-dialog-actions align="end">
<button mat-button mat-dialog-close>{{'btn.cancel' | translate}}</button>
<button mat-button (click)="retry()" *ngIf="fileErrorDetail">{{'btn.retry' | translate}}</button>
<button mat-button (click)="ok()" cdkFocusInitial *ngIf="!fileErrorDetail"
[disabled]="formGroup.invalid || !enabledOK">{{'btn.accept' | translate}}</button>
</mat-dialog-actions> -->
<div mat-dialog-actions class="border-top">
<button mat-button mat-dialog-close>{{'btn.cancel' | translate}}</button>
<button mat-button (click)="retry()" *ngIf="fileErrorDetail">{{'btn.retry' | translate}}</button>
<button mat-button (click)="ok()" cdkFocusInitial *ngIf="!fileErrorDetail"
[disabled]="formGroup.invalid || !enabledOK">{{'btn.accept' | translate}}</button>
</div>
\ No newline at end of file
.example-container {
max-height: 200px;
overflow: auto;
margin-bottom: 10px
}
table {
width: 100%;
}
.none-overflow{
overflow: hidden;
}
.title_header_popup {
i {
font-size: 28px;
padding-right: 20px;
color: red;
}
}
\ No newline at end of file
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { CaFileUploadModalComponent } from './ca-file-upload-modal.component';
describe('CaFileUploadModalComponent', () => {
let component: CaFileUploadModalComponent;
let fixture: ComponentFixture<CaFileUploadModalComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ CaFileUploadModalComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(CaFileUploadModalComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit, Inject } from '@angular/core';
import { FormGroup, FormBuilder, FormControl, Validators } from '@angular/forms';
import { HttpEventType, HttpErrorResponse } from '@angular/common/http';
import { of } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
import { AgentService } from '../../../service/agent.service';
import { MatDialogRef, MatTableDataSource, MAT_DIALOG_DATA } from '@angular/material';
import { NotificationService, NotificationType } from '@xdf/commons';
import { TranslateService } from '@ngx-translate/core';
export class FileUploadModel {
id: number;
uuid: string;
filename: string;
status: string;
user: string;
uploadDate: string;
description: string;
}
@Component({
selector: 'byte-ca-file-upload-modal',
templateUrl: './ca-file-upload-modal.component.html',
styleUrls: ['./ca-file-upload-modal.component.scss']
})
export class CaFileUploadModalComponent implements OnInit {
formGroup: FormGroup;
accept = '.xls,.xlsx';
enabledOK = false;
createMode = true;
fileInfo = new FileUploadModel();
fileErrorDetail: any;
dataSource = new MatTableDataSource([]);
displayedColumns: string[] = [];
applicationSettings: any;
constructor(
private formBuilder: FormBuilder,
private agentService: AgentService,
private notificationService: NotificationService,
private translateService: TranslateService,
public dialogRef: MatDialogRef<CaFileUploadModalComponent>,
@Inject(MAT_DIALOG_DATA) public data: any
) {
this.formGroup = this.formBuilder.group({
description: new FormControl({ value: '', disabled: false }),
file: new FormControl({ value: '', disabled: false }),
filename: new FormControl({ value: '', disabled: true })
});
if (data) {
this.fileInfo = data;
this.formGroup.controls.description.setValue(this.fileInfo.description);
this.formGroup.controls.filename.setValue(this.fileInfo.filename);
this.createMode = false;
this.enabledOK = true;
}
}
ngOnInit() {
}
buildErrorDetail(status, detail) {
this.fileErrorDetail = undefined;
if ('CONTENT_ERROR' === status) {
this.displayedColumns = ['line', 'type', 'value'];
if (detail) {
const fileErrorDetailTemp = [];
for (const line of Object.keys(detail)) {
const object = detail[line];
const type = Object.keys(object)[0];
fileErrorDetailTemp.push({
line,
type,
value: object[type],
});
}
if (fileErrorDetailTemp) {
this.fileErrorDetail = fileErrorDetailTemp;
this.dataSource.data = fileErrorDetailTemp;
}
}
} else if ('HEADER_ERROR' === status) {
this.displayedColumns = ['header', 'value'];
if (detail) {
const fileErrorDetailTemp = [];
for (const header of Object.keys(detail)) {
const value = detail[header];
fileErrorDetailTemp.push({
header,
value,
});
}
if (fileErrorDetailTemp) {
this.fileErrorDetail = fileErrorDetailTemp;
this.dataSource.data = fileErrorDetailTemp;
}
}
} else {
this.fileErrorDetail = undefined;
}
}
retry() {
this.fileErrorDetail = undefined;
}
uploadFile(event) {
for (const i in event) {
if (event[i] instanceof File) {
const reader = new FileReader();
reader.onload = () => {
// this.formGroup.controls['imageAvatar'].setValue(reader.result as string);
};
reader.readAsDataURL(event[i]);
const fileSelected = {
data: event[i],
state: 'in',
inProgress: false,
progress: 0,
canRetry: false
};
this.validateFile(fileSelected);
}
}
}
validateFile(file) {
const formData = new FormData();
formData.append('file', file.data);
file.inProgress = true;
this.enabledOK = false;
this.agentService.upload(formData).pipe(
map(event => {
switch (event.type) {
case HttpEventType.UploadProgress:
file.progress = Math.round(event.loaded * 100 / event.total);
break;
case HttpEventType.Response:
return event;
}
}),
catchError((error: HttpErrorResponse) => {
file.inProgress = false;
return of(`${file.data.name} upload failed.`);
})
).subscribe((event: any) => {
if (typeof (event) === 'object') {
this.fileErrorDetail = undefined;
this.enabledOK = false;
const info = event.body;
this.fileInfo = new FileUploadModel();
if (info) {
const status = info.fileValidationResult.status;
if ('OK' === status) {
this.fileInfo.id = info.id;
this.fileInfo.description = this.formGroup.controls.description.value;
this.fileInfo.uuid = info.uuid;
this.fileInfo.filename = info.fileName;
this.fileInfo.status = info.status;
this.fileInfo.user = info.user;
this.fileInfo.uploadDate = info.uploadDate;
this.enabledOK = true;
this.fileErrorDetail = undefined;
} else if ('INCOMPATIBLE_EXTENSION' === status) {
this.formGroup.controls.file.setValue(null);
const message = 'label.file.incompatible.extension';
this.enabledOK = false;
this.fileErrorDetail = undefined;
this.notificationService.showMessage(this.translateService.instant(message)
+ '[' + this.accept + ']', null, NotificationType.error);
} else if ('CONTENT_ERROR' === status) {
this.formGroup.controls.file.setValue(null);
this.enabledOK = false;
this.buildErrorDetail(status, info.fileValidationResult.recordsErrorMap);
} else if ('HEADER_ERROR' === status) {
this.formGroup.controls.file.setValue(null);
this.enabledOK = false;
this.buildErrorDetail(status, info.fileValidationResult.headersErrorMap);
}
} else {
this.enabledOK = false;
this.fileErrorDetail = undefined;
this.formGroup.controls.file.setValue(null);
}
}
});
}
ok() {
this.fileInfo.description = this.formGroup.controls.description.value;
this.dialogRef.close(this.fileInfo);
}
}
<div class="panel-viewer-wrapper">
<div class="panel-viewer-title">
<mat-icon>dns</mat-icon>
{{'label.questions.title' | translate}}
</div>
<div class="panel-viewer-body">
<div class="row pb-4">
<div class="col-1"></div>
<div class="col-10">
<div class="row pt-2" *ngIf="!viewMode" [hidden]="!(dataSource.data && dataSource.data.length)">
<div class="col-12">
<button type="button" class="btn btn-outline-primary btn-sm pull-right" (click)="addFile()">
<i class="fa fa-file-excel-o"></i>
<span class="visible-md-inline visible-lg-inline visible-xl-inline">
{{'btn.new.file' | translate}}
</span>
</button>
</div>
</div>
<div class="border-all text-center" *ngIf="!(dataSource.data && dataSource.data.length)">
<button type="button" class="btn btn-outline-primary btn-sm " (click)="addFile()">
<i class="fa fa-file-excel-o"></i>
<span class="visible-md-inline visible-lg-inline visible-xl-inline">
{{'btn.upload.file' | translate}}
</span>
</button>
</div>
<div class="table-container mat-elevation-z8 p-b-15 mt-3" [hidden]="!(dataSource.data && dataSource.data.length)">
<table mat-table [dataSource]="dataSource" matSort>
<!-- Load ID -->
<ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef mat-sort-header class="w-id text-right">{{'label.file.id' | translate}}</th>
<td mat-cell *matCellDef="let element" class="w-id text-right"> {{element.id}} </td>
</ng-container>
<!-- Filename -->
<ng-container matColumnDef="filename">
<th mat-header-cell *matHeaderCellDef mat-sort-header class="w-filename">{{'label.file.name' | translate}}
</th>
<td mat-cell *matCellDef="let element" class="w-filename"> {{element.filename}} </td>
</ng-container>
<!-- Description -->
<ng-container matColumnDef="description">
<th mat-header-cell *matHeaderCellDef mat-sort-header class="w-description">
{{'label.file.description' | translate}}</th>
<td mat-cell *matCellDef="let element" class="w-description"> {{element.description}} </td>
</ng-container>
<!-- Status -->
<ng-container matColumnDef="status">
<th mat-header-cell *matHeaderCellDef mat-sort-header class="w-status">{{'label.file.status' | translate}}
</th>
<td mat-cell *matCellDef="let element" class="w-status">
<span [ngClass]="getClassStatus(element.status)">{{ getTextStatus(element.status) }}</span>
</td>
</ng-container>
<!-- User -->
<ng-container matColumnDef="user">
<th mat-header-cell *matHeaderCellDef mat-sort-header class="w-user">{{'label.file.user' | translate}}
</th>
<td mat-cell *matCellDef="let element" class="w-user"> {{element.user}} </td>
</ng-container>
<!-- Fecha de carga -->
<ng-container matColumnDef="uploadDate">
<th mat-header-cell *matHeaderCellDef class="w-uploadDate text-right">{{'label.file.upload.date' | translate}}</th>
<td mat-cell *matCellDef="let element" class="w-uploadDate text-right">
<i class="fa fa-calendar" *ngIf="element.uploadDate"></i> {{element.uploadDate}}
</td>
</ng-container>
<!-- Actions -->
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef class="w-actions"></th>
<td mat-cell *matCellDef="let element; let $index = index" class="w-actions text-center">
<div class="btn-group">
<button type="button" class="btn btn-default btn-sm" (click)="onEditRecord(element, $index)"
[disabled]="!resourceAuth['edit'] || viewMode">
<i class="fa fa-edit"></i>
<span class="visible-md-inline visible-lg-inline visible-xl-inline">
{{'btn.edit' | translate}}
</span>
</button>
<button type="button" class="btn btn-default btn-sm" (click)="onDeleteRecord(element, $index)"
[disabled]="!resourceAuth['delete'] || viewMode">
<i class="fa fa-trash"></i>
<span class="visible-md-inline visible-lg-inline visible-xl-inline">
{{'btn.delete' | translate}}
</span>
</button>
</div>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true;"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
</div>
</div>
<div class="col-1"></div>
</div>
<div class="footer-bar">
<div class="row">
<div class="col-12">
<button mat-stroked-button matStepperPrevious class="pull-left">
<i class="fa fa-chevron-left"></i>
<span class="pl-1">{{'btn.previous' | translate}}</span>
</button>
<button mat-stroked-button (click)="next()" class="pull-right" [disabled]="!dataSource.data.length">
<span class="pr-1">{{'btn.next' | translate}}</span>
<i class="fa fa-chevron-right"></i>
</button>
</div>
</div>
</div>
</div>
\ No newline at end of file
.table-container {
height: 300px;
overflow: auto;
}
th.mat-sort-header-sorted {
color: black;
}
$fontcolor: #676a6c;
.content {
width: 100%;
display: flex;
padding-right: 0px !important;
.grid-container,
.filter-panel {
.crud-table {
margin-bottom: 0px;
width: 100%;
}
.form {
padding: 10px 20px 10px 20px;
}
}
.filter-panel {
margin-bottom: 10px;
}
}
.btn-group {
.btn {
font-size: 10px;
}
}
th.mat-column-actions {
width: 1px !important;
padding-right: 0px !important;
}
td.mat-column-actions {
min-width: 80px;
padding-right: 20px !important;
cursor: default !important;
}
td {
vertical-align: middle !important;
color: $fontcolor;
font-size: 12px;
}
th {
vertical-align: middle !important;
}
tr.mat-header-row {
height: 50px !important;
}
tr.mat-footer-row,
tr.mat-row {
height: 40px !important;
}
.table-toolbar {
right: 10px;
top: 10px;
button {
font-size: 12px;
}
}
.mat-raised-button {
padding: 0px 10px;
}
::ng-deep .mat-sort-header-arrow {
visibility: hidden;
}
::ng-deep .mat-sort-header-button {
.mat-icon {
padding-left: 10px;
font-size: 12px;
padding-top: 5px;
}
}
th {
background: rgb(242, 242, 242);
}
//////
table {
width: 100%;
}
tr.mat-header-row {
height: 25px;
}
tr.mat-footer-row,
tr.mat-row {
height: 40px;
}
.button-grid {
margin: 2px 5px;
mat-icon {
padding-top: 2px;
}
}
.btn-grid-action {
padding: 0 10px;
line-height: 0em;
}
.grid-ibox-content {
width: 100%;
}
td.mat-cell,
td.mat-footer-cell,
th.mat-header-cell {
/* padding: 0; */
border-bottom-width: 1px;
border-bottom-style: solid;
padding: 1px 10px 1px 10px;
}
.p-b-15 {
padding-bottom: 15px;
}
.w-id {
width: 5%;
}
.w-filename {
width: 20%;
}
.w-description {
width: 18%;
}
.w-status {
width: 12%;
}
.w-user {
width: 15%;
}
.w-uploadDate {
width: 10%;
}
.w-actions {
width: 20%;
}
.border-all.text-center {
padding: 50px;
border-radius: 4px;
margin-top: 56px;
}
::ng-deep .text-right > .mat-sort-header-container {
justify-content: flex-end !important;
}
\ No newline at end of file
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { CaFrequentQuestionsComponent } from './ca-frequent-questions.component';
describe('CaFrequentQuestionsComponent', () => {
let component: CaFrequentQuestionsComponent;
let fixture: ComponentFixture<CaFrequentQuestionsComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ CaFrequentQuestionsComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(CaFrequentQuestionsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit, Input, ViewContainerRef, ViewChild, Output } from '@angular/core';
import { AfterViewInit, EventEmitter } from '@angular/core';
import { MatStepper, MatDialog, MatTableDataSource, MatSort } from '@angular/material';
import { ActivatedRoute, Router } from '@angular/router';
import { animate, trigger, state, transition, style } from '@angular/animations';
import { AuthorizationService } from '@xdf/security';
import { TranslateService } from '@ngx-translate/core';
import { CaFileUploadModalComponent, FileUploadModel } from '../ca-file-upload-modal/ca-file-upload-modal.component';
@Component({
selector: 'byte-ca-frequent-questions',
templateUrl: './ca-frequent-questions.component.html',
styleUrls: ['./ca-frequent-questions.component.scss'],
animations: [
trigger('fadeInOut', [
state('in', style({ opacity: 100 })),
transition('* => void', [
animate(300, style({ opacity: 0 }))
])
])
]
})
export class CaFrequentQuestionsComponent implements OnInit, AfterViewInit {
@ViewChild(MatSort, { static: false }) sort: MatSort;
@Input()
stepper: MatStepper;
@Output()
nextPage: EventEmitter<boolean> = new EventEmitter<boolean>();
public resourceAuth = new Object();
dirty = false;
accept = '.xls,.xlsx';
agentDetail: any;
displayedColumns: string[] = ['id', 'filename', 'description', 'status', 'user', 'uploadDate', 'actions'];
dataSource = new MatTableDataSource<FileUploadModel>([]);
mapStatus = {
LO: {
class: 'label label-primary',
text: 'label.status.loaded'
},
PS: {
class: 'label label-warning',
text: 'label.status.pending'
}
};
files = [];
viewMode: boolean;
constructor(
protected route: ActivatedRoute,
protected router: Router,
protected vcRef: ViewContainerRef,
protected authorizationService: AuthorizationService,
private translate: TranslateService,
private activatedRoute: ActivatedRoute,
private matDialog: MatDialog
) {
this.viewMode = this.activatedRoute.snapshot.data.mode === 'view';
}
ngOnInit() {
const keyAuthorization = 'authorization';
const authList = this.route.snapshot.paramMap[keyAuthorization];
if (authList) {
this.resourceAuth = new Object();
authList.forEach(option => {
this.resourceAuth[option] = true;
});
}
}
isDirty() {
return this.dirty;
}
buildForm(agentDetail: any) {
this.agentDetail = agentDetail;
if (agentDetail.frequentQuestions) {
this.dataSource.data = agentDetail.frequentQuestions;
}
}
setDataForWizard(result: any) {
console.log(result);
/*
this.protocols = result.connectionProtocolOptions;
this.generalProperties = result.generalProperties;
this.alias = result.alias;
this.maxNumberOfConnectionsByExternalSystem = result.maxNumberOfConnectionsByExternalSystem;
this.columnsForEntity = result.columnsForEntity;
*/
}
ngAfterViewInit() {
this.dataSource.sort = this.sort;
}
getClassStatus(status) {
return this.mapStatus[status].class;
}
getTextStatus(status) {
return this.translate.instant(this.mapStatus[status].text);
}
addFile() {
const dialog = this.matDialog.open(CaFileUploadModalComponent, {
width: '600px',
data: null
});
dialog.afterClosed().subscribe(result => {
if (result) {
const fileAdded = { ...result };
const listTemp = this.dataSource.data;
listTemp.push(fileAdded);
this.dataSource.data = listTemp;
this.dirty = true;
}
});
}
onEditRecord(item, index) {
item.editable = true;
const dialog = this.matDialog.open(CaFileUploadModalComponent, {
width: '500px',
data: item
});
dialog.afterClosed().subscribe(result => {
if (result) {
const fileEdited = { ...result };
const listTemp = this.dataSource.data;
listTemp[index] = fileEdited;
this.dataSource.data = listTemp;
}
});
}
saveQuestions(validateForm: boolean) {
const success = true;
this.agentDetail.frequentQuestions = this.dataSource.data;
return success;
}
onDeleteRecord(item, index) {
const listTemp = this.dataSource.data;
listTemp.splice(index, 1);
this.dataSource.data = listTemp;
this.dirty = true;
}
next() {
if (!this.dataSource.data.length) {
return;
}
if (this.viewMode) {
this.stepper.next();
return;
}
if (this.saveQuestions(true)) {
this.nextPage.emit(this.isDirty());
this.stepper.next();
}
}
}
<div class="panel-viewer-wrapper">
<div class="panel-viewer-title">
<i class="fa fa-info-circle"></i>
{{'label.general-information.title' | translate}}
</div>
<form [formGroup]="formGroup" autocomplete="off">
<div class="panel-viewer-body">
<div class="row pt-3 pb-4">
<div class="col-3"></div>
<div class="col-6 mat-elevation-z3">
<div class="row">
<div class="col-6">
<!-- INICIO :: SECCION AVATAR -->
<div class="row pt-2 h-100">
<div class="col-12">
<label class="form-field-label" #labelcontrol>{{ 'label.avatar' | translate }}
<span aria-hidden="true"
class="mat-placeholder-required mat-form-field-required-marker"> *</span>
</label>
<div class="h-85">
<div class="image-preview">
<div [ngClass]="{'with-image': formGroup.controls['imageAvatar'].value, 'edit-image': formGroup.controls['imageAvatar'].value, 'without-image': !formGroup.controls['imageAvatar'].value}">
<img src="{{ urlBase + formGroup.controls['imageAvatar'].value }}"
style="height: 100%;"
*ngIf="formGroup.controls['imageAvatar'].value">
<div class="image-notfound"
*ngIf="!formGroup.controls['imageAvatar'].value"></div>
</div>
<button type="button" mat-stroked-button (click)="fileInput.click()"
*ngIf="!viewMode" class="btn-upload-image">
<mat-icon>file_upload</mat-icon>
<!-- {{text | translate}} -->
</button>
</div>
</div>
<input type="file" #fileInput name="fileUpload"
(change)="uploadFiles($event.target.files)"
style="display:none;" >
</div>
</div>
<!-- FIN :: SECCION AVATAR -->
</div>
<div class="col-6">
<div class="row pt-2">
<div class="col-12">
<mat-form-field class="amd-form-control">
<input matInput [placeholder]="'label.name' | translate" formControlName="name"
maxlength="50" required>
<mat-error *ngFor="let error of getErrors('name', 'label.name')">{{ 'message.error.' + error.name | translate : error.prop}}
</mat-error>
</mat-form-field>
</div>
</div>
<div class="row pt-2">
<div class="col-12">
<mat-form-field class="amd-form-control">
<textarea matInput cdkTextareaAutosize class="overflow-auto"
[placeholder]="'label.description' | translate" maxlength="200"
formControlName="description" #autosize="cdkTextareaAutosize" cdkAutosizeMinRows="3"
cdkAutosizeMaxRows="6" required></textarea>
<mat-error *ngFor="let error of getErrors('description', 'label.description')">{{ 'message.error.' + error.name | translate : error.prop}}
</mat-error>
</mat-form-field>
</div>
</div>
<div class="row pt-2">
<div class="col-12">
<mat-form-field class="amd-form-control">
<input matInput [placeholder]="'label.version' | translate" formControlName="version"
maxlength="15" required pattern="[0-9]{1,2}[.]{1}[0-9]{1,2}[.]{1}[0-9]{1,2}">
<mat-hint>##.##.##</mat-hint>
<mat-error *ngFor="let error of getErrors('version', 'label.version')">{{ 'message.error.' + error.name | translate : error.prop}}
</mat-error>
</mat-form-field>
</div>
</div>
<div class="row pt-2">
<div class="col-12">
<mat-form-field class="amd-form-control">
<mat-select [placeholder]="'label.country' | translate" formControlName="country"
required (selectionChange)="onCountryChange($event, true)">
<mat-option *ngFor="let country of countries" [value]="country.id">
{{country.name | translate}}
</mat-option>
</mat-select>
<mat-error *ngFor="let error of getErrors('country', 'label.country')">{{ 'message.error.' + error.name | translate : error.prop}}
</mat-error>
</mat-form-field>
</div>
</div>
<div class="row pt-2">
<div class="col-12">
<mat-form-field class="amd-form-control">
<mat-select [placeholder]="'label.timezone' | translate" formControlName="timezone"
required>
<mat-option *ngFor="let timezone of timezones" [value]="timezone">
{{timezone | translate}}
</mat-option>
</mat-select>
<mat-error *ngFor="let error of getErrors('timezone', 'label.timezone')">{{ 'message.error.' + error.name | translate : error.prop}}
</mat-error>
</mat-form-field>
</div>
</div>
<div class="row pt-2">
<div class="col-12">
<mat-form-field class="amd-form-control">
<mat-select [placeholder]="'label.language' | translate" formControlName="language" required >
<mat-option *ngFor="let language of languages" [value]="language.code">
{{language.name | translate}}
</mat-option>
</mat-select>
<mat-error *ngFor="let error of getErrors('language', 'label.language')">{{ 'message.error.' + error.name | translate : error.prop}}
</mat-error>
</mat-form-field>
</div>
</div>
<div class="row pt-2">
<div class="col-12">
<mat-form-field class="amd-form-control">
<mat-select [placeholder]="'label.type' | translate" formControlName="type" required >
<mat-option *ngFor="let type of types" [value]="type.code">
{{type.name | translate}}
</mat-option>
</mat-select>
<mat-error *ngFor="let error of getErrors('type', 'label.type')">{{ 'message.error.' + error.name | translate : error.prop}}
</mat-error>
</mat-form-field>
</div>
</div>
</div>
</div>
</div>
<div class="col-3"></div>
</div>
<div class="footer-bar">
<div class="row">
<div class="col-12">
<button mat-stroked-button (click)="next()" class="pull-right" [disabled]="formGroup.invalid">
<span class="pr-1">{{'btn.next' | translate}}</span>
<i class="fa fa-chevron-right"></i>
</button>
</div>
</div>
</div>
</div>
</form>
</div>
\ No newline at end of file
ul,
li {
margin: 0;
padding: 0;
list-style: none;
}
#file-label {
display: inline-flex;
vertical-align: middle;
font-size: 12px;
line-height: 18px;
}
#file-label mat-icon {
font-size: 18px;
text-align: center;
}
#file-label a {
cursor: pointer;
}
.uploadList {
margin-top: 10px;
}
.uploadfilecontainer {
background-position: center;
line-height: 200px;
margin: 20px auto;
border: 2px dashed #1c8adb;
border-radius: 10px;
button {
vertical-align: middle;
}
}
.uploadfilecontainer:hover {
cursor: pointer;
background-color: #9ecbec !important;
opacity: 0.8;
}
.image-preview {
height: 100%;
width: 100%;
position: relative;
overflow: hidden;
background-image: none;
background-color: white;
background-position: center center;
background-repeat: no-repeat;
background-size: cover;
border: 1px solid rgba(0, 0, 0, 0.12);
border-radius: 5px;
}
.image-notfound {
width: 100%;
height: 100%;
// border-radius: 5px;
// border-bottom-color:rgba(0,0,0,.12);
&::after {
content: "photo_size_select_actual";
font-family: "Material Icons";
position: relative;
font-size: 4.5em;
color: rgba(230, 230, 230, 1);
top: calc(50% - 3rem);
left: calc(50% - 2.25rem);
z-index: 0;
}
}
.btn-upload-image {
font-size: 80%;
width: 100%;
border-radius: 0;
border-width: 1px 0 0 0;
border-top-color: rgba(0, 0, 0, 0.12);
}
.form-field-label {
color: rgba(0, 0, 0, 0.54);
font-size: 75%;
}
.with-image {
text-align: center;
height: 100%;
}
.edit-image {
text-align: center;
height: calc(100% - 36px);
}
.without-image {
text-align: inherit;
height: calc(100% - 36px);
}
.h-85 {
height: 85%;
}
.h-100 {
height: 85%;
}
.col-6.mat-elevation-z3 {
padding: 24px;
}
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { CaGeneralInformationComponent } from './ca-general-information.component';
describe('CaGeneralInformationComponent', () => {
let component: CaGeneralInformationComponent;
let fixture: ComponentFixture<CaGeneralInformationComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ CaGeneralInformationComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(CaGeneralInformationComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { FormGroup, FormBuilder, FormControl, Validators } from '@angular/forms';
import { MatStepper } from '@angular/material';
import { ActivatedRoute } from '@angular/router';
import { animate, trigger, state, transition, style } from '@angular/animations';
import { NotificationService, NotificationType } from '@xdf/commons';
import { TranslateService } from '@ngx-translate/core';
import { ValidatorUtils } from '@xdf/gallery';
export const FILE_TYPE = {
image: /image.*/,
file: /.*/
};
@Component({
selector: 'byte-ca-general-information',
templateUrl: './ca-general-information.component.html',
styleUrls: ['./ca-general-information.component.scss'],
animations: [
trigger('fadeInOut', [
state('in', style({ opacity: 100 })),
transition('* => void', [
animate(300, style({ opacity: 0 }))
])
])
]
})
export class CaGeneralInformationComponent implements OnInit {
@Input()
stepper: MatStepper;
@Output()
nextPage: EventEmitter<boolean> = new EventEmitter<boolean>();
agentDetail: any;
formGroup: FormGroup;
viewMode: boolean;
mode = 'new';
imageName = 'imageAvatar';
urlBase = '';
countries = [];
timezones = [];
languages = [
{
code: 'ES',
name: 'Español'
}
];
types = [
{
code: 'FQ',
name: 'Agente de preguntas frecuentes'
}
];
acceptedImageTypes = ['image/png', 'image/jpeg', 'image/gif'];
acceptedTypes = 'PNG, JPEG, GIF';
constructor(
private formBuilder: FormBuilder,
private activatedRoute: ActivatedRoute,
private notificationService: NotificationService,
private translateService: TranslateService,
private validatorUtils: ValidatorUtils
) {
this.mode = this.activatedRoute.snapshot.data.mode;
this.viewMode = this.mode === 'view';
this.countries = this.activatedRoute.snapshot.data.countryData;
this.formGroup = this.formBuilder.group({
name: new FormControl({ value: '', disabled: this.viewMode }),
description: new FormControl({ value: '', disabled: this.viewMode }),
version: new FormControl({ value: '', disabled: this.viewMode }),
imageAvatar: new FormControl({ value: '', disabled: this.viewMode }, { validators: [Validators.required] }),
country: new FormControl({ value: '', disabled: this.viewMode }),
timezone: new FormControl({ value: '', disabled: this.viewMode }),
language: new FormControl({ value: '', disabled: this.viewMode }),
type: new FormControl({ value: '', disabled: this.viewMode })
});
}
ngOnInit() {
}
buildForm(agentDetail: any) {
this.agentDetail = agentDetail;
if (agentDetail) {
this.formGroup.patchValue({
name: agentDetail.name,
description: agentDetail.description,
version: agentDetail.version,
timezone: agentDetail.timezone,
country: agentDetail.countryId,
imageAvatar: agentDetail.avatar,
language: agentDetail.language,
type: agentDetail.type
});
this.onCountryChange(this.formGroup.controls.country);
}
}
saveGeneralInformation(validateForm: boolean): boolean {
if (validateForm && !this.formGroup.valid) {
return false;
}
this.agentDetail.name = this.formGroup.controls.name.value;
this.agentDetail.description = this.formGroup.controls.description.value;
this.agentDetail.version = this.formGroup.controls.version.value;
this.agentDetail.countryId = this.formGroup.controls.country.value;
this.agentDetail.timezone = this.formGroup.controls.timezone.value;
this.agentDetail.avatar = this.formGroup.controls.imageAvatar.value;
this.agentDetail.language = this.formGroup.controls.language.value;
this.agentDetail.type = this.formGroup.controls.type.value;
return true;
}
isDirty() {
return this.formGroup.dirty;
}
uploadFiles(event) {
for (const i in event) {
if (event[i] instanceof File) {
const eventTemp = event[i];
if (this.acceptedImageTypes.includes(eventTemp.type)) {
const reader = new FileReader();
reader.onload = () => {
this.formGroup.controls['imageAvatar'].setValue(reader.result as string);
};
reader.readAsDataURL(event[i]);
} else {
const message = 'label.imageAvatar.incompatible.extension';
this.notificationService.showMessage(this.translateService.instant(message) +
'[' + this.acceptedTypes + ']', null, NotificationType.error);
}
}
}
}
onCountryChange(obj, deleteTimeZone?: boolean) {
const selectedCountry = obj.value;
this.timezones = [];
if (deleteTimeZone) {
this.formGroup.controls['timezone'].setValue(null);
}
if (selectedCountry) {
for (const index in this.countries) {
if (selectedCountry === this.countries[index].id) {
this.timezones = this.countries[index].timezones;
break;
}
}
}
}
next() {
if (this.viewMode) {
this.stepper.next();
return;
}
if (this.saveGeneralInformation(true)) {
this.nextPage.emit(this.isDirty());
this.stepper.next();
}
}
getErrors(name: string, placeholder: string) {
return this.validatorUtils.getErrors(this.formGroup.controls[name] as FormControl, name, placeholder);
}
}
import { TestBed } from '@angular/core/testing';
import { UploadService } from './upload.service';
describe('UploadService', () => {
beforeEach(() => TestBed.configureTestingModule({}));
it('should be created', () => {
const service: UploadService = TestBed.get(UploadService);
expect(service).toBeTruthy();
});
});
import { HttpClient, HttpEvent, HttpErrorResponse, HttpEventType } from '@angular/common/http';
import { map } from 'rxjs/operators';
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class UploadService {
SERVER_URL = './service/agent';
constructor(private httpClient: HttpClient) { }
public upload(formData) {
return this.httpClient.post<any>(this.SERVER_URL, formData, {
reportProgress: true,
observe: 'events'
});
}
}
/*
* Inspinia js helpers:
*
* correctHeight() - fix the height of main wrapper
* detectBody() - detect windows size
* smoothlyMenu() - add smooth fade in/out on navigation show/ide
*
*/
// import * as jQuery_ from 'jquery';
// const jQuery = jQuery_;
declare var jQuery: any;
export function correctHeight() {
const pageWrapper = jQuery('#page-wrapper');
const navbarHeight = jQuery('nav.navbar-default').height();
const wrapperHeight = pageWrapper.height();
if (navbarHeight > wrapperHeight) {
pageWrapper.css('min-height', navbarHeight + 'px');
}
if (navbarHeight <= wrapperHeight) {
if (navbarHeight < jQuery(window).height()) {
pageWrapper.css('min-height', jQuery(window).height() + 'px');
} else {
pageWrapper.css('min-height', navbarHeight + 'px');
}
}
if (jQuery('body').hasClass('fixed-nav')) {
if (navbarHeight > wrapperHeight) {
pageWrapper.css('min-height', navbarHeight + 'px');
} else {
pageWrapper.css('min-height', jQuery(window).height() - 60 + 'px');
}
}
}
export function detectBody() {
if (jQuery(document).width() < 769) {
jQuery('body').addClass('body-small');
} else {
jQuery('body').removeClass('body-small');
}
}
export function smoothlyMenu() {
if (!jQuery('body').hasClass('mini-navbar') || jQuery('body').hasClass('body-small')) {
// Hide menu in order to smoothly turn on when maximize menu
jQuery('#side-menu').hide();
// For smoothly turn on menu
setTimeout(
() => {
jQuery('#side-menu').fadeIn(400);
}, 200);
} else if (jQuery('body').hasClass('fixed-sidebar')) {
jQuery('#side-menu').hide();
setTimeout(
() => {
jQuery('#side-menu').fadeIn(400);
}, 100);
} else {
// Remove all inline style from jquery fadeIn function to reset menu state
jQuery('#side-menu').removeAttr('style');
}
}
export function fixHeight() {
const heightWithoutNavbar = jQuery('body > #wrapper').height() - 62;
jQuery('.sidebar-panel').css('min-height', heightWithoutNavbar + 'px');
const navbarheight = jQuery('nav.navbar-default').height();
const wrapperHeight = jQuery('#page-wrapper').height();
if (navbarheight > wrapperHeight) {
jQuery('#page-wrapper').css('min-height', navbarheight + 'px');
}
if (navbarheight < wrapperHeight) {
jQuery('#page-wrapper').css('min-height', jQuery(window).height() + 'px');
}
if (jQuery('body').hasClass('fixed-nav')) {
if (navbarheight > wrapperHeight) {
jQuery('#page-wrapper').css('min-height', navbarheight + 'px');
} else {
jQuery('#page-wrapper').css('min-height', jQuery(window).height() - 60 + 'px');
}
}
}
import { NgModule } from '@angular/core';
import { DirtyGuard, XdfGalleryModule } from '@xdf/gallery';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { TranslateModule } from '@ngx-translate/core';
import { XdfSettingsModule } from '@xdf/settings';
import { BytebotLayoutComponent } from './bytebot-layout/bytebot-layout.component';
import { LayoutModule } from '@angular/cdk/layout';
@NgModule({
declarations: [
BytebotLayoutComponent
],
imports: [
CommonModule,
FormsModule,
ReactiveFormsModule,
TranslateModule,
LayoutModule
],
entryComponents: [
],
exports: [
BytebotLayoutComponent
]
,
providers: [
{ provide: DirtyGuard, useClass: DirtyGuard }
]
})
export class BytebotLayoutModule { }
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { BytebotLayoutComponent } from './bytebot-layout.component';
describe('BytebotLayoutComponent', () => {
let component: BytebotLayoutComponent;
let fixture: ComponentFixture<BytebotLayoutComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ BytebotLayoutComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(BytebotLayoutComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, HostListener, OnInit } from '@angular/core';
import { detectBody } from '../app.helpers';
@Component({
selector: 'byte-bytebot-layout',
templateUrl: './bytebot-layout.component.html',
styleUrls: ['./bytebot-layout.component.scss']
})
export class BytebotLayoutComponent implements OnInit {
constructor(// protected toogleService: ToogleService
) { }
ngOnInit() {
detectBody();
}
@HostListener('window:resize')
public onResize() {
detectBody();
}
gotoTop() {
console.log('custom-layout');
}
onToggle() {
console.log('test');
// this.toogleService.onToggle(true);
}
}
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AuthGuard } from '@xdf/security';
import { TemplateResolver, CrudDetailComponent, DirtyGuard, GridViewComponent, CrudGridComponent, RecordResolver } from '@xdf/gallery';
import { ResourceAuthGuard } from '@xdf/security';
import { UserRoleFormComponent, AccessDetailResolver } from '@xdf/settings';
const routes: Routes = [
{
path: 'user-role', component: GridViewComponent, canActivate: [AuthGuard, ResourceAuthGuard],
resolve: { template: TemplateResolver },
data: {
program: 'user_role',
breadcrumb: 'breadcrumb.user.role'
}
},
{
path: 'user-role/detail/:mode', component: UserRoleFormComponent, canActivate: [AuthGuard, ResourceAuthGuard],
canDeactivate: [DirtyGuard],
resolve: { record: RecordResolver, accessList: AccessDetailResolver },
data: {
program: 'user_role',
breadcrumb: 'breadcrumb.user.role.detail'
}
},
{
path: 'user', component: CrudGridComponent, canActivate: [AuthGuard, ResourceAuthGuard],
resolve: { template: TemplateResolver },
data: {
innerTemplate: 'none',
program: 'user',
breadcrumb: 'breadcrumb.user'
}
},
{
path: 'user/detail/:mode', component: CrudDetailComponent, canActivate: [AuthGuard, ResourceAuthGuard], canDeactivate: [DirtyGuard],
resolve: { record: RecordResolver },
data: {
program: 'user',
breadcrumb: 'breadcrumb.user.detail'
}
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class SecurityRoutingModule { }
import { NgModule } from '@angular/core';
import { DirtyGuard, XdfGalleryModule } from '@xdf/gallery';
import { SecurityRoutingModule } from './security-routing.module';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { TranslateModule } from '@ngx-translate/core';
import { XdfSettingsModule } from '@xdf/settings';
@NgModule({
declarations: [
],
imports: [
CommonModule,
FormsModule,
ReactiveFormsModule,
TranslateModule,
XdfGalleryModule,
XdfSettingsModule,
SecurityRoutingModule
],
entryComponents: [
],
providers: [
{ provide: DirtyGuard, useClass: DirtyGuard }
]
})
export class SecurityModule { }
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AuthGuard } from '@xdf/security';
import { DirtyGuard, TemplateResolver, CrudGridComponent, EditableDataTableTemplateResolver } from '@xdf/gallery';
import { CrudDetailComponent, FormViewComponent, ListResolver, RecordResolver } from '@xdf/gallery';
import { ResourceAuthGuard } from '@xdf/security';
import { ApplicationFormComponent, ValposFormComponent } from '@xdf/settings';
import { TabsLayoutComponent, TabsTemplateResolver } from '@xdf/layouts';
const routes: Routes = [
{
path: 'system-settings', component: TabsLayoutComponent,
resolve: { template: TabsTemplateResolver },
data: {
templateName: 'system-settings',
},
children: [
{ path: 'information', component: FormViewComponent, canActivate: [AuthGuard, ResourceAuthGuard], canDeactivate: [DirtyGuard],
resolve: { record: ListResolver },
data: {
option: 'information',
program: 'system_settings_information',
breadcrumb: 'breadcrumb.settings.information'
}
},
{ path: 'information/:mode', component: FormViewComponent, canActivate: [AuthGuard, ResourceAuthGuard], canDeactivate: [DirtyGuard],
resolve: { ecord: ListResolver },
data: {
withoutGrid: true,
option: 'information',
program: 'system_settings_information',
breadcrumb: 'breadcrumb.settings.information'
}
},
{ path: 'password', component: FormViewComponent, canActivate: [AuthGuard, ResourceAuthGuard], canDeactivate: [DirtyGuard],
resolve: { record: ListResolver },
data: {
option: 'password',
program: 'system_settings_password',
breadcrumb: 'breadcrumb.settings.password'
}
},
{ path: 'password/:mode', component: FormViewComponent, canActivate: [AuthGuard, ResourceAuthGuard], canDeactivate: [DirtyGuard],
resolve: { record: ListResolver },
data: {
withoutGrid: true,
option: 'password',
program: 'system_settings_password',
breadcrumb: 'breadcrumb.settings.password'
}
},
{ path: 'userpolicy', component: FormViewComponent, canActivate: [AuthGuard, ResourceAuthGuard], canDeactivate: [DirtyGuard],
resolve: { record: ListResolver },
data: {
option: 'userpolicy',
program: 'system_settings_userpolicy',
breadcrumb: 'breadcrumb.settings.userpolicy'
}
},
{ path: 'userpolicy/:mode', component: FormViewComponent, canActivate: [AuthGuard, ResourceAuthGuard], canDeactivate: [DirtyGuard],
resolve: { record: ListResolver },
data: {
withoutGrid: true,
option: 'userpolicy',
program: 'system_settings_userpolicy',
breadcrumb: 'breadcrumb.settings.userpolicy'
}
}
]
},
{
path: 'application', component: CrudGridComponent, canActivate: [AuthGuard, ResourceAuthGuard],
resolve: { template: TemplateResolver },
data: {
program: 'application',
breadcrumb: 'breadcrumb.application'
}
},
{
path: 'application/detail/:mode', component: ApplicationFormComponent,
canActivate: [AuthGuard, ResourceAuthGuard], canDeactivate: [DirtyGuard],
resolve: { record: RecordResolver },
data: {
program: 'application',
breadcrumb: 'breadcrumb.application.detail'
}
},
{
path: 'valpos', component: CrudGridComponent, canActivate: [AuthGuard, ResourceAuthGuard],
resolve: { template: TemplateResolver },
data: {
program: 'valpos',
breadcrumb: 'breadcrumb.valpos'
}
},
{
path: 'valpos/detail/:mode', component: ValposFormComponent, canActivate: [AuthGuard, ResourceAuthGuard], canDeactivate: [DirtyGuard],
resolve: { record: RecordResolver, editableTableTemplate: EditableDataTableTemplateResolver },
data: {
program: 'valpos',
breadcrumb: 'breadcrumb.valpos.detail',
editableTableTemplate: 'valpos-detail'
}
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class SettingsRoutingModule { }
import { NgModule } from '@angular/core';
import { DirtyGuard, XdfGalleryModule, EditableDataTableTemplateResolver } from '@xdf/gallery';
import { SettingsRoutingModule } from './settings-routing.module';
import { TranslateModule } from '@ngx-translate/core';
import { ReactiveFormsModule, FormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
import { MatFormFieldModule, MatSelectModule, MatTooltipModule, MatButtonModule } from '@angular/material';
import { XdfSettingsModule } from '@xdf/settings';
import { XdfLayoutsModule } from '@xdf/layouts';
@NgModule({
declarations: [
],
imports: [
CommonModule,
FormsModule,
ReactiveFormsModule,
TranslateModule,
SettingsRoutingModule,
MatFormFieldModule,
MatSelectModule,
MatTooltipModule,
XdfGalleryModule,
XdfSettingsModule,
XdfLayoutsModule,
MatButtonModule
],
entryComponents: [
],
providers: [
{ provide: DirtyGuard, useClass: DirtyGuard },
EditableDataTableTemplateResolver
]
})
export class SettingsModule { }
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { SettingsService, ApplicationSettings } from '@xdf/layouts';
@Injectable({
providedIn: 'root'
})
export class BytebotSettingsService extends SettingsService {
constructor(private http: HttpClient) {
super();
}
getApplicationSettings(): Observable<ApplicationSettings> {
return this.http.get<ApplicationSettings>('./service/settings-logo/');
}
}
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class SharedFilterService {
private myStartDate: Date;
private myEndDate: Date;
get startDate(): Date {
return this.myStartDate;
}
get endDate(): Date {
return this.myEndDate;
}
setStartDate(date: Date) {
this.myStartDate = date;
}
setEndDate(date: Date) {
this.myEndDate = date;
}
}
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { HomeComponent } from './home.component';
describe('HomeComponent', () => {
let component: HomeComponent;
let fixture: ComponentFixture<HomeComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ HomeComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(HomeComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'byte-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
[
{
"view":"(UTC-11:00) Midway, Niue, Pago Pago",
"gmt":"-11:00"
},
{
"view":"(UTC-10:00) Honolulu, Tahiti",
"gmt":"-10:00"
},
{
"view":"(UTC-9:30) Marquesas",
"gmt":"-9:30"
},
{
"view":"(UTC-9:00) Juneau, Nome, Gambier",
"gmt":"-9:00"
},
{
"view":"(UTC-8:00) Dawson, Los Angeles, Tijuana, Vancouver",
"gmt":"-8:00"
},
{
"view":"(UTC-7:00) Boise, Phoenix, Edmonton, Inuvik",
"gmt":"-7:00"
},
{
"view":"(UTC-6:00) Belize, Chicago, Costa Rica, El Salvador, Guatemala, Managua, Mexico City",
"gmt":"-6:00"
},
{
"view":"(UTC-5:00) Bogota, Cancun, Detroit, Lima, New York, Panama, Toronto",
"gmt":"-5:00"
},
{
"view":"(UTC-4:00) Aruba, Barbados, Caracas, Guyana, La Paz, Manaus, Santiago, Puerto Rico",
"gmt":"-4:00"
},
{
"view":"(UTC-3:30) St Johns",
"gmt":"-3:30"
},
{
"view":"(UTC-3:00) Buenos Aires, Bahia, Cayenne, Montevideo",
"gmt":"-3:00"
},
{
"view":"(UTC-2:00) Noronha, South Georgia",
"gmt":"-2:00"
},
{
"view":"(UTC-1:00) Scoresbysund, Azores, Cape Verde",
"gmt":"-1:00"
},
{
"view":"(UTC) Hora universal coordinada",
"gmt":"0:00"
},
{
"view":"(UTC+1:00) Algiers, Madrid, Berlin, Bruselas, Lagos, Túnez, Niamey, Amsterdam",
"gmt":"+1:00"
},
{
"view":"(UTC+2:00) Cairo, Harare, Tripoli, Gaza, Atenas",
"gmt":"+2:00"
},
{
"view":"(UTC+3:00) Qatar, Moscú, Simferopol ",
"gmt":"+3:00"
},
{
"view":"(UTC+3:30) Tehran",
"gmt":"+3:30"
},
{
"view":"(UTC+4:00) Baku, Dubai",
"gmt":"+4:00"
},
{
"view":"(UTC+4:30) Kabul ",
"gmt":"+4:30"
},
{
"view":"(UTC+5:00) Mawson, Aqtobe, Karachi, Maldivas",
"gmt":"+5:00"
},
{
"view":"(UTC+5:30) Colombo, Kolkata ",
"gmt":"+5:30"
},
{
"view":"(UTC+5:45) Kathmandu",
"gmt":"+5:45"
},
{
"view":"(UTC+6:00) Bishkek, Novosibirsk, Qyzylorda",
"gmt":"+6:00"
},
{
"view":"(UTC+7:00) Bangkok, Indonesia, Barnaul ",
"gmt":"+7:00"
},
{
"view":"(UTC+8:00) Macau, Shanghai, Singapore",
"gmt":"+8:00"
},
{
"view":"(UTC+8:30) Pyongyang",
"gmt":"+8:30"
},
{
"view":"(UTC+8:45) Eucla",
"gmt":"+8:45"
},
{
"view":"(UTC+9:00) Chita, Jayapura, Tokyo, Palau",
"gmt":"+9:00"
},
{
"view":"(UTC+9:30) Darwin, Adelaide",
"gmt":"+9:30"
},
{
"view":"(UTC+10:00) Vladivostok, Brisbane, Hobart",
"gmt":"+10:00"
},
{
"view":"(UTC+10:30) Lord Howe",
"gmt":"+10:30"
},
{
"view":"(UTC+11:00) Magadan, Bougainville, Guadalcanal",
"gmt":"+11:00"
},
{
"view":"(UTC+12:00) Kamchatka, Auckland, Majuro",
"gmt":"+12:00"
},
{
"view":"(UTC+12:45) Chatham",
"gmt":"+12:45"
},
{
"view":"(UTC+13:00) Apia, Enderbury, Tongatapu ",
"gmt":"+13:00"
},
{
"view":"(UTC+14:00) Kiritimati ",
"gmt":"+14:00"
}
]
\ No newline at end of file
[
{
"id": 30,
"name": "security",
"label": "menu.security",
"icon": "<i class=\"fa fa-address-book\"></i>",
"fullPath": "/security",
"singlePath": "security",
"isProgram": false,
"children": [
{
"id": 32,
"name": "user",
"label": "menu.security.user",
"icon": null,
"fullPath": "/security/user",
"singlePath": "user",
"isProgram": true,
"children": []
},
{
"id": 32,
"name": "user_role",
"label": "menu.security.user.role",
"icon": null,
"fullPath": "/security/user-role",
"singlePath": "user-role",
"isProgram": true,
"children": []
}
]
},
{
"id": 37,
"name": "CONVERSATIONAL_AGENT",
"label": "menu.parent.agent",
"icon": "<i class=\"fa fa-cog\"></i>",
"fullPath": "/configuration/agent",
"singlePath": "configuration",
"isProgram": true,
"children": []
},
{
"id": 38,
"name": "BBOT_DASHBOARD",
"label": "menu.parent.dashboard",
"icon": "<i class=\"fa fa-area-chart\"></i>",
"fullPath": "/dashboards",
"singlePath": "dashboards",
"isProgram": false,
"children": [
{
"id": 32,
"name": "operative_dashboard",
"label": "menu.dashboard.operative",
"icon": null,
"fullPath": "/dashboards/operative",
"singlePath": "operative",
"isProgram": true,
"children": []
},
{
"id": 32,
"name": "customer_interaction_dashboard",
"label": "menu.dashboard.customer.interaction",
"icon": null,
"fullPath": "/dashboards/customer-interaction",
"singlePath": "customer-interaction",
"isProgram": true,
"children": []
}
]
},
{
"id": 39,
"name": "CONVERSATIONAL_AIRPORT",
"label": "menu.parent.airport",
"icon": "<i class=\"fa fa-cog\"></i>",
"fullPath": "/reserva/airport",
"singlePath": "reserva",
"isProgram": true,
"children": []
}
]
[
{ "user": "./assets/definitions/security-definitions/user.json" },
{ "user_role": "./assets/definitions/security-definitions/user-role.json" },
{ "system_settings_information": "./assets/definitions/setting-definitions/system-settings-information.json" },
{ "system_settings_password": "./assets/definitions/setting-definitions/system-settings-password.json" },
{ "system_settings_userpolicy": "./assets/definitions/setting-definitions/system-settings-userpolicy.json" },
{ "application": "./assets/definitions/setting-definitions/application.json" },
{ "valpos": "./assets/definitions/setting-definitions/valpos.json"}
]
\ No newline at end of file
{
"label": {
"type": "text",
"required": true
},
"value": {
"type": "text",
"required": true
}
}
\ No newline at end of file
{
"name": "user_role",
"title": "user.role.title",
"fieldToShowInActon": "identifier",
"icon": "<span class=\"material-icons\">supervisor_account</span>",
"service": "./service/user-role",
"recordId": "id",
"showFormIn": "standard",
"definitionReport": "user-role-report-1",
"attributes": [
{
"name": "id",
"type": "number",
"formOptions": {
"options": {
"hideInNew": true,
"readonly": true,
"styleClass": "col-xs-3 col-sm-6 col-md-3"
},
"validators": [
"required"
],
"controlType": "number"
}
},
{
"name": "identifier",
"type": "string",
"formOptions": {
"options": {
"styleClass": "col-md-6",
"showLength": true,
"maxLength": 80
},
"validators": [
"required"
]
}
},
{
"name": "description",
"type": "string",
"formOptions": {
"options": {
"styleClass": "col-md-6",
"showLength": true,
"maxLength": 120
},
"validators": [
"required"
]
}
}
],
"grid": [
{
"sortColumnDefault": "id",
"sortColumnDirection": "desc",
"pagingSize": 5,
"expandRow": false,
"columns": [
{
"name": "id",
"sortable": true,
"style": {"width": "100px"},
"optional": false,
"filter": true
},
{
"name": "identifier",
"sortable": true,
"style": {"width": "180px"},
"filter": true
},
{
"name": "description",
"sortable": true,
"style": {"width": "180px"},
"filter": true
}
]
}
]
}
\ No newline at end of file
{
"name": "user",
"title": "user.title",
"fieldToShowInActon": "username",
"titleDesc": "user.title.desc",
"icon": "<i class=\"fa fa-user fa-1_5x\"></i>",
"service": "./service/user",
"recordId": "id",
"showFormIn": "standard",
"definitionReport": "user-report-1",
"attributes": [
{
"name": "id",
"type": "number",
"formOptions": {
"options": {
"readonly": true,
"hideInNew": true,
"styleClass": "col-xs-3 col-sm-6 col-md-6"
},
"validators": [
"required"
],
"controlType": "number"
}
},
{
"name": "username",
"type": "string",
"formOptions": {
"options": {
"styleClass": "col-xs-3 col-sm-6 col-md-6",
"showLength": true,
"maxLength": 25
},
"validators": [
"required",
"identifier",
{
"name": "minLength",
"value": 3
},
{
"name": "maxLength",
"value": 25
}
],
"controlType": "text"
}
},
{
"name": "password",
"type": "string",
"formOptions": {
"controlType": "password",
"options": {
"styleClass": "col-md-6",
"showLength": true,
"maxLength": 30,
"showStrength": false
},
"validators": [
"required",
{
"name": "validatePassword",
"isRemote": true,
"service": "validate/password"
}
]
}
},
{
"name": "defaultRole",
"type": "string",
"formOptions": {
"options": {
"sourceService": "./service/user-role",
"sourceValue": "id",
"sourceLabel": "identifier",
"showSuggest": true,
"styleClass": "col-md-6"
},
"validators": [
"required"
],
"controlType": "select"
}
},
{
"name": "roleList",
"type": "string",
"formOptions": {
"options": {
"sourceService": "./service/user-role",
"sourceValue": "id",
"sourceLabel": "identifier",
"styleClass": "col-md-6",
"multiple": true
},
"validators": [
"required"
],
"controlType": "select"
}
},
{
"name": "firstName",
"type": "string",
"formOptions": {
"options": {
"styleClass": "col-xs-3 col-sm-6 col-md-6",
"showLength": true,
"maxLength": 30
},
"validators": [
"required",
"names",
{
"name": "minLength",
"value": 2
}
],
"controlType": "text"
}
},
{
"name": "secondName",
"type": "string",
"formOptions": {
"options": {
"styleClass": "col-xs-3 col-sm-6 col-md-6",
"showLength": true,
"maxLength": 30
},
"validators": [
"names",
{
"name": "minLength",
"value": 2
}
],
"controlType": "text"
}
},
{
"name": "firstSurname",
"type": "string",
"formOptions": {
"options": {
"styleClass": "col-xs-3 col-sm-6 col-md-6",
"showLength": true,
"maxLength": 30
},
"validators": [
"names",
"required",
{
"name": "minLength",
"value": 2
}
],
"controlType": "text"
}
},
{
"name": "secondSurname",
"type": "string",
"formOptions": {
"options": {
"styleClass": "col-xs-3 col-sm-6 col-md-6",
"showLength": true,
"maxLength": 30
},
"validators": [
"names",
"required",
{
"name": "minLength",
"value": 2
}
],
"controlType": "text"
}
},
{
"name": "sex",
"type": "string",
"formOptions": {
"values": {
"M": "label.sex.m",
"F": "label.sex.f"
},
"selected": "F",
"options": {
"showInline": true
},
"validators": [],
"controlType": "radio"
}
},
{
"name": "salutationPrefer",
"type": "string",
"formOptions": {
"values": {
"01": "Sr.",
"02": "Sra."
},
"options": {
"styleClass": "col-md-3"
},
"validators": [
"required"
],
"controlType": "select"
}
},
{
"name": "birthday",
"type": "date",
"formOptions": {
"controlType": "datepicker",
"validators": [
"required"
],
"options": {
"editabled": false,
"styleClass": "col-md-6"
}
}
},
{
"name": "phoneNumber",
"type": "string",
"formOptions": {
"options": {
"showSuggest": false,
"maxLength": 20,
"styleClass": "col-md-3"
},
"validators": [
"required",
{
"name": "pattern",
"value": "^[+]*[(]{0,1}[0-9]{1,4}[)]{0,1}[-\\s\\./0-9]*$"
}
],
"controlType": "text"
}
},
{
"name": "businessEmail",
"type": "string",
"formOptions": {
"options": {
"rightIcon": "mail",
"maxLength": 80,
"styleClass": "col-xl-6"
},
"validators": [
"required",
"email"
],
"controlType": "text"
}
},
{
"name": "status",
"type": "valpos",
"formOptions": {
"values": {
"LO": "user.status.locked",
"AC": "user.status.active",
"IN": "user.status.inactive",
"XP": "user.status.password.expired",
"CR": "user.status.created",
"DE": "user.status.deleted"
},
"controlType": "badge",
"options": {
"hideInNew": true,
"styleClass": "col-md-6",
"styles": {
"LO": "label label-warning",
"AC": "label label-primary",
"IN": "label label-danger",
"XP": "label label-warning",
"CR": "label label-warning",
"DE": "label label-danger"
}
}
}
}
],
"groups": [
{
"name": "user_info",
"title": "user_group_user_info",
"description": "country_group_info_description",
"controls": [
[
"username", "status"
],
[ "password" ],
[
"defaultRole",
"roleList"
]
]
},
{
"name": "personal_info",
"title": "user_group_personal_info",
"description": "country_group_info_description",
"controls": [
[
"firstName",
"secondName",
"firstSurname",
"secondSurname",
"gender",
"sex",
"birthday"
]
]
},
{
"name": "contact_info",
"title": "user_group_contact_info",
"description": "country_group_info_description",
"controls": [
[
"salutationPrefer", "phoneNumber",
"businessEmail"
]
]
}
],
"grid": [
{
"sortColumnDefault": "username",
"sortColumnDirection": "desc",
"pagingSize": 5,
"expandRow": true,
"columns": [
{
"name": "username",
"sortable": true,
"style": {
"width": "100px"
},
"optional": false,
"filter": true
},
{
"name": "firstName",
"sortable": true,
"style": {
"width": "100px"
},
"optional": false,
"filter": true
},
{
"name": "firstSurname",
"sortable": true,
"style": {
"width": "100px"
},
"optional": false,
"filter": true
},
{
"name": "businessEmail",
"sortable": true,
"style": {
"width": "100px"
},
"optional": false,
"filter": true
},
{
"name": "status",
"sortable": true,
"style": {
"width": "50px"
},
"optional": false,
"filter": true
}
]
}
]
}
\ No newline at end of file
{
"name": "application",
"title": "application.title",
"fieldToShowInActon": "identifier",
"icon": "<i class=\"fa fa-window-restore\"></i>",
"service": "./service/application",
"recordId": "id",
"showFormIn": "standard",
"definitionReport": "application-report-1",
"attributes": [
{
"name": "id",
"type": "number",
"formOptions": {
"options": {
"readonly": true,
"hideInNew": true,
"styleClass": "col-xs-12 col-sm-6 col-md-6"
},
"validators": [
"required"
],
"controlType": "number"
}
},
{
"name": "identifier",
"type": "string",
"formOptions": {
"options": {
"styleClass": "col-xs-12 col-sm-6 col-md-6",
"showLength": true,
"maxLength": 60
},
"validators": [
"required"
],
"controlType": "text"
}
},
{
"name": "description",
"type": "string",
"formOptions": {
"options": {
"styleClass": "col-xs-12 col-sm-6 col-md-6",
"showLength": true,
"maxLength": 200
},
"validators": [
"required"
],
"controlType": "text"
}
},
{
"name": "redirectURL",
"type": "string",
"formOptions": {
"options": {
"styleClass": "col-xs-12 col-sm-6 col-md-6",
"showLength": true,
"maxLength": 2000
},
"validators": [
"required"
],
"controlType": "text"
}
},
{
"name": "clientId",
"type": "string",
"formOptions": {
"options": {
"readonly": true,
"styleClass": "col-xs-12 col-sm-6 col-md-6"
},
"controlType": "text"
}
},
{
"name": "clientSecret",
"type": "string",
"formOptions": {
"options": {
"readonly": true,
"styleClass": "col-xs-12 col-sm-6 col-md-6"
},
"controlType": "text"
}
},
{
"name": "status",
"type": "valpos",
"formOptions": {
"values": {
"A": "user.status.active",
"I": "user.status.inactive"
},
"controlType": "badge",
"options": {
"hideInNew": true,
"styleClass": "col-md-6",
"styles": {
"A": "label label-primary",
"I": "label label-danger"
}
}
}
}
],
"groups": [
{
"name": "info",
"title": "",
"description": "country_group_info_description",
"controls": [
[
"identifier", "status"
],
"description",
"returnPath",
"clientId",
"clientSecret"
]
}
],
"grid": [
{
"sortColumnDefault": "identifier",
"sortColumnDirection": "desc",
"pagingSize": 5,
"expandRow": false,
"columns": [
{
"name": "identifier",
"sortable": true,
"style": {
"width": "100px"
},
"optional": false,
"filter": true
},
{
"name": "description",
"sortable": true,
"style": {
"width": "180px"
},
"filter": true
},
{
"name": "redirectURL",
"sortable": true,
"style": {
"width": "180px"
},
"filter": true
},
{
"name": "status",
"sortable": true,
"style": {
"width": "50px"
},
"optional": false,
"filter": true
}
]
}
]
}
\ No newline at end of file
{
"name": "system_settings_information",
"title": "system_settings_information_title",
"titleDesc": "system_settings_information_title_desc",
"icon": "<i class=\"fa fa-info-circle fa-2x\"></i>",
"service": "./service/system-settings/information",
"attributes": [
{
"name": "name",
"type": "string",
"formOptions": {
"options": {
"max-length": "200",
"styleClass": "col-12"
},
"validators": [
"required"
]
}
},
{
"name": "email",
"type": "string",
"formOptions": {
"options": {
"rightIcon": "mail",
"rightIconLabel": "",
"showLength": true,
"maxLength": 200,
"styleClass": "col-12"
},
"validators": [
"required",
"email"
]
}
},
{
"name": "domain",
"type": "string",
"formOptions": {
"options": {
"rightIcon": "http",
"rightIconLabel": "",
"showLength": true,
"maxLength": 200,
"styleClass": "col-12"
},
"validators": [
"required",
"url"
]
}
},
{
"name": "image",
"type": "file-upload",
"formOptions": {
"options": {
"text": "btn.upload.image",
"param": "file",
"target": "./service/file/upload",
"height": "250px",
"styleClass": "col-6"
},
"controlType": "file-upload"
}
}
],
"groups": [
{
"name": "info",
"title": "",
"description": "settings_information_group_info_description",
"controls": [
"name",
"email",
"domain",
["image"]
]
}
]
}
\ No newline at end of file
{
"name": "system_settings_password",
"title": "system_settings_password_title",
"titleDesc": "system_settings_password_title_desc",
"icon": "<i class=\"fa fa-key fa-2x\"></i>",
"service": "./service/system-settings/password",
"attributes": [
{
"name": "includeUppercase",
"type": "boolean",
"formOptions": {
"options": {
"showSuggest": true,
"styleClass": "col-12"
},
"controlType": "checkbox"
}
},
{
"name": "includeNumber",
"type": "boolean",
"formOptions": {
"options": {
"showSuggest": true,
"styleClass": "col-12"
},
"controlType": "checkbox"
}
},
{
"name": "notIncludeUserId",
"type": "boolean",
"formOptions": {
"options": {
"showSuggest": true,
"styleClass": "col-12"
},
"controlType": "checkbox"
}
},
{
"name": "notIncludeReverseUserId",
"type": "boolean",
"formOptions": {
"options": {
"showSuggest": true,
"styleClass": "col-12"
},
"controlType": "checkbox"
}
},
{
"name": "passwordMinLength",
"type": "boolean",
"formOptions": {
"options": {
"showSuggest": true,
"styleClass": "col-12"
},
"controlType": "checkbox"
}
}
]
}
\ No newline at end of file
{
"name": "system_settings_userpolicy",
"title": "system_settings_userpolicy_title",
"titleDesc": "system_settings_userpolicy_title_desc",
"icon": "<i class=\"fa fa-user-secret fa-2x\"></i>",
"service": "./service/system-settings/userpolicy",
"attributes": [
{
"name": "maxFailLogin",
"type": "number",
"formOptions": {
"options": {
"showSuggest": true,
"styleClass": "col-12"
},
"validators": [
"required",
{
"name": "min",
"value": 0
},
{
"name": "max",
"value": 99
}
],
"controlType": "number"
}
},
{
"name": "historyValidation",
"type": "number",
"formOptions": {
"options": {
"showSuggest": true,
"styleClass": "col-12"
},
"validators": [
"required",
{
"name": "min",
"value": 0
},
{
"name": "max",
"value": 99
}
],
"controlType": "number"
}
},
{
"name": "userInactivity",
"type": "number",
"formOptions": {
"options": {
"showSuggest": true,
"styleClass": "col-12"
},
"validators": [
"required",
{
"name": "min",
"value": 0
},
{
"name": "max",
"value": 99
}
],
"controlType": "number"
}
},
{
"name": "passwordExpiration",
"type": "number",
"formOptions": {
"options": {
"showSuggest": true,
"styleClass": "col-12"
},
"validators": [
"required",
{
"name": "min",
"value": 0
},
{
"name": "max",
"value": 99
}
],
"controlType": "number"
}
},
{
"name": "automaticUnlock",
"type": "number",
"formOptions": {
"options": {
"showSuggest": true,
"styleClass": "col-12"
},
"validators": [
"required",
{
"name": "min",
"value": 0
},
{
"name": "max",
"value": 99
}
],
"controlType": "number"
}
},
{
"name": "manageAccountByEmail",
"type": "boolean",
"formOptions": {
"options": {
"showSuggest": true,
"styleClass": "col-12"
},
"controlType": "checkbox"
}
}
]
}
\ No newline at end of file
{
"name": "valpos",
"title": "valpos.title",
"fieldToShowInActon": "identifier",
"icon": "<i class=\"glyphicon glyphicon-list\"></i>",
"service": "./service/possible-value",
"recordId": "id",
"showFormIn": "standard",
"definitionReport": "valpos-report-1",
"attributes": [
{
"name": "id",
"type": "number",
"formOptions": {
"options": {
"readonly": true,
"hideInNew": true,
"styleClass": "col-xs-12 col-sm-6 col-md-6"
},
"validators": [
"required"
],
"controlType": "number"
}
},
{
"name": "identifier",
"type": "string",
"formOptions": {
"options": {
"styleClass": "col-xs-12 col-sm-6 col-md-6",
"showLength": true,
"maxLength": 20
},
"validators": [
"required"
],
"controlType": "text"
}
},
{
"name": "description",
"type": "string",
"formOptions": {
"options": {
"styleClass": "col-xs-12 col-sm-6 col-md-6",
"showLength": true,
"maxLength": 200
},
"validators": [
"required"
],
"controlType": "text"
}
}
],
"groups": [
{
"name": "info",
"title": "",
"description": "country_group_info_description",
"controls": [
[
"id"
],
"identifier",
"description"
]
}
],
"grid": [
{
"sortColumnDefault": "id",
"sortColumnDirection": "desc",
"pagingSize": 5,
"expandRow": false,
"columns": [
{
"name": "id",
"sortable": true,
"style": {
"width": "100px"
},
"optional": false,
"filter": true
},
{
"name": "identifier",
"sortable": true,
"style": {
"width": "180px"
},
"filter": true
},
{
"name": "description",
"sortable": true,
"style": {
"width": "180px"
},
"filter": true
}
]
}
]
}
\ No newline at end of file
[
{
"name": "system_settings_information",
"label": "tabs.system.settings.information.title",
"description": "tabs.system.settings.information.title.desc",
"path": "/settings/system-settings/information",
"icon": "<i class=\"fa fa-info-circle fa-1_5x\"></i>"
},
{
"name": "system_settings_password",
"label": "tabs.system.settings.password.title",
"description": "tabs.system.settings.password.title.desc",
"path": "/settings/system-settings/password",
"icon": "<i class=\"fa fa-key fa-1_5x\"></i>"
},
{
"name": "system_settings_userpolicy",
"label": "tabs.system.settings.userpolicy.title",
"description": "tabs.system.settings.userpolicy.title.desc",
"path": "/settings/system-settings/userpolicy",
"icon": "<i class=\"fa fa-user-secret fa-1_5x\"></i>"
}
]
\ No newline at end of file
[
"view",
"edit",
"delete",
"new"
]
\ No newline at end of file
{"itemsPerPage":10,"currentPage":0,"totalItems":2,"totalPages":1,"data":[{"id":1,"name":"ENTIDAD1","description":"ENTIDAD 1"},{"id":2,"name":"ENTIDAD2","description":"ENTIDAD 2"}]}
\ No newline at end of file
{
"summary": {
"sessionInactivity": {
"value": 30,
"history": [
10,
10,
10,
10,
10,
10,
10
],
"percent": 2,
"up": true
},
"totalSessions": {
"value": 30,
"percent": 2,
"up": true,
"history": [10, 8, 6, 5, 6, 8, 10]
},
"totalReceivedMessages": {
"value": 30,
"percent": 2,
"down": true,
"history": [1, 5, 3, 8, 4, 10, 0]
},
"totalSentMessages": {
"value": 30,
"percent": 2,
"down": true,
"history": [10, 8, 6, 5, 6, 8, 10]
}
},
"averages": {
"firstResponseAverage": 1.2,
"sessionAverage": 1.2
},
"customerMessageDetail": [
[
1577854800000,
0,
2.7
],
[
1577854800000,
1,
2.5
],
[
1577854800000,
2,
3.5
],
[
1577854800000,
3,
4.5
],
[
1577854800000,
4,
5.5
],
[
1577854800000,
5,
2.5
],
[
1577854800000,
6,
2.5
],
[
1577854800000,
7,
2.5
],
[
1577854800000,
8,
2.5
],
[
1577854800000,
9,
2.5
],
[
1577854800000,
10,
2.5
],
[
1577854800000,
11,
2.5
],
[
1577854800000,
12,
2.5
],
[
1577854800000,
13,
2.5
],
[
1577854800000,
14,
2.5
],
[
1577854800000,
15,
2.5
],
[
1577854800000,
16,
2.5
],
[
1577854800000,
17,
2.5
],
[
1577854800000,
18,
2.5
],
[
1577854800000,
19,
2.5
],
[
1577854800000,
20,
2.5
],
[
1577854800000,
21,
2.5
],
[
1577854800000,
22,
2.5
],
[
1577854800000,
23,
2.5
],
[
1577941200000,
0,
9
],
[
1577941200000,
1,
11
],
[
1577941200000,
2,
12
],
[
1577941200000,
3,
11
],
[
1577941200000,
4,
15
],
[
1577941200000,
5,
16
],
[
1577941200000,
6,
17
],
[
1577941200000,
7,
18
],
[
1577941200000,
8,
19
],
[
1577941200000,
9,
11
],
[
1577941200000,
10,
12
],
[
1577941200000,
11,
13
],
[
1577941200000,
12,
14
],
[
1577941200000,
13,
12
],
[
1577941200000,
14,
15
],
[
1577941200000,
15,
19
],
[
1577941200000,
16,
20
],
[
1577941200000,
17,
16
],
[
1577941200000,
18,
18
],
[
1577941200000,
19,
15
],
[
1577941200000,
20,
15
],
[
1577941200000,
21,
15
],
[
1577941200000,
22,
15
],
[
1577941200000,
23,
15
],
[
1578027600000,
0,
13
],
[
1578027600000,
1,
12
],
[
1578027600000,
2,
3
],
[
1578027600000,
3,
12
],
[
1578027600000,
4,
4
],
[
1578027600000,
5,
8
],
[
1578027600000,
6,
15
],
[
1578027600000,
7,
12
],
[
1578027600000,
8,
19
],
[
1578027600000,
9,
2
],
[
1578027600000,
10,
16
],
[
1578027600000,
11,
16
],
[
1578027600000,
12,
19
],
[
1578027600000,
13,
9
],
[
1578027600000,
14,
7
],
[
1578027600000,
15,
19
],
[
1578027600000,
16,
9
],
[
1578027600000,
17,
13
],
[
1578027600000,
18,
17
],
[
1578027600000,
19,
13
],
[
1578027600000,
20,
16
],
[
1578027600000,
21,
10
],
[
1578027600000,
22,
10
],
[
1578027600000,
23,
19
],
[
1578114000000,
0,
17
],
[
1578114000000,
1,
6
],
[
1578114000000,
2,
13
],
[
1578114000000,
3,
4
],
[
1578114000000,
4,
7
],
[
1578114000000,
5,
4
],
[
1578114000000,
6,
9
],
[
1578114000000,
7,
9
],
[
1578114000000,
8,
3
],
[
1578114000000,
9,
9
],
[
1578114000000,
10,
11
],
[
1578114000000,
11,
7
],
[
1578114000000,
12,
14
],
[
1578114000000,
13,
15
],
[
1578114000000,
14,
8
],
[
1578114000000,
15,
11
],
[
1578114000000,
16,
14
],
[
1578114000000,
17,
19
],
[
1578114000000,
18,
3
],
[
1578114000000,
19,
20
],
[
1578114000000,
20,
6
],
[
1578114000000,
21,
13
],
[
1578114000000,
22,
10
],
[
1578114000000,
23,
18
],
[
1578114000000,
24,
16
]
]
}
\ No newline at end of file
[
"system_settings",
"valpos",
"user_role",
"user",
"entidades",
"estados",
"motivos",
"categoria_motivo",
"CONVERSATIONAL_AGENT",
"OPERATIVE_DASHBOARD",
"customer_interaction_dashboard",
"CONVERSATIONAL_AIRPORT"
]
\ No newline at end of file
[
{"id": 1, "name": "Perú (+51)", "code": "+51"},
{"id": 2, "name": "Chile (+52)", "code": "+52"},
{"id": 3, "name": "México (+53)", "code": "+53"}
]
\ No newline at end of file
[
{
"id": 1,
"username": "agutierrez",
"firstName": "Aaron",
"secondName": "Junior",
"firstLastName": "Gutiérrez",
"secondLastName": "López",
"email": "agutierrez@bytesw.com",
"gender": "M",
"maritalStatus": "S",
"birthday": "2020-03-10",
"phone": "952226613",
"countryCode": 1,
"principalRole": 1,
"assignedRoles": [1, 2],
"status": "A"
},
{
"id": 2,
"username": "mortiz",
"firstName": "Marco",
"secondName": "Antonio",
"firstLastName": "Ortiz",
"secondLastName": "García",
"email": "mortiz@bytesw.com",
"gender": "M",
"maritalStatus": "C",
"birthday": "2020-03-10",
"phone": "952226613",
"countryCode": 1,
"principalRole": 1,
"assignedRoles": [1, 2],
"status": "I"
}
]
\ No newline at end of file
[
{ "id": 1, "identifier": "ADMIN", "description": "Aministración" },
{ "id": 2, "identifier": "XDFUSER", "description": "XdfUser" }
]
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"title.error": "Error",
"title.http.error": "Http Error",
"title.not.http.error": "Error!"
}
\ No newline at end of file
{
"title.error": "Error",
"title.http.error": "Error Http",
"title.not.http.error": "Error!"
}
\ No newline at end of file
{
"HOME": "Start",
"BACK": "Back",
"home.subtitle": "Welcome to XDF Project",
"home.comments": "It is an application skeleton for a typical web app. You can use it to quickly bootstrap your webapp projects and dev environment.",
"btn.previous": "Back",
"label.agent": "Agents",
"agent_avatar": "Avatar",
"agent_code": "ID",
"agent_name": "Name",
"agent_version": "Version",
"agent_status": "Status",
"agent_country": "Country",
"agent_timezone": "Timezone",
"btn.file.upload" : "Upload",
"btn.accept": "Accept",
"label.deployment-channels.title": "Deployment channels",
"label.deployment-channels.description": "Configure the messaging channels that will be used by the agent",
"label.channels": "Configured channels",
"label.active": "Active",
"label.inactive": "Inactive",
"label.name": "Name",
"label.deployment-channels.configuration": "Deployment channels",
"label.deployment-channels.configuration.description": "Select a deployment channel",
"label.status.pending" : "Pending",
"label.status.loaded" : "Loaded",
"label.status.off" : "Disabled",
"label.created": "Created",
"label.deployed": "Deployed",
"label.sync-pending": "Sync pending",
"breadcrumb.agent": "Agents",
"label.general-information.title" : "General information",
"label.general-information.description" : "Register the basic information for the agent",
"label.avatar" : "Avatar",
"label.description" : "Description",
"label.version" : "Version",
"label.country" : "Country",
"label.timezone" : "Timezone",
"label.language" : "Language",
"label.type" : "Agent type",
"label.questions.title" : "Frequent questions",
"label.questions.description" : "Upload files whose content will be used as training for the agent",
"btn.new.file" : "New file",
"label.file.id" : "ID",
"label.file.name" : "Name",
"label.file.description" : "Description",
"label.file.status" : "Status",
"label.file.user" : "User",
"label.file.upload.date" : "Loaded date",
"label.file-upload.title" : "Questions file",
"label.file-upload.description" : "The question file will be used as material training",
"label.file" : "File",
"label.file.incompatible.extension" : "Invalid file. Just accept the following file extensions ",
"label.imageAvatar.incompatible.extension" : "Invalid file. Just accept the followeing image types ",
"label.delete-channel": "Delete channel",
"agent.edit.success": "The agent was successfully edited",
"agent.create.success": "The agent was created successfully",
"agent.synchronize.success": "Synchronization was successful",
"error.message.complete-form": "Complete the form correctly",
"label.file.tooltip" : "For security reasons, you cannot edit uploaded files. Please delete and upload a new file",
"EMPTY.VALUE": "Empty value",
"NOT.FOUND.VALUE": "Value not found",
"header.type": "Column",
"header.header": "Column",
"header.line": "Row",
"header.value": "Value",
"HEADER.REPETEAD": "Repeated column",
"HEADER.NOT.FOUND": "Column not found",
"label.file-upload.error.subtitle": "Error detail",
"label.file-upload.error.description": "An error occurred in the validation of the file.",
"btn.synchronize": "Synchronize"
}
\ No newline at end of file
{
"HOME": "Inicio",
"BACK": "Regresar",
"home.subtitle": "Bienvenido al proyecto XDF",
"home.comments": "Este proyecto presenta una aplicación web típica. Puede usarlo como un marco de referencia para el desarrollo de sus aplicaciones web.",
"btn.previous": "Atrás",
"label.agent": "Agentes",
"agent_avatar": "Avatar",
"agent_code": "ID",
"agent_name": "Nombre",
"agent_version": "Versión",
"agent_status": "Estado",
"agent_country": "País",
"agent_timezone": "Zona horaria",
"agent_publish_version": "Versión publicada",
"btn.file.upload": "Cargar",
"btn.accept": "Aceptar",
"label.deployment-channels.title": "Canales de mensajería",
"label.deployment-channels.description": "Configure los canales de mensajería por los cuales interactuará el agente",
"label.channels": "Canales configurados",
"label.active": "Activo",
"label.inactive": "Inactivo",
"label.name": "Nombre",
"label.deployment-channels.configuration": "Canales de mensajería",
"label.deployment-channels.configuration.description": "Seleccione un canal de mensajería",
"label.status.pending": "Pendiente",
"label.status.loaded": "Cargado",
"label.status.off": "En Baja",
"label.created": "Creado",
"label.deployed": "Desplegado",
"label.sync-pending": "Pendiente de sincronización",
"breadcrumb.agent": "Agentes",
"label.general-information.title": "Información general",
"label.general-information.description": "Registre la información correspondiente al agente",
"label.avatar": "Avatar",
"label.description": "Descripción",
"label.version": "Versión",
"label.country": "País",
"label.timezone": "Zona horaria",
"label.language": "Idioma",
"label.type": "Tipo de agente",
"label.questions.title": "Preguntas frecuentes",
"label.questions.description": "Cargue los archivos con las preguntas frecuentes de entrenamiento",
"btn.new.file": "Nuevo archivo",
"label.file.id": "ID",
"label.file.name": "Nombre",
"label.file.description": "Descripción",
"label.file.status": "Estado",
"label.file.user": "Usuario",
"label.file.upload.date": "Fecha de carga",
"label.file-upload.title": "Archivo de preguntas",
"label.file-upload.description": "El archivo de preguntas se utilizará para el entrenamiento del bot",
"label.file": "Archivo",
"label.file.incompatible.extension": "Archivo no válido. Sólo se aceptan archivos con extensión ",
"label.imageAvatar.incompatible.extension": "Archivo no válido. Sólo se aceptan imágenes y con formato ",
"label.delete-channel": "Borrar canal",
"agent.edit.success": "El agente fue editado correctamente",
"agent.create.success": "El agente fue creado correctamente",
"agent.synchronize.success": "La sincronización se realizó correctamente",
"error.message.complete-form": "Complete correctamente el formulario",
"label.file.tooltip": "Por seguridad, no se pueden editar los archivos validados",
"EMPTY.VALUE": "Celda vacía",
"NOT.FOUND.VALUE": "Valor no encontrado",
"header.type": "Columna",
"header.header": "Columna",
"header.line": "Fila",
"header.value": "Valor",
"HEADER.REPETEAD": "Columna repetida",
"HEADER.NOT.FOUND": "Columna no encontrado",
"label.file-upload.error.subtitle": "Detalle de error",
"label.file-upload.error.description": "Ha ocurrido un error en la validación del archivo.",
"btn.retry": "Cargar otro archivo",
"btn.synchronize": "Publicar",
"btn.upload.file": "Subir archivo",
"query.filters.endDate": "Fecha de fin",
"query.filters.startDate": "Fecha de inicio",
"query.filters.channel": "Canal",
"dashboards.operative.title": "Dashboard de indicadores operativos",
"dashboards.operative.title.desc": "Consulte los indicadores de sesión y mensajes dentro de las operaciones del bot",
"dashboards.customer.interaction.title": "Dashboard de indicadores de interacción",
"dashboards.customer.interaction.title.desc": "Consulte los indicadores de interacción en relación a las intenciones del cliente",
"dashboards.operative.session.time.desc": "Tiempo en días, horas y minutos transcurridos desde la última sesión",
"dashboards.operative.session.total.desc": "Número de conversaciones realizadas a través del bot",
"dashboards.operative.message.received.desc": "Número de mensajes generados por los clientes a través del bot",
"dashboards.operative.message.sended.desc": "Número de mensajes generados en respuesta a la solicitud de un cliente",
"dashboards.operative.message.customer.activity": "Frecuencia de mensajes por hora",
"pipe.format.day": "d",
"pipe.format.hour": "h",
"pipe.format.minute": "m",
"pipe.format.seconds": "s",
"dashboards.operative.inactivity.sessions": "Tiempo de inactividad",
"dashboards.operative.avg.sessions": "Promedio de sesiones por cliente",
"dashboards.operative.sessions": "Total de sesiones",
"dashboards.operative.receveid": "Total de mensajes recibidos",
"dashboards.operative.sended": "Total de mensajes enviados",
"dashboards.customer.interaction.tracing.intent": "Histórico de las intenciones",
"dashboards.customer.interaction.avg.intent": "Promedio de intenciones por cliente",
"dashboards.customer.interaction.goals": "Cantidad de objetivos cumplidos",
"dashboards.customer.interaction.sentences": "Frases no identificadas",
"dashboards.customer.interaction.intents": "Intenciones más utilizadas",
"security.password.error.passwordMinLength": "La contraseña no cumple con el mínimo de caracteres configurado.",
"message.error.duplicated": "Registro duplicado"
}
\ No newline at end of file
{
"btn.search": "Search for",
"btn.save": "Save",
"btn.back": "Back",
"btn.new": "New",
"btn.edit": "Edit",
"btn.delete": "Delete",
"btn.close": "Close",
"btn.yes": "Yes",
"btn.no": "No",
"btn.cancel": "Cancel",
"btn.next": "Next",
"btn.reset": "Reset",
"btn.audit": "Audit",
"btn.show.more": "Show more",
"btn.upload.image": "Upload image",
"btn.execute": "Execute",
"paginator.item.per.page": "Items per page: ",
"paginator.next.page": "Next Page",
"paginator.previous.page": "Previous Page",
"paginator.range": "of",
"label.range.today": "Today",
"label.range.yesterday": "Yesterday",
"label.range.last.7.days": "Last 7 days",
"label.range.last.30.days": "last 30 days",
"label.range.this.month": "This month",
"label.range.last.month": "Last month",
"label.range.custom": "Custom range",
"label.boolean.true": "Yes",
"label.boolean.false": "No",
"title.grid.actions": "Actions",
"action.grid.edit": "Click to Edit",
"action.grid.delete": "Click to Delete",
"action.grid.columns": "Columns",
"action.grid.filter": "Filters",
"action.grid.filter.button": "Filter",
"action.grid.filter.help": "Help",
"action.grid.filter.clear": "Clear all filters",
"action.grid.export.excel": "Export to xls",
"action.grid.export.pdf": "Export to pdf",
"action.grid.refresh": "Refresh",
"action.message.edit": "Editing: ",
"action.message.view": "Viewing: ",
"audit.grid.update": "<b>{{ user }}</b> actualizó el registro con id: <b>{{ id }}</b>",
"audit.grid.create": "<b>{{ user }}</b> creó el registro con id: <b>{{ id }}</b>",
"audit.dialog.title": "Audit Info",
"message.error.validateAge": "The age must be over 17 years and less that 100",
"message.error.email": "The email does not comply with the format",
"message.error.required": "The \"{{ label }}\" field is required",
"message.error.minlength": "The \"{{ label }}\" field supports at least \"{{requiredLength}}\" characters",
"message.error.maxlength": "The \"{{ label }}\" field supports at maximum \"{{requiredLength}}\" characters",
"message.error.min": "Value must be greater equal that to \"{{ min }}\"",
"message.error.max": "Value must be less equal that to \"{{ max }}\"",
"message.error.pattern": "The \"{{ label }}\" field does not meet the required format",
"message.error.duplicity.name": "The value entered already exists",
"message.error.matDatepickerParse": "The value input is not valid",
"message.error.resource.authorization": "Don't have access to the program",
"message.error.matDatepickerMin": "The date must be greater than {{ min }}",
"message.error.array.required": "You must select at least one item",
"message.error.identifier": "The \"{{ label }}\" field can only contain numbers, letters and underscore",
"message.error.names": "The \"{{ label }}\" field is not valid",
"title.dirty.confirmation": "Confirm",
"title.delete.confirmation": "Delete",
"title.information": "Information",
"message.update.succesful": "Registration updated successfully",
"message.create.succesful": "The record was created successfully",
"message.dirty.confirmation": "You have unsaved changes. Are you sure you want to leave?",
"message.delete.confirmation": "Are you sure you want to delete?",
"title.error.conflict": "Conflict between versions",
"message.error.conflict": "During the registry edition, another user modified the value.",
"label.actual.value": "Current value",
"message.error.unauthorized": "Does not have permissions for this option",
"wizard.title.done": "Confirmation",
"security.message.error.title": "Security Error!",
"security.message.error.parameter": "Route requires 'parameter name'",
"security.message.error.parameter.not.found": "Not Found 'program' Parameter",
"settings.message.error.title": "Settings Error!",
"inner.content.notfound.error": "Have not configured internal content for the rows",
"datatype.filter.error": "The field '{{field}}' does not allow the type of data entered",
"label.autocomplete.search": "Search.."
}
\ No newline at end of file
{
"btn.search": "Buscar",
"btn.save": "Guardar",
"btn.back": "Regresar",
"btn.new": "Nuevo",
"btn.edit": "Editar",
"btn.delete": "Eliminar",
"btn.close": "Cerrar",
"btn.yes": "Si",
"btn.no": "No",
"btn.cancel": "Cancelar",
"btn.next": "Siguiente",
"btn.reset": "Reiniciar",
"btn.audit": "Auditoría",
"btn.show.more": "Ver más",
"btn.upload.image": "Subir imagen",
"btn.execute": "Ejecutar",
"paginator.item.per.page": "Resultados por página: ",
"paginator.next.page": "Siguiente Página",
"paginator.previous.page": "Anterior Página",
"paginator.range": "de",
"label.range.today": "Hoy",
"label.range.yesterday": "Ayer",
"label.range.last.7.days": "Últimos 7 días",
"label.range.last.30.days": "Últimos 30 días",
"label.range.this.month": "Mes actual",
"label.range.last.month": "Mes anterior",
"label.range.custom": "Personalizado",
"label.boolean.true": "Si",
"label.boolean.false": "No",
"title.grid.actions": "Acciones",
"action.grid.edit": "Editar",
"action.grid.delete": "Eliminar",
"action.grid.columns": "Columnas",
"action.grid.filter": "Filtros",
"action.grid.filter.button": "Filtrar",
"action.grid.filter.help": "Ayuda",
"action.grid.filter.clear": "Eliminar todos los filtros",
"action.grid.export.excel": "Exportar a xls",
"action.grid.export.pdf": "Exportar a pdf",
"action.grid.refresh": "Actualizar",
"action.message.edit": "Editando el registro: ",
"action.message.view": "Visualizando el registro: ",
"audit.grid.update": "<b>{{ user }}</b> actualizó el registro con id: <b>{{ id }}</b>",
"audit.grid.create": "<b>{{ user }}</b> creó el registro con id: <b>{{ id }}</b>",
"audit.dialog.title": "Información de Auditoría",
"message.error.validateAge": "La edad debe ser mayor de 17 años y menor de 100",
"message.error.email": "El email no cumple con el formato",
"message.error.required": "El campo \"{{ label }}\" es requerido",
"message.error.minlength": "El campo \"{{ label }}\" admite como mínimo \"{{ requiredLength }}\" caracteres",
"message.error.maxlength": "El campo \"{{ label }}\" admite como máximo \"{{ requiredLength }}\" caracteres",
"message.error.min": "El valor debe ser mayor o igual a \"{{ min }}\"",
"message.error.max": "El valor debe ser menor o igual a \"{{ max }}\"",
"message.error.pattern": "El campo \"{{ label }}\" no cumple con el formato requerido",
"message.error.duplicity.name": "El valor ingresado ya existe",
"message.error.matDatepickerParse": "El valor ingresado no es válido",
"message.error.resource.authorization": "No tiene acceso al programa",
"message.error.matDatepickerMin": "La fecha debe ser mayor a {{ min }}",
"message.error.array.required": "Debe seleccionar al menos un elemento",
"message.error.identifier": "El campo \"{{ label }}\" solo puede contener números, letras y guiones",
"message.error.names": "El campo \"{{ label }}\" no es válido",
"title.dirty.confirmation": "Confirmar",
"title.delete.confirmation": "Eliminar",
"title.error": "Error",
"title.information": "Información",
"message.update.succesful": "El registro se actualizó correctamente",
"message.create.succesful": "El registro se creó correctamente",
"message.dirty.confirmation": "El formulario tiene cambios no guardados. ¿Desea abandonarlo?",
"message.delete.confirmation": "¿Está seguro que desea eliminar el registro?",
"title.error.conflict": "Conflicto entre versiones",
"message.error.conflict": "Durante la edición del registo, otro usuario a modificado el valor",
"label.actual.value": "Valor actual",
"message.error.unauthorized": "No se tiene permiso para esta opción",
"wizard.title.done": "Confirmación",
"security.message.error.title": "Error de seguridad!",
"security.message.error.parameter": "Ruta requiere el parámetro '{{parameter}}'",
"security.message.error.parameter.not.found": "Parámetro '{{parameter}}' no encontrado",
"settings.message.error.title": "Error de configuración!",
"inner.content.notfound.error": "No ha configurado un contenido interno para las filas",
"datatype.filter.error": "El campo '{{field}}' no permite el tipo de dato ingresado",
"label.autocomplete.search": "Buscar.."
}
\ No newline at end of file
{
"language": "Language",
"en": "English",
"es": "Spanish",
"since": "{{now}}",
"back.to.top": "Back to Top",
"logout": "Logout",
"notfound.title": "We are sorry, Page not found!",
"notfound.subtitle": "The page you are looking for might have been removed had its name changed or is temporarily unavailable.",
"notfound.gohome": "Back To Homepage",
"title.chat": "Chat",
"title.application.options": "System Preferences",
"application.options.details": "This option allows users to customize their experience with the application. The settings will be maintained on this device and with this browser",
"application.options.exit": "Exit",
"title.roles.options": "Roles",
"roles.options.select.one": "Select the role you want to use"
}
\ No newline at end of file
{
"language": "Idioma",
"en": "Inglés",
"es": "Español",
"since": "{{now}}",
"back.to.top": "Volver arriba",
"logout": "Salir",
"notfound.title": "Lo sentimos, ¡página no encontrada!",
"notfound.subtitle": "La página que ud busca ha sido removida, ha cambiado de nombre o temporalmente no está disponible.",
"notfound.gohome": "Ir a Inicio",
"title.chat": "Chat",
"title.application.options": "Ajuste de sistema",
"application.options.details": "Está opción permite a los usuarios personalizar su experiencia con el aplicativo. Los ajustes se mantendrán en este dispositivo y con este navegador",
"application.options.exit": "Salir",
"title.roles.options": "Roles",
"roles.options.select.one": "Seleccione el rol que desea utilizar"
}
\ No newline at end of file
{
"menu.system.settings": "System settings",
"menu.cruds": "Configuration",
"menu.cruds.customer": "Customers",
"menu.cruds.country": "Countries",
"menu.security": "Security",
"menu.security.user": "User",
"menu.security.user.role": "User role",
"menu.settings": "System",
"menu.settings.application": "Applications",
"menu.settings.system": "System settings",
"menu.settings.valpos": "Possible values",
"menu.business.config": "Settings",
"menu.ticket.manager": "Ticket manager",
"menu.parent.dashboard": "Dashboard"
}
\ No newline at end of file
{
"menu.system.settings": "Sistema",
"menu.cruds": "Configuración",
"menu.cruds.customer": "Clientes",
"menu.cruds.country": "Ciudades",
"menu.security": "Seguridad",
"menu.security.user": "Usuario",
"menu.security.user.role": "Rol de usuario",
"menu.settings": "Sistema",
"menu.settings.application": "Aplicaciones",
"menu.settings.system": "Configuración de sistema",
"menu.settings.valpos": "Valores posibles",
"menu.business.config": "Configuración",
"menu.ticket.manager": "Gestor de tickets",
"menu.parent.agent": "Agentes",
"menu.parent.nuevo": "Aeropuertos",
"menu.parent.dashboard": "Dashboards",
"menu.dashboard.operative": "Indicadores operativos",
"menu.dashboard.customer.interaction": "Indicadores de interacción",
"menu.parent.airport": "Aeropuertos"
}
\ No newline at end of file
{
"login.title": "Login Page",
"breadcrumb.user.role": "User role",
"breadcrumb.user.role.detail": "User role",
"breadcrumb.user": "User",
"breadcrumb.user.detail": "User",
"control.new": "New",
"control.view": "View",
"control.edit": "Edit",
"control.delete": "Delete",
"control.export": "Export",
"control.audit": "Audit",
"control.execute": "Execute",
"label.username": "Username",
"label.password": "Password",
"label.sex.m": "Male",
"label.sex.f": "Female",
"user.role.title": "User role",
"user.role.title.desc": "User Role Manager",
"user_role_group_info_header": "General Information",
"user_role_id_header": "ID",
"user_role_identifier_header": "Identifier",
"user_role_description_header": "Description",
"user_role_form_id_placeholder": "ID",
"user_role_form_identifier_placeholder": "Identifier",
"user_role_form_description_placeholder": "Description",
"user.title": "Users",
"user.title.desc": "User Role Manager",
"user_group_info_header": "General Information",
"user_username_header": "Username",
"user_firstName_header": "First name",
"user_firstSurname_header": "Last name",
"user_businessEmail_header": "Email",
"user_status_header": "Status",
"user_group_user_info": "User Data",
"user_group_personal_info": "Personal information",
"user_group_contact_info": "Contact information",
"user_form_username_placeholder": "Username",
"user_form_password_placeholder": "Password",
"user_form_defaultRole_label": "Main role",
"user_form_defaultRole_suggest": "This role will be used as the default role in the application.",
"user_form_defaultRole_placeholder": "Main role",
"user_form_roleList_label": "Assigned roles",
"user_form_roleList_placeholder": "Assigned roles",
"user_form_firstName_placeholder": "First name",
"user_form_secondName_placeholder": "Second name",
"user_form_firstSurname_placeholder": "Last name",
"user_form_secondSurname_placeholder": "Mother's last name",
"user_form_salutationPrefer_label": "Salutation",
"user_form_salutationPrefer_placeholder": "Salutation",
"user_form_sex_label": "Gender",
"user_form_sex_placeholder": "Gender",
"user_form_birthday_placeholder": "Birthday",
"user_form_countryCode_label": "Country code",
"user_form_countryCode_placeholder": "Country code",
"user_form_phoneNumber_placeholder": "Phone",
"user_form_businessEmail_placeholder": "Email",
"user.status.locked": "Locked",
"user.status.active": "Active",
"user.status.inactive": "Inactive",
"user.status.password.expired": "password expired",
"user.status.created": "Created",
"user.status.deleted": "Deleted"
}
\ No newline at end of file
{
"login.title": "Identificación de Usuario",
"breadcrumb.user.role": "Rol de usuario",
"breadcrumb.user.role.detail": "Rol de usuario",
"breadcrumb.user": "Usuario",
"breadcrumb.user.detail": "Usuario",
"control.new": "Creación",
"control.view": "Visualizar",
"control.edit": "Edición",
"control.delete": "Eliminar",
"control.export": "Exportar",
"control.audit": "Ver auditoria",
"control.execute": "Ejecutar",
"label.username": "Usuario",
"label.password": "Contraseña",
"label.sex.m": "Masculino",
"label.sex.f": "Femenino",
"user.role.title": "Rol de usuario",
"user.role.title.desc": "Mantenimiento de roles de usuario",
"user_role_group_info_header": "Información General",
"user_role_id_header": "Id.",
"user_role_identifier_header": "Identificador",
"user_role_description_header": "Descripción",
"user_role_form_id_placeholder": "Id.",
"user_role_form_identifier_placeholder": "Identificador",
"user_role_form_description_placeholder": "Descripción",
"user.title": "Usuarios",
"user.title.desc": "Mantenimiento de usuarios",
"user_group_info_header": "Información General",
"user_username_header": "Código",
"user_firstName_header": "Primer nombre",
"user_firstSurname_header": "Apellido paterno",
"user_businessEmail_header": "Email",
"user_status_header": "Estado",
"user_group_user_info": "Datos de usuario",
"user_group_personal_info": "Datos personales",
"user_group_contact_info": "Datos de contacto",
"user_form_username_placeholder": "Código de usuario",
"user_form_password_placeholder": "Contraseña",
"user_form_defaultRole_label": "Rol principal",
"user_form_defaultRole_suggest": "Este rol será utilizado como rol por defecto en la aplicación.",
"user_form_defaultRole_placeholder": "Rol principal",
"user_form_roleList_label": "Roles asignados",
"user_form_roleList_placeholder": "Roles asignados",
"user_form_firstName_placeholder": "Primer nombre",
"user_form_secondName_placeholder": "Segundo nombre",
"user_form_firstSurname_placeholder": "Apellido paterno",
"user_form_secondSurname_placeholder": "Apellido Materno",
"user_form_salutationPrefer_label": "Saludo",
"user_form_salutationPrefer_placeholder": "Saludo",
"user_form_sex_label": "Género",
"user_form_sex_placeholder": "Género",
"user_form_birthday_placeholder": "Fecha de nacimiento",
"user_form_countryCode_label": "Código de país",
"user_form_countryCode_placeholder": "Código de país",
"user_form_phoneNumber_placeholder": "Teléfono",
"user_form_businessEmail_placeholder": "Correo electrónico",
"user.status.locked": "Bloqueado",
"user.status.active": "Activo",
"user.status.inactive": "Inactivo",
"user.status.password.expired": "Contraseña expirada",
"user.status.created": "Creado",
"user.status.deleted": "Eliminado"
}
\ No newline at end of file
{
"breadcrumb.application": "Application",
"breadcrumb.application.detail": "Application information",
"breadcrumb.valpos": "Possible value",
"breadcrumb.valpos.detail": "Possible value information",
"breadcrumb.settings.userpolicy": "User policy",
"breadcrumb.settings.information": "General information",
"breadcrumb.settings.password": "Password settings",
"tabs.system.settings.information.title": "Information",
"tabs.system.settings.information.title.desc": "Organization information",
"tabs.system.settings.password.title": "Password settings",
"tabs.system.settings.password.title.desc": "Security policies for the password",
"tabs.system.settings.userpolicy.title": "User policies",
"tabs.system.settings.userpolicy.title.desc": "Security policies for the application",
"security.message.error.title": "Security Error!",
"security.message.error.parameter": "Route requires 'parameter name'",
"security.message.error.parameter.not.found": "Not Found 'program' Parameter",
"settings.message.error.title": "Settings Error!",
"settings.general.header": "General",
"settings.general.information.short": "Information",
"system_settings_information_title": "General Information",
"system_settings_information_title_desc": "Enter company-related information, which can be used in notifications.",
"system_settings_information_form_name_placeholder": "Name",
"system_settings_information_form_name_suggest": "Application name.",
"system_settings_information_form_email_placeholder": "Email",
"system_settings_information_form_email_suggest": "Company email.",
"system_settings_information_form_domain_placeholder": "Application domain",
"system_settings_information_form_domain_suggest": "Application domain",
"system_settings_information_form_image_label": "Application logo",
"settings.security.header": "Security",
"settings.security.password.short": "Password",
"system_settings_password_title": "Passwrod settings",
"system_settings_password_title_desc": "Customize the security policies for the password.",
"system_settings_password_form_includeUppercase_label": "Include capital letters",
"system_settings_password_form_includeUppercase_suggest": "Requires the password to contain at least one capital letter.",
"system_settings_password_form_includeNumber_label": "Incluir números",
"system_settings_password_form_includeNumber_suggest": "Requires the password to contain at least one number.",
"system_settings_password_form_notIncludeUserId_label": "Do not include the user code",
"system_settings_password_form_notIncludeUserId_suggest": "The password must not include the user code.",
"system_settings_password_form_notIncludeReverseUserId_label": "Do not include the user code backwards",
"system_settings_password_form_notIncludeReverseUserId_suggest": "Validate that the password does not include the user's code in reverse.",
"system_settings_password_form_passwordMinLength_label": "Minimum length",
"system_settings_password_form_passwordMinLength_suggest": "Minimum length for the password.",
"settings.security.user.policy.short": "User policies",
"system_settings_userpolicy_title": "User policies",
"system_settings_userpolicy_title_desc": "Customize the following security policies for users using the Byte security platform.",
"system_settings_userpolicy_form_maxFailLogin_placeholder": "Maximum failed attempts",
"system_settings_userpolicy_form_maxFailLogin_suggest": "Specify the number of failed login attempts, before blocking the user.",
"system_settings_userpolicy_form_historyValidation_placeholder": "Validate password history",
"system_settings_userpolicy_form_historyValidation_suggest": "Specify the number of last passwords that cannot be repeated.",
"system_settings_userpolicy_form_userInactivity_placeholder": "Block users for inactivity",
"system_settings_userpolicy_form_userInactivity_suggest": "Specify the number of days that must pass to block the user for inactivity.",
"system_settings_userpolicy_form_passwordExpiration_placeholder": "Password expiration",
"system_settings_userpolicy_form_passwordExpiration_suggest": "Specify the number of days for passwords associated with user accounts to expire.",
"system_settings_userpolicy_form_automaticUnlock_placeholder": "Automatic user unlocking",
"system_settings_userpolicy_form_automaticUnlock_suggest": "Specify the number of minutes it takes for an account to be automatically unlocked.",
"system_settings_userpolicy_form_manageAccountByEmail_label": "Manage user accounts via email",
"system_settings_userpolicy_form_manageAccountByEmail_suggest": "Enable the option if you want to use email sending for user account management",
"settings.notification.header": "Communication",
"settings.notification.mail.short": "Email server",
"system_settings_mail_title": "Email Server Configuration",
"system_settings_mail_title_desc": "Enter the information related to the email service that the application will use",
"notification.mail.from.address": "Outbound account (from)",
"notification.mail.from.address.suggest": "Email address that the application will use to send emails.",
"notification.mail.prefix": "Subject prefix",
"notification.mail.prefix.suggest": "Subject prefix.",
"notification.mail.server": "SMTP server",
"notification.mail.server.suggest": "Name or IP address of the SMTP server.",
"notification.mail.smtp.port": "SMTP port",
"notification.mail.smtp.port.suggest": "SMTP service port.",
"notification.mail.username": "User",
"notification.mail.username.suggest": "Mail account user.",
"notification.mail.password": "Password",
"notification.mail.password.suggest": "Email account password.",
"notification.mail.use.auth": "Use authentication",
"notification.mail.use.tls": "Use TLS",
"notification.mail.test.title": "Mail configuration validation",
"notification.mail.test.suggest": "This section allows you to validate the mail settings before being saved.",
"notification.mail.test.recipients": "Test recipients",
"notification.mail.test.recipients.suggest": "Enter one or more destination emails and press the \"Send email\" button.",
"notification.mail.test.view.logs": "Show logs",
"application_btn_new_secret": "Generate new secret",
"application_btn_show_credentials": "View credentials",
"application.title": "Application maintenance",
"application_group_general_information":"General information",
"application_credentials_title":"Credentials",
"application_identifier_header": "Identifier",
"application_description_header": "Description",
"application_redirectURL_header": "Return url",
"application_status_header": "Status",
"application_form_identifier_placeholder": "Identifier",
"application_form_description_placeholder": "Descripción",
"application_form_redirectURL_placeholder": "Return url",
"application_form_client_id_placeholder": "ClienteId",
"application_form_client_secret_placeholder": "ClientSecret",
"application_form_access_token_validity_placeholder": "AccessTokenValidity",
"application_form_refresh_token_validity_placeholder": "RefreshTokenValidity",
"application_generated_secret_title": "Change secret",
"application_generated_secret_message": "Are you sure you want to generate a new secret?",
"application_new_secret_success": "Another secret was successfully generated",
"application.status.active": "Active",
"application.status.inactive": "Inactive",
"menu.settings.valpos": "Valores posibles",
"valpos.title": "Mantenimiento de valores posibles",
"valpos_id_header": "Id",
"valpos_identifier_header": "Identifier",
"valpos_description_header": "Description",
"valpos_group_values": "Possible values Assigned",
"valpos_group_general_information": "General Information",
"valpos_form_id_placeholder": "Id",
"valpos_form_identifier_placeholder": "Identifier",
"valpos_form_description_placeholder": "Description",
"valpos.label.title": "Label",
"valpos.value.title": "Value"
}
\ No newline at end of file
{
"breadcrumb.application": "Aplicación",
"breadcrumb.application.detail": "Información de aplicación",
"breadcrumb.valpos": "Valor posible",
"breadcrumb.valpos.detail": "Información de valor posible",
"breadcrumb.settings.userpolicy": "Políticas de usuario",
"breadcrumb.settings.information": "Información general",
"breadcrumb.settings.password": "Políticas de contraseña",
"tabs.system.settings.information.title": "Información general",
"tabs.system.settings.information.title.desc": "Datos de la organización.",
"tabs.system.settings.password.title": "Políticas de contraseña",
"tabs.system.settings.password.title.desc": "Reglas que debe cumplir al definir las contraseñas.",
"tabs.system.settings.userpolicy.title": "Políticas de usuario",
"tabs.system.settings.userpolicy.title.desc": "Reglas de seguridad para la aplicación.",
"security.message.error.title": "Error de seguridad!",
"security.message.error.parameter": "Ruta requiere el parámetro '{{parameter}}'",
"security.message.error.parameter.not.found": "Parámetro '{{parameter}}' no encontrado",
"settings.message.error.title": "Error de configuración!",
"settings.general.header": "General",
"settings.general.information.short": "Información",
"system_settings_information_title": "Información General",
"system_settings_information_title_desc": "Ingrese información relacionada a la compañía, que podrá ser usada en las notificaciones.",
"system_settings_information_form_name_placeholder": "Nombre",
"system_settings_information_form_name_suggest": "Nombre de la aplicación.",
"system_settings_information_form_email_placeholder": "Correo electrónico",
"system_settings_information_form_email_suggest": "Correo electrónico de la empresa.",
"system_settings_information_form_domain_placeholder": "Dominio de la aplicación",
"system_settings_information_form_domain_suggest": "Dominio de la aplicación",
"system_settings_information_form_image_label": "Logo de la aplicación",
"settings.security.header": "Seguridad",
"settings.security.password.short": "Contraseña",
"system_settings_password_title": "Configuración de Contraseña",
"system_settings_password_title_desc": "Personalice las políticas de seguridad para la contraseña.",
"system_settings_password_form_includeUppercase_label": "Incluir mayúsculas",
"system_settings_password_form_includeUppercase_suggest": "Requiere que la contraseña contenga al menos una letra mayúscula.",
"system_settings_password_form_includeNumber_label": "Incluir números",
"system_settings_password_form_includeNumber_suggest": "Requiere que la contraseña contenga al menos un número.",
"system_settings_password_form_notIncludeUserId_label": "No incluir el código del usuario",
"system_settings_password_form_notIncludeUserId_suggest": "La contraseña no debe incluir el código de usuario.",
"system_settings_password_form_notIncludeReverseUserId_label": "No incluir el código de usuario al revés",
"system_settings_password_form_notIncludeReverseUserId_suggest": "Validar que la contraseña no incluya el código del usuario al revés.",
"system_settings_password_form_passwordMinLength_label": "Longitud mínima",
"system_settings_password_form_passwordMinLength_suggest": "Longitud mínima para la contraseña.",
"settings.security.user.policy.short": "Políticas de usuario",
"system_settings_userpolicy_title": "Políticas de usuario",
"system_settings_userpolicy_title_desc": "Personalice las siguientes políticas de seguridad para los usuarios que utilicen la plataforma de seguridad Byte.",
"system_settings_userpolicy_form_maxFailLogin_placeholder": "Máximo de intentos fallidos",
"system_settings_userpolicy_form_maxFailLogin_suggest": "Especifique el número de intentos fallidos de ingreso al sistema, antes de bloquear el usuario.",
"system_settings_userpolicy_form_historyValidation_placeholder": "Validar historial de contraseñas",
"system_settings_userpolicy_form_historyValidation_suggest": "Especifique el número de últimas contraseña que no puede repetirse.",
"system_settings_userpolicy_form_userInactivity_placeholder": "Bloquear usuarios por inactividad",
"system_settings_userpolicy_form_userInactivity_suggest": "Especifique el número de días que deben pasar para bloquear al usuario por inactividad.",
"system_settings_userpolicy_form_passwordExpiration_placeholder": "Vencimiento de contraseñas",
"system_settings_userpolicy_form_passwordExpiration_suggest": "Especifique el número de días para que las contraseñas asociadas a las cuentas de usuario expiren.",
"system_settings_userpolicy_form_automaticUnlock_placeholder": "Desbloqueo automático de usuarios",
"system_settings_userpolicy_form_automaticUnlock_suggest": "Especifique el número de minutos que tienen que pasar para que una cuenta se desbloquee de manera automática.",
"system_settings_userpolicy_form_manageAccountByEmail_label": "Administrar cuentas de usuario vía email",
"system_settings_userpolicy_form_manageAccountByEmail_suggest": "Habilite la opción si desea utilizar el envío de correos electrónicos para la administración de cuentas de usuario",
"settings.notification.header": "Comunicación",
"settings.notification.mail.short": "Servidor email",
"system_settings_mail_title": "Configuración de Servidor de Email",
"system_settings_mail_title.desc": "Ingrese la información relacionada al servicio de email que usará la aplicación",
"notification.mail.from.address": "Cuenta de salida (from)",
"notification.mail.from.address.suggest": "Dirección de correo que usará la aplicación para el envio de correos.",
"notification.mail.prefix": "Prefijo de asunto",
"notification.mail.prefix.suggest": "Prefijo de asunto.",
"notification.mail.server": "Servidor SMTP",
"notification.mail.server.suggest": "Nombre o dirección IP del servidor SMTP.",
"notification.mail.smtp.port": "Puerto SMTP",
"notification.mail.smtp.port.suggest": "Puerto del servicio SMTP.",
"notification.mail.username": "Usuario",
"notification.mail.username.suggest": "Usuario de la cuenta de correo.",
"notification.mail.password": "Contraseña",
"notification.mail.password.suggest": "Contraseña de la cuenta de correo.",
"notification.mail.use.auth": "Usa autenticación",
"notification.mail.use.tls": "Usa TLS",
"notification.mail.test.title": "Validación de configuración de correo",
"notification.mail.test.suggest": "Esta sección permite validar la configuración de correo antes de ser grabada.",
"notification.mail.test.recipients": "Destinatarios de prueba",
"notification.mail.test.recipients.suggest": "Ingrese uno o más email de destino y presione el botón \"Enviar email\".",
"notification.mail.test.view.logs": "Ver logs",
"application_btn_new_secret": "Generar nuevas credenciales",
"application_btn_show_credentials": "Ver credenciales",
"application.title": "Mantenimiento de aplicaciones",
"application_group_general_information":"Información general",
"application_credentials_title":"Credenciales",
"application_identifier_header": "Identificador",
"application_description_header": "Descripción",
"application_redirectURL_header": "Url de retorno",
"application_status_header": "Estado",
"application_form_identifier_placeholder": "Identificador",
"application_form_description_placeholder": "Descripción",
"application_form_redirectURL_placeholder": "Url de retorno",
"application_form_client_id_placeholder": "ClienteId",
"application_form_client_secret_placeholder": "ClientSecret",
"application_form_access_token_validity_placeholder": "AccessTokenValidity",
"application_form_refresh_token_validity_placeholder": "RefreshTokenValidity",
"application_generated_secret_title": "Cambiar secret",
"application_generated_secret_message": "¿Está seguro que quiere generar un nuevo secret?",
"application_new_secret_success": "Se generó correctamente otro secret",
"application.status.active": "Activo",
"application.status.inactive": "Inactivo",
"menu.settings.valpos": "Valores posibles",
"valpos.title": "Mantenimiento de valores posibles",
"valpos_id_header": "Código",
"valpos_identifier_header": "Identificador",
"valpos_description_header": "Descripción",
"valpos_group_values": "Valores posibles Asignados",
"valpos_group_general_information": "Información general",
"valpos_form_id_placeholder": "Código",
"valpos_form_identifier_placeholder": "Identificador",
"valpos_form_description_placeholder": "Descripción",
"valpos.label.title": "Clave",
"valpos.value.title": "Valor"
}
\ No newline at end of file
@import "~bootstrap/scss/bootstrap";
@import "./css/animate";
@import "./css/inspinia";
@import '~@swimlane/ngx-datatable/index.css';
@import "~@ng-select/ng-select/themes/default.theme.css";
@import './css/ngx-datatable/bootstrap';
@import './css/ngx-datatable/material';
\ No newline at end of file
@charset "UTF-8";
/*!
Animate.css - http://daneden.me/animate
Licensed under the MIT license
Copyright (c) 2013 Daniel Eden
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
.animated {
-webkit-animation-duration: 1s;
animation-duration: 1s;
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
}
.animated.infinite {
-webkit-animation-iteration-count: infinite;
animation-iteration-count: infinite;
}
.animated.hinge {
-webkit-animation-duration: 2s;
animation-duration: 2s;
}
@-webkit-keyframes bounce {
0%, 20%, 50%, 80%, 100% {
-webkit-transform: translateY(0);
transform: translateY(0);
}
40% {
-webkit-transform: translateY(-30px);
transform: translateY(-30px);
}
60% {
-webkit-transform: translateY(-15px);
transform: translateY(-15px);
}
}
@keyframes bounce {
0%, 20%, 50%, 80%, 100% {
-webkit-transform: translateY(0);
-ms-transform: translateY(0);
transform: translateY(0);
}
40% {
-webkit-transform: translateY(-30px);
-ms-transform: translateY(-30px);
transform: translateY(-30px);
}
60% {
-webkit-transform: translateY(-15px);
-ms-transform: translateY(-15px);
transform: translateY(-15px);
}
}
.bounce {
-webkit-animation-name: bounce;
animation-name: bounce;
}
@-webkit-keyframes flash {
0%, 50%, 100% {
opacity: 1;
}
25%, 75% {
opacity: 0;
}
}
@keyframes flash {
0%, 50%, 100% {
opacity: 1;
}
25%, 75% {
opacity: 0;
}
}
.flash {
-webkit-animation-name: flash;
animation-name: flash;
}
/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */
@-webkit-keyframes pulse {
0% {
-webkit-transform: scale(1);
transform: scale(1);
}
50% {
-webkit-transform: scale(1.1);
transform: scale(1.1);
}
100% {
-webkit-transform: scale(1);
transform: scale(1);
}
}
@keyframes pulse {
0% {
-webkit-transform: scale(1);
-ms-transform: scale(1);
transform: scale(1);
}
50% {
-webkit-transform: scale(1.1);
-ms-transform: scale(1.1);
transform: scale(1.1);
}
100% {
-webkit-transform: scale(1);
-ms-transform: scale(1);
transform: scale(1);
}
}
.pulse {
-webkit-animation-name: pulse;
animation-name: pulse;
}
@-webkit-keyframes rubberBand {
0% {
-webkit-transform: scale(1);
transform: scale(1);
}
30% {
-webkit-transform: scaleX(1.25) scaleY(0.75);
transform: scaleX(1.25) scaleY(0.75);
}
40% {
-webkit-transform: scaleX(0.75) scaleY(1.25);
transform: scaleX(0.75) scaleY(1.25);
}
60% {
-webkit-transform: scaleX(1.15) scaleY(0.85);
transform: scaleX(1.15) scaleY(0.85);
}
100% {
-webkit-transform: scale(1);
transform: scale(1);
}
}
@keyframes rubberBand {
0% {
-webkit-transform: scale(1);
-ms-transform: scale(1);
transform: scale(1);
}
30% {
-webkit-transform: scaleX(1.25) scaleY(0.75);
-ms-transform: scaleX(1.25) scaleY(0.75);
transform: scaleX(1.25) scaleY(0.75);
}
40% {
-webkit-transform: scaleX(0.75) scaleY(1.25);
-ms-transform: scaleX(0.75) scaleY(1.25);
transform: scaleX(0.75) scaleY(1.25);
}
60% {
-webkit-transform: scaleX(1.15) scaleY(0.85);
-ms-transform: scaleX(1.15) scaleY(0.85);
transform: scaleX(1.15) scaleY(0.85);
}
100% {
-webkit-transform: scale(1);
-ms-transform: scale(1);
transform: scale(1);
}
}
.rubberBand {
-webkit-animation-name: rubberBand;
animation-name: rubberBand;
}
@-webkit-keyframes shake {
0%, 100% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
10%, 30%, 50%, 70%, 90% {
-webkit-transform: translateX(-10px);
transform: translateX(-10px);
}
20%, 40%, 60%, 80% {
-webkit-transform: translateX(10px);
transform: translateX(10px);
}
}
@keyframes shake {
0%, 100% {
-webkit-transform: translateX(0);
-ms-transform: translateX(0);
transform: translateX(0);
}
10%, 30%, 50%, 70%, 90% {
-webkit-transform: translateX(-10px);
-ms-transform: translateX(-10px);
transform: translateX(-10px);
}
20%, 40%, 60%, 80% {
-webkit-transform: translateX(10px);
-ms-transform: translateX(10px);
transform: translateX(10px);
}
}
.shake {
-webkit-animation-name: shake;
animation-name: shake;
}
@-webkit-keyframes swing {
20% {
-webkit-transform: rotate(15deg);
transform: rotate(15deg);
}
40% {
-webkit-transform: rotate(-10deg);
transform: rotate(-10deg);
}
60% {
-webkit-transform: rotate(5deg);
transform: rotate(5deg);
}
80% {
-webkit-transform: rotate(-5deg);
transform: rotate(-5deg);
}
100% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
}
@keyframes swing {
20% {
-webkit-transform: rotate(15deg);
-ms-transform: rotate(15deg);
transform: rotate(15deg);
}
40% {
-webkit-transform: rotate(-10deg);
-ms-transform: rotate(-10deg);
transform: rotate(-10deg);
}
60% {
-webkit-transform: rotate(5deg);
-ms-transform: rotate(5deg);
transform: rotate(5deg);
}
80% {
-webkit-transform: rotate(-5deg);
-ms-transform: rotate(-5deg);
transform: rotate(-5deg);
}
100% {
-webkit-transform: rotate(0deg);
-ms-transform: rotate(0deg);
transform: rotate(0deg);
}
}
.swing {
-webkit-transform-origin: top center;
-ms-transform-origin: top center;
transform-origin: top center;
-webkit-animation-name: swing;
animation-name: swing;
}
@-webkit-keyframes tada {
0% {
-webkit-transform: scale(1);
transform: scale(1);
}
10%, 20% {
-webkit-transform: scale(0.9) rotate(-3deg);
transform: scale(0.9) rotate(-3deg);
}
30%, 50%, 70%, 90% {
-webkit-transform: scale(1.1) rotate(3deg);
transform: scale(1.1) rotate(3deg);
}
40%, 60%, 80% {
-webkit-transform: scale(1.1) rotate(-3deg);
transform: scale(1.1) rotate(-3deg);
}
100% {
-webkit-transform: scale(1) rotate(0);
transform: scale(1) rotate(0);
}
}
@keyframes tada {
0% {
-webkit-transform: scale(1);
-ms-transform: scale(1);
transform: scale(1);
}
10%, 20% {
-webkit-transform: scale(0.9) rotate(-3deg);
-ms-transform: scale(0.9) rotate(-3deg);
transform: scale(0.9) rotate(-3deg);
}
30%, 50%, 70%, 90% {
-webkit-transform: scale(1.1) rotate(3deg);
-ms-transform: scale(1.1) rotate(3deg);
transform: scale(1.1) rotate(3deg);
}
40%, 60%, 80% {
-webkit-transform: scale(1.1) rotate(-3deg);
-ms-transform: scale(1.1) rotate(-3deg);
transform: scale(1.1) rotate(-3deg);
}
100% {
-webkit-transform: scale(1) rotate(0);
-ms-transform: scale(1) rotate(0);
transform: scale(1) rotate(0);
}
}
.tada {
-webkit-animation-name: tada;
animation-name: tada;
}
/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */
@-webkit-keyframes wobble {
0% {
-webkit-transform: translateX(0%);
transform: translateX(0%);
}
15% {
-webkit-transform: translateX(-25%) rotate(-5deg);
transform: translateX(-25%) rotate(-5deg);
}
30% {
-webkit-transform: translateX(20%) rotate(3deg);
transform: translateX(20%) rotate(3deg);
}
45% {
-webkit-transform: translateX(-15%) rotate(-3deg);
transform: translateX(-15%) rotate(-3deg);
}
60% {
-webkit-transform: translateX(10%) rotate(2deg);
transform: translateX(10%) rotate(2deg);
}
75% {
-webkit-transform: translateX(-5%) rotate(-1deg);
transform: translateX(-5%) rotate(-1deg);
}
100% {
-webkit-transform: translateX(0%);
transform: translateX(0%);
}
}
@keyframes wobble {
0% {
-webkit-transform: translateX(0%);
-ms-transform: translateX(0%);
transform: translateX(0%);
}
15% {
-webkit-transform: translateX(-25%) rotate(-5deg);
-ms-transform: translateX(-25%) rotate(-5deg);
transform: translateX(-25%) rotate(-5deg);
}
30% {
-webkit-transform: translateX(20%) rotate(3deg);
-ms-transform: translateX(20%) rotate(3deg);
transform: translateX(20%) rotate(3deg);
}
45% {
-webkit-transform: translateX(-15%) rotate(-3deg);
-ms-transform: translateX(-15%) rotate(-3deg);
transform: translateX(-15%) rotate(-3deg);
}
60% {
-webkit-transform: translateX(10%) rotate(2deg);
-ms-transform: translateX(10%) rotate(2deg);
transform: translateX(10%) rotate(2deg);
}
75% {
-webkit-transform: translateX(-5%) rotate(-1deg);
-ms-transform: translateX(-5%) rotate(-1deg);
transform: translateX(-5%) rotate(-1deg);
}
100% {
-webkit-transform: translateX(0%);
-ms-transform: translateX(0%);
transform: translateX(0%);
}
}
.wobble {
-webkit-animation-name: wobble;
animation-name: wobble;
}
@-webkit-keyframes bounceIn {
0% {
opacity: 0;
-webkit-transform: scale(.3);
transform: scale(.3);
}
50% {
opacity: 1;
-webkit-transform: scale(1.05);
transform: scale(1.05);
}
70% {
-webkit-transform: scale(.9);
transform: scale(.9);
}
100% {
opacity: 1;
-webkit-transform: scale(1);
transform: scale(1);
}
}
@keyframes bounceIn {
0% {
opacity: 0;
-webkit-transform: scale(.3);
-ms-transform: scale(.3);
transform: scale(.3);
}
50% {
opacity: 1;
-webkit-transform: scale(1.05);
-ms-transform: scale(1.05);
transform: scale(1.05);
}
70% {
-webkit-transform: scale(.9);
-ms-transform: scale(.9);
transform: scale(.9);
}
100% {
opacity: 1;
-webkit-transform: scale(1);
-ms-transform: scale(1);
transform: scale(1);
}
}
.bounceIn {
-webkit-animation-name: bounceIn;
animation-name: bounceIn;
}
@-webkit-keyframes bounceInDown {
0% {
opacity: 0;
-webkit-transform: translateY(-2000px);
transform: translateY(-2000px);
}
60% {
opacity: 1;
-webkit-transform: translateY(30px);
transform: translateY(30px);
}
80% {
-webkit-transform: translateY(-10px);
transform: translateY(-10px);
}
100% {
-webkit-transform: translateY(0);
transform: translateY(0);
}
}
@keyframes bounceInDown {
0% {
opacity: 0;
-webkit-transform: translateY(-2000px);
-ms-transform: translateY(-2000px);
transform: translateY(-2000px);
}
60% {
opacity: 1;
-webkit-transform: translateY(30px);
-ms-transform: translateY(30px);
transform: translateY(30px);
}
80% {
-webkit-transform: translateY(-10px);
-ms-transform: translateY(-10px);
transform: translateY(-10px);
}
100% {
-webkit-transform: translateY(0);
-ms-transform: translateY(0);
transform: translateY(0);
}
}
.bounceInDown {
-webkit-animation-name: bounceInDown;
animation-name: bounceInDown;
}
@-webkit-keyframes bounceInLeft {
0% {
opacity: 0;
-webkit-transform: translateX(-2000px);
transform: translateX(-2000px);
}
60% {
opacity: 1;
-webkit-transform: translateX(30px);
transform: translateX(30px);
}
80% {
-webkit-transform: translateX(-10px);
transform: translateX(-10px);
}
100% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
}
@keyframes bounceInLeft {
0% {
opacity: 0;
-webkit-transform: translateX(-2000px);
-ms-transform: translateX(-2000px);
transform: translateX(-2000px);
}
60% {
opacity: 1;
-webkit-transform: translateX(30px);
-ms-transform: translateX(30px);
transform: translateX(30px);
}
80% {
-webkit-transform: translateX(-10px);
-ms-transform: translateX(-10px);
transform: translateX(-10px);
}
100% {
-webkit-transform: translateX(0);
-ms-transform: translateX(0);
transform: translateX(0);
}
}
.bounceInLeft {
-webkit-animation-name: bounceInLeft;
animation-name: bounceInLeft;
}
@-webkit-keyframes bounceInRight {
0% {
opacity: 0;
-webkit-transform: translateX(2000px);
transform: translateX(2000px);
}
60% {
opacity: 1;
-webkit-transform: translateX(-30px);
transform: translateX(-30px);
}
80% {
-webkit-transform: translateX(10px);
transform: translateX(10px);
}
100% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
}
@keyframes bounceInRight {
0% {
opacity: 0;
-webkit-transform: translateX(2000px);
-ms-transform: translateX(2000px);
transform: translateX(2000px);
}
60% {
opacity: 1;
-webkit-transform: translateX(-30px);
-ms-transform: translateX(-30px);
transform: translateX(-30px);
}
80% {
-webkit-transform: translateX(10px);
-ms-transform: translateX(10px);
transform: translateX(10px);
}
100% {
-webkit-transform: translateX(0);
-ms-transform: translateX(0);
transform: translateX(0);
}
}
.bounceInRight {
-webkit-animation-name: bounceInRight;
animation-name: bounceInRight;
}
@-webkit-keyframes bounceInUp {
0% {
opacity: 0;
-webkit-transform: translateY(2000px);
transform: translateY(2000px);
}
60% {
opacity: 1;
-webkit-transform: translateY(-30px);
transform: translateY(-30px);
}
80% {
-webkit-transform: translateY(10px);
transform: translateY(10px);
}
100% {
-webkit-transform: translateY(0);
transform: translateY(0);
}
}
@keyframes bounceInUp {
0% {
opacity: 0;
-webkit-transform: translateY(2000px);
-ms-transform: translateY(2000px);
transform: translateY(2000px);
}
60% {
opacity: 1;
-webkit-transform: translateY(-30px);
-ms-transform: translateY(-30px);
transform: translateY(-30px);
}
80% {
-webkit-transform: translateY(10px);
-ms-transform: translateY(10px);
transform: translateY(10px);
}
100% {
-webkit-transform: translateY(0);
-ms-transform: translateY(0);
transform: translateY(0);
}
}
.bounceInUp {
-webkit-animation-name: bounceInUp;
animation-name: bounceInUp;
}
@-webkit-keyframes bounceOut {
0% {
-webkit-transform: scale(1);
transform: scale(1);
}
25% {
-webkit-transform: scale(.95);
transform: scale(.95);
}
50% {
opacity: 1;
-webkit-transform: scale(1.1);
transform: scale(1.1);
}
100% {
opacity: 0;
-webkit-transform: scale(.3);
transform: scale(.3);
}
}
@keyframes bounceOut {
0% {
-webkit-transform: scale(1);
-ms-transform: scale(1);
transform: scale(1);
}
25% {
-webkit-transform: scale(.95);
-ms-transform: scale(.95);
transform: scale(.95);
}
50% {
opacity: 1;
-webkit-transform: scale(1.1);
-ms-transform: scale(1.1);
transform: scale(1.1);
}
100% {
opacity: 0;
-webkit-transform: scale(.3);
-ms-transform: scale(.3);
transform: scale(.3);
}
}
.bounceOut {
-webkit-animation-name: bounceOut;
animation-name: bounceOut;
}
@-webkit-keyframes bounceOutDown {
0% {
-webkit-transform: translateY(0);
transform: translateY(0);
}
20% {
opacity: 1;
-webkit-transform: translateY(-20px);
transform: translateY(-20px);
}
100% {
opacity: 0;
-webkit-transform: translateY(2000px);
transform: translateY(2000px);
}
}
@keyframes bounceOutDown {
0% {
-webkit-transform: translateY(0);
-ms-transform: translateY(0);
transform: translateY(0);
}
20% {
opacity: 1;
-webkit-transform: translateY(-20px);
-ms-transform: translateY(-20px);
transform: translateY(-20px);
}
100% {
opacity: 0;
-webkit-transform: translateY(2000px);
-ms-transform: translateY(2000px);
transform: translateY(2000px);
}
}
.bounceOutDown {
-webkit-animation-name: bounceOutDown;
animation-name: bounceOutDown;
}
@-webkit-keyframes bounceOutLeft {
0% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
20% {
opacity: 1;
-webkit-transform: translateX(20px);
transform: translateX(20px);
}
100% {
opacity: 0;
-webkit-transform: translateX(-2000px);
transform: translateX(-2000px);
}
}
@keyframes bounceOutLeft {
0% {
-webkit-transform: translateX(0);
-ms-transform: translateX(0);
transform: translateX(0);
}
20% {
opacity: 1;
-webkit-transform: translateX(20px);
-ms-transform: translateX(20px);
transform: translateX(20px);
}
100% {
opacity: 0;
-webkit-transform: translateX(-2000px);
-ms-transform: translateX(-2000px);
transform: translateX(-2000px);
}
}
.bounceOutLeft {
-webkit-animation-name: bounceOutLeft;
animation-name: bounceOutLeft;
}
@-webkit-keyframes bounceOutRight {
0% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
20% {
opacity: 1;
-webkit-transform: translateX(-20px);
transform: translateX(-20px);
}
100% {
opacity: 0;
-webkit-transform: translateX(2000px);
transform: translateX(2000px);
}
}
@keyframes bounceOutRight {
0% {
-webkit-transform: translateX(0);
-ms-transform: translateX(0);
transform: translateX(0);
}
20% {
opacity: 1;
-webkit-transform: translateX(-20px);
-ms-transform: translateX(-20px);
transform: translateX(-20px);
}
100% {
opacity: 0;
-webkit-transform: translateX(2000px);
-ms-transform: translateX(2000px);
transform: translateX(2000px);
}
}
.bounceOutRight {
-webkit-animation-name: bounceOutRight;
animation-name: bounceOutRight;
}
@-webkit-keyframes bounceOutUp {
0% {
-webkit-transform: translateY(0);
transform: translateY(0);
}
20% {
opacity: 1;
-webkit-transform: translateY(20px);
transform: translateY(20px);
}
100% {
opacity: 0;
-webkit-transform: translateY(-2000px);
transform: translateY(-2000px);
}
}
@keyframes bounceOutUp {
0% {
-webkit-transform: translateY(0);
-ms-transform: translateY(0);
transform: translateY(0);
}
20% {
opacity: 1;
-webkit-transform: translateY(20px);
-ms-transform: translateY(20px);
transform: translateY(20px);
}
100% {
opacity: 0;
-webkit-transform: translateY(-2000px);
-ms-transform: translateY(-2000px);
transform: translateY(-2000px);
}
}
.bounceOutUp {
-webkit-animation-name: bounceOutUp;
animation-name: bounceOutUp;
}
@-webkit-keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.fadeIn {
-webkit-animation-name: fadeIn;
animation-name: fadeIn;
}
@-webkit-keyframes fadeInDown {
0% {
opacity: 0;
-webkit-transform: translateY(-20px);
transform: translateY(-20px);
}
100% {
opacity: 1;
-webkit-transform: translateY(0);
transform: translateY(0);
}
}
@keyframes fadeInDown {
0% {
opacity: 0;
-webkit-transform: translateY(-20px);
-ms-transform: translateY(-20px);
transform: translateY(-20px);
}
100% {
opacity: 1;
-webkit-transform: translateY(0);
-ms-transform: translateY(0);
transform: translateY(0);
}
}
.fadeInDown {
-webkit-animation-name: fadeInDown;
animation-name: fadeInDown;
}
@-webkit-keyframes fadeInDownBig {
0% {
opacity: 0;
-webkit-transform: translateY(-2000px);
transform: translateY(-2000px);
}
100% {
opacity: 1;
-webkit-transform: translateY(0);
transform: translateY(0);
}
}
@keyframes fadeInDownBig {
0% {
opacity: 0;
-webkit-transform: translateY(-2000px);
-ms-transform: translateY(-2000px);
transform: translateY(-2000px);
}
100% {
opacity: 1;
-webkit-transform: translateY(0);
-ms-transform: translateY(0);
transform: translateY(0);
}
}
.fadeInDownBig {
-webkit-animation-name: fadeInDownBig;
animation-name: fadeInDownBig;
}
@-webkit-keyframes fadeInLeft {
0% {
opacity: 0;
-webkit-transform: translateX(-20px);
transform: translateX(-20px);
}
100% {
opacity: 1;
-webkit-transform: translateX(0);
transform: translateX(0);
}
}
@keyframes fadeInLeft {
0% {
opacity: 0;
-webkit-transform: translateX(-20px);
-ms-transform: translateX(-20px);
transform: translateX(-20px);
}
100% {
opacity: 1;
-webkit-transform: translateX(0);
-ms-transform: translateX(0);
transform: translateX(0);
}
}
.fadeInLeft {
-webkit-animation-name: fadeInLeft;
animation-name: fadeInLeft;
}
@-webkit-keyframes fadeInLeftBig {
0% {
opacity: 0;
-webkit-transform: translateX(-2000px);
transform: translateX(-2000px);
}
100% {
opacity: 1;
-webkit-transform: translateX(0);
transform: translateX(0);
}
}
@keyframes fadeInLeftBig {
0% {
opacity: 0;
-webkit-transform: translateX(-2000px);
-ms-transform: translateX(-2000px);
transform: translateX(-2000px);
}
100% {
opacity: 1;
-webkit-transform: translateX(0);
-ms-transform: translateX(0);
transform: translateX(0);
}
}
.fadeInLeftBig {
-webkit-animation-name: fadeInLeftBig;
animation-name: fadeInLeftBig;
}
@-webkit-keyframes fadeInRight {
0% {
opacity: 0;
-webkit-transform: translateX(20px);
transform: translateX(20px);
}
100% {
opacity: 1;
-webkit-transform: translateX(0);
transform: translateX(0);
}
}
@keyframes fadeInRight {
0% {
opacity: 0;
-webkit-transform: translateX(20px);
-ms-transform: translateX(20px);
transform: translateX(20px);
}
100% {
opacity: 1;
-webkit-transform: translateX(0);
-ms-transform: translateX(0);
transform: translateX(0);
}
}
.fadeInRight {
-webkit-animation-name: fadeInRight;
animation-name: fadeInRight;
}
@-webkit-keyframes fadeInRightBig {
0% {
opacity: 0;
-webkit-transform: translateX(2000px);
transform: translateX(2000px);
}
100% {
opacity: 1;
-webkit-transform: translateX(0);
transform: translateX(0);
}
}
@keyframes fadeInRightBig {
0% {
opacity: 0;
-webkit-transform: translateX(2000px);
-ms-transform: translateX(2000px);
transform: translateX(2000px);
}
100% {
opacity: 1;
-webkit-transform: translateX(0);
-ms-transform: translateX(0);
transform: translateX(0);
}
}
.fadeInRightBig {
-webkit-animation-name: fadeInRightBig;
animation-name: fadeInRightBig;
}
@-webkit-keyframes fadeInUp {
0% {
opacity: 0;
-webkit-transform: translateY(20px);
transform: translateY(20px);
}
100% {
opacity: 1;
-webkit-transform: translateY(0);
transform: translateY(0);
}
}
@keyframes fadeInUp {
0% {
opacity: 0;
-webkit-transform: translateY(20px);
-ms-transform: translateY(20px);
transform: translateY(20px);
}
100% {
opacity: 1;
-webkit-transform: translateY(0);
-ms-transform: translateY(0);
transform: translateY(0);
}
}
.fadeInUp {
-webkit-animation-name: fadeInUp;
animation-name: fadeInUp;
}
@-webkit-keyframes fadeInUpBig {
0% {
opacity: 0;
-webkit-transform: translateY(2000px);
transform: translateY(2000px);
}
100% {
opacity: 1;
-webkit-transform: translateY(0);
transform: translateY(0);
}
}
@keyframes fadeInUpBig {
0% {
opacity: 0;
-webkit-transform: translateY(2000px);
-ms-transform: translateY(2000px);
transform: translateY(2000px);
}
100% {
opacity: 1;
-webkit-transform: translateY(0);
-ms-transform: translateY(0);
transform: translateY(0);
}
}
.fadeInUpBig {
-webkit-animation-name: fadeInUpBig;
animation-name: fadeInUpBig;
}
@-webkit-keyframes fadeOut {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
@keyframes fadeOut {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
.fadeOut {
-webkit-animation-name: fadeOut;
animation-name: fadeOut;
}
@-webkit-keyframes fadeOutDown {
0% {
opacity: 1;
-webkit-transform: translateY(0);
transform: translateY(0);
}
100% {
opacity: 0;
-webkit-transform: translateY(20px);
transform: translateY(20px);
}
}
@keyframes fadeOutDown {
0% {
opacity: 1;
-webkit-transform: translateY(0);
-ms-transform: translateY(0);
transform: translateY(0);
}
100% {
opacity: 0;
-webkit-transform: translateY(20px);
-ms-transform: translateY(20px);
transform: translateY(20px);
}
}
.fadeOutDown {
-webkit-animation-name: fadeOutDown;
animation-name: fadeOutDown;
}
@-webkit-keyframes fadeOutDownBig {
0% {
opacity: 1;
-webkit-transform: translateY(0);
transform: translateY(0);
}
100% {
opacity: 0;
-webkit-transform: translateY(2000px);
transform: translateY(2000px);
}
}
@keyframes fadeOutDownBig {
0% {
opacity: 1;
-webkit-transform: translateY(0);
-ms-transform: translateY(0);
transform: translateY(0);
}
100% {
opacity: 0;
-webkit-transform: translateY(2000px);
-ms-transform: translateY(2000px);
transform: translateY(2000px);
}
}
.fadeOutDownBig {
-webkit-animation-name: fadeOutDownBig;
animation-name: fadeOutDownBig;
}
@-webkit-keyframes fadeOutLeft {
0% {
opacity: 1;
-webkit-transform: translateX(0);
transform: translateX(0);
}
100% {
opacity: 0;
-webkit-transform: translateX(-20px);
transform: translateX(-20px);
}
}
@keyframes fadeOutLeft {
0% {
opacity: 1;
-webkit-transform: translateX(0);
-ms-transform: translateX(0);
transform: translateX(0);
}
100% {
opacity: 0;
-webkit-transform: translateX(-20px);
-ms-transform: translateX(-20px);
transform: translateX(-20px);
}
}
.fadeOutLeft {
-webkit-animation-name: fadeOutLeft;
animation-name: fadeOutLeft;
}
@-webkit-keyframes fadeOutLeftBig {
0% {
opacity: 1;
-webkit-transform: translateX(0);
transform: translateX(0);
}
100% {
opacity: 0;
-webkit-transform: translateX(-2000px);
transform: translateX(-2000px);
}
}
@keyframes fadeOutLeftBig {
0% {
opacity: 1;
-webkit-transform: translateX(0);
-ms-transform: translateX(0);
transform: translateX(0);
}
100% {
opacity: 0;
-webkit-transform: translateX(-2000px);
-ms-transform: translateX(-2000px);
transform: translateX(-2000px);
}
}
.fadeOutLeftBig {
-webkit-animation-name: fadeOutLeftBig;
animation-name: fadeOutLeftBig;
}
@-webkit-keyframes fadeOutRight {
0% {
opacity: 1;
-webkit-transform: translateX(0);
transform: translateX(0);
}
100% {
opacity: 0;
-webkit-transform: translateX(20px);
transform: translateX(20px);
}
}
@keyframes fadeOutRight {
0% {
opacity: 1;
-webkit-transform: translateX(0);
-ms-transform: translateX(0);
transform: translateX(0);
}
100% {
opacity: 0;
-webkit-transform: translateX(20px);
-ms-transform: translateX(20px);
transform: translateX(20px);
}
}
.fadeOutRight {
-webkit-animation-name: fadeOutRight;
animation-name: fadeOutRight;
}
@-webkit-keyframes fadeOutRightBig {
0% {
opacity: 1;
-webkit-transform: translateX(0);
transform: translateX(0);
}
100% {
opacity: 0;
-webkit-transform: translateX(2000px);
transform: translateX(2000px);
}
}
@keyframes fadeOutRightBig {
0% {
opacity: 1;
-webkit-transform: translateX(0);
-ms-transform: translateX(0);
transform: translateX(0);
}
100% {
opacity: 0;
-webkit-transform: translateX(2000px);
-ms-transform: translateX(2000px);
transform: translateX(2000px);
}
}
.fadeOutRightBig {
-webkit-animation-name: fadeOutRightBig;
animation-name: fadeOutRightBig;
}
@-webkit-keyframes fadeOutUp {
0% {
opacity: 1;
-webkit-transform: translateY(0);
transform: translateY(0);
}
100% {
opacity: 0;
-webkit-transform: translateY(-20px);
transform: translateY(-20px);
}
}
@keyframes fadeOutUp {
0% {
opacity: 1;
-webkit-transform: translateY(0);
-ms-transform: translateY(0);
transform: translateY(0);
}
100% {
opacity: 0;
-webkit-transform: translateY(-20px);
-ms-transform: translateY(-20px);
transform: translateY(-20px);
}
}
.fadeOutUp {
-webkit-animation-name: fadeOutUp;
animation-name: fadeOutUp;
}
@-webkit-keyframes fadeOutUpBig {
0% {
opacity: 1;
-webkit-transform: translateY(0);
transform: translateY(0);
}
100% {
opacity: 0;
-webkit-transform: translateY(-2000px);
transform: translateY(-2000px);
}
}
@keyframes fadeOutUpBig {
0% {
opacity: 1;
-webkit-transform: translateY(0);
-ms-transform: translateY(0);
transform: translateY(0);
}
100% {
opacity: 0;
-webkit-transform: translateY(-2000px);
-ms-transform: translateY(-2000px);
transform: translateY(-2000px);
}
}
.fadeOutUpBig {
-webkit-animation-name: fadeOutUpBig;
animation-name: fadeOutUpBig;
}
@-webkit-keyframes flip {
0% {
-webkit-transform: perspective(400px) translateZ(0) rotateY(0) scale(1);
transform: perspective(400px) translateZ(0) rotateY(0) scale(1);
-webkit-animation-timing-function: ease-out;
animation-timing-function: ease-out;
}
40% {
-webkit-transform: perspective(400px) translateZ(150px) rotateY(170deg) scale(1);
transform: perspective(400px) translateZ(150px) rotateY(170deg) scale(1);
-webkit-animation-timing-function: ease-out;
animation-timing-function: ease-out;
}
50% {
-webkit-transform: perspective(400px) translateZ(150px) rotateY(190deg) scale(1);
transform: perspective(400px) translateZ(150px) rotateY(190deg) scale(1);
-webkit-animation-timing-function: ease-in;
animation-timing-function: ease-in;
}
80% {
-webkit-transform: perspective(400px) translateZ(0) rotateY(360deg) scale(.95);
transform: perspective(400px) translateZ(0) rotateY(360deg) scale(.95);
-webkit-animation-timing-function: ease-in;
animation-timing-function: ease-in;
}
100% {
-webkit-transform: perspective(400px) translateZ(0) rotateY(360deg) scale(1);
transform: perspective(400px) translateZ(0) rotateY(360deg) scale(1);
-webkit-animation-timing-function: ease-in;
animation-timing-function: ease-in;
}
}
@keyframes flip {
0% {
-webkit-transform: perspective(400px) translateZ(0) rotateY(0) scale(1);
-ms-transform: perspective(400px) translateZ(0) rotateY(0) scale(1);
transform: perspective(400px) translateZ(0) rotateY(0) scale(1);
-webkit-animation-timing-function: ease-out;
animation-timing-function: ease-out;
}
40% {
-webkit-transform: perspective(400px) translateZ(150px) rotateY(170deg) scale(1);
-ms-transform: perspective(400px) translateZ(150px) rotateY(170deg) scale(1);
transform: perspective(400px) translateZ(150px) rotateY(170deg) scale(1);
-webkit-animation-timing-function: ease-out;
animation-timing-function: ease-out;
}
50% {
-webkit-transform: perspective(400px) translateZ(150px) rotateY(190deg) scale(1);
-ms-transform: perspective(400px) translateZ(150px) rotateY(190deg) scale(1);
transform: perspective(400px) translateZ(150px) rotateY(190deg) scale(1);
-webkit-animation-timing-function: ease-in;
animation-timing-function: ease-in;
}
80% {
-webkit-transform: perspective(400px) translateZ(0) rotateY(360deg) scale(.95);
-ms-transform: perspective(400px) translateZ(0) rotateY(360deg) scale(.95);
transform: perspective(400px) translateZ(0) rotateY(360deg) scale(.95);
-webkit-animation-timing-function: ease-in;
animation-timing-function: ease-in;
}
100% {
-webkit-transform: perspective(400px) translateZ(0) rotateY(360deg) scale(1);
-ms-transform: perspective(400px) translateZ(0) rotateY(360deg) scale(1);
transform: perspective(400px) translateZ(0) rotateY(360deg) scale(1);
-webkit-animation-timing-function: ease-in;
animation-timing-function: ease-in;
}
}
.animated.flip {
-webkit-backface-visibility: visible;
-ms-backface-visibility: visible;
backface-visibility: visible;
-webkit-animation-name: flip;
animation-name: flip;
}
@-webkit-keyframes flipInX {
0% {
-webkit-transform: perspective(400px) rotateX(90deg);
transform: perspective(400px) rotateX(90deg);
opacity: 0;
}
40% {
-webkit-transform: perspective(400px) rotateX(-10deg);
transform: perspective(400px) rotateX(-10deg);
}
70% {
-webkit-transform: perspective(400px) rotateX(10deg);
transform: perspective(400px) rotateX(10deg);
}
100% {
-webkit-transform: perspective(400px) rotateX(0deg);
transform: perspective(400px) rotateX(0deg);
opacity: 1;
}
}
@keyframes flipInX {
0% {
-webkit-transform: perspective(400px) rotateX(90deg);
-ms-transform: perspective(400px) rotateX(90deg);
transform: perspective(400px) rotateX(90deg);
opacity: 0;
}
40% {
-webkit-transform: perspective(400px) rotateX(-10deg);
-ms-transform: perspective(400px) rotateX(-10deg);
transform: perspective(400px) rotateX(-10deg);
}
70% {
-webkit-transform: perspective(400px) rotateX(10deg);
-ms-transform: perspective(400px) rotateX(10deg);
transform: perspective(400px) rotateX(10deg);
}
100% {
-webkit-transform: perspective(400px) rotateX(0deg);
-ms-transform: perspective(400px) rotateX(0deg);
transform: perspective(400px) rotateX(0deg);
opacity: 1;
}
}
.flipInX {
-webkit-backface-visibility: visible !important;
-ms-backface-visibility: visible !important;
backface-visibility: visible !important;
-webkit-animation-name: flipInX;
animation-name: flipInX;
}
@-webkit-keyframes flipInY {
0% {
-webkit-transform: perspective(400px) rotateY(90deg);
transform: perspective(400px) rotateY(90deg);
opacity: 0;
}
40% {
-webkit-transform: perspective(400px) rotateY(-10deg);
transform: perspective(400px) rotateY(-10deg);
}
70% {
-webkit-transform: perspective(400px) rotateY(10deg);
transform: perspective(400px) rotateY(10deg);
}
100% {
-webkit-transform: perspective(400px) rotateY(0deg);
transform: perspective(400px) rotateY(0deg);
opacity: 1;
}
}
@keyframes flipInY {
0% {
-webkit-transform: perspective(400px) rotateY(90deg);
-ms-transform: perspective(400px) rotateY(90deg);
transform: perspective(400px) rotateY(90deg);
opacity: 0;
}
40% {
-webkit-transform: perspective(400px) rotateY(-10deg);
-ms-transform: perspective(400px) rotateY(-10deg);
transform: perspective(400px) rotateY(-10deg);
}
70% {
-webkit-transform: perspective(400px) rotateY(10deg);
-ms-transform: perspective(400px) rotateY(10deg);
transform: perspective(400px) rotateY(10deg);
}
100% {
-webkit-transform: perspective(400px) rotateY(0deg);
-ms-transform: perspective(400px) rotateY(0deg);
transform: perspective(400px) rotateY(0deg);
opacity: 1;
}
}
.flipInY {
-webkit-backface-visibility: visible !important;
-ms-backface-visibility: visible !important;
backface-visibility: visible !important;
-webkit-animation-name: flipInY;
animation-name: flipInY;
}
@-webkit-keyframes flipOutX {
0% {
-webkit-transform: perspective(400px) rotateX(0deg);
transform: perspective(400px) rotateX(0deg);
opacity: 1;
}
100% {
-webkit-transform: perspective(400px) rotateX(90deg);
transform: perspective(400px) rotateX(90deg);
opacity: 0;
}
}
@keyframes flipOutX {
0% {
-webkit-transform: perspective(400px) rotateX(0deg);
-ms-transform: perspective(400px) rotateX(0deg);
transform: perspective(400px) rotateX(0deg);
opacity: 1;
}
100% {
-webkit-transform: perspective(400px) rotateX(90deg);
-ms-transform: perspective(400px) rotateX(90deg);
transform: perspective(400px) rotateX(90deg);
opacity: 0;
}
}
.flipOutX {
-webkit-animation-name: flipOutX;
animation-name: flipOutX;
-webkit-backface-visibility: visible !important;
-ms-backface-visibility: visible !important;
backface-visibility: visible !important;
}
@-webkit-keyframes flipOutY {
0% {
-webkit-transform: perspective(400px) rotateY(0deg);
transform: perspective(400px) rotateY(0deg);
opacity: 1;
}
100% {
-webkit-transform: perspective(400px) rotateY(90deg);
transform: perspective(400px) rotateY(90deg);
opacity: 0;
}
}
@keyframes flipOutY {
0% {
-webkit-transform: perspective(400px) rotateY(0deg);
-ms-transform: perspective(400px) rotateY(0deg);
transform: perspective(400px) rotateY(0deg);
opacity: 1;
}
100% {
-webkit-transform: perspective(400px) rotateY(90deg);
-ms-transform: perspective(400px) rotateY(90deg);
transform: perspective(400px) rotateY(90deg);
opacity: 0;
}
}
.flipOutY {
-webkit-backface-visibility: visible !important;
-ms-backface-visibility: visible !important;
backface-visibility: visible !important;
-webkit-animation-name: flipOutY;
animation-name: flipOutY;
}
@-webkit-keyframes lightSpeedIn {
0% {
-webkit-transform: translateX(100%) skewX(-30deg);
transform: translateX(100%) skewX(-30deg);
opacity: 0;
}
60% {
-webkit-transform: translateX(-20%) skewX(30deg);
transform: translateX(-20%) skewX(30deg);
opacity: 1;
}
80% {
-webkit-transform: translateX(0%) skewX(-15deg);
transform: translateX(0%) skewX(-15deg);
opacity: 1;
}
100% {
-webkit-transform: translateX(0%) skewX(0deg);
transform: translateX(0%) skewX(0deg);
opacity: 1;
}
}
@keyframes lightSpeedIn {
0% {
-webkit-transform: translateX(100%) skewX(-30deg);
-ms-transform: translateX(100%) skewX(-30deg);
transform: translateX(100%) skewX(-30deg);
opacity: 0;
}
60% {
-webkit-transform: translateX(-20%) skewX(30deg);
-ms-transform: translateX(-20%) skewX(30deg);
transform: translateX(-20%) skewX(30deg);
opacity: 1;
}
80% {
-webkit-transform: translateX(0%) skewX(-15deg);
-ms-transform: translateX(0%) skewX(-15deg);
transform: translateX(0%) skewX(-15deg);
opacity: 1;
}
100% {
-webkit-transform: translateX(0%) skewX(0deg);
-ms-transform: translateX(0%) skewX(0deg);
transform: translateX(0%) skewX(0deg);
opacity: 1;
}
}
.lightSpeedIn {
-webkit-animation-name: lightSpeedIn;
animation-name: lightSpeedIn;
-webkit-animation-timing-function: ease-out;
animation-timing-function: ease-out;
}
@-webkit-keyframes lightSpeedOut {
0% {
-webkit-transform: translateX(0%) skewX(0deg);
transform: translateX(0%) skewX(0deg);
opacity: 1;
}
100% {
-webkit-transform: translateX(100%) skewX(-30deg);
transform: translateX(100%) skewX(-30deg);
opacity: 0;
}
}
@keyframes lightSpeedOut {
0% {
-webkit-transform: translateX(0%) skewX(0deg);
-ms-transform: translateX(0%) skewX(0deg);
transform: translateX(0%) skewX(0deg);
opacity: 1;
}
100% {
-webkit-transform: translateX(100%) skewX(-30deg);
-ms-transform: translateX(100%) skewX(-30deg);
transform: translateX(100%) skewX(-30deg);
opacity: 0;
}
}
.lightSpeedOut {
-webkit-animation-name: lightSpeedOut;
animation-name: lightSpeedOut;
-webkit-animation-timing-function: ease-in;
animation-timing-function: ease-in;
}
@-webkit-keyframes rotateIn {
0% {
-webkit-transform-origin: center center;
transform-origin: center center;
-webkit-transform: rotate(-200deg);
transform: rotate(-200deg);
opacity: 0;
}
100% {
-webkit-transform-origin: center center;
transform-origin: center center;
-webkit-transform: rotate(0);
transform: rotate(0);
opacity: 1;
}
}
@keyframes rotateIn {
0% {
-webkit-transform-origin: center center;
-ms-transform-origin: center center;
transform-origin: center center;
-webkit-transform: rotate(-200deg);
-ms-transform: rotate(-200deg);
transform: rotate(-200deg);
opacity: 0;
}
100% {
-webkit-transform-origin: center center;
-ms-transform-origin: center center;
transform-origin: center center;
-webkit-transform: rotate(0);
-ms-transform: rotate(0);
transform: rotate(0);
opacity: 1;
}
}
.rotateIn {
-webkit-animation-name: rotateIn;
animation-name: rotateIn;
}
@-webkit-keyframes rotateInDownLeft {
0% {
-webkit-transform-origin: left bottom;
transform-origin: left bottom;
-webkit-transform: rotate(-90deg);
transform: rotate(-90deg);
opacity: 0;
}
100% {
-webkit-transform-origin: left bottom;
transform-origin: left bottom;
-webkit-transform: rotate(0);
transform: rotate(0);
opacity: 1;
}
}
@keyframes rotateInDownLeft {
0% {
-webkit-transform-origin: left bottom;
-ms-transform-origin: left bottom;
transform-origin: left bottom;
-webkit-transform: rotate(-90deg);
-ms-transform: rotate(-90deg);
transform: rotate(-90deg);
opacity: 0;
}
100% {
-webkit-transform-origin: left bottom;
-ms-transform-origin: left bottom;
transform-origin: left bottom;
-webkit-transform: rotate(0);
-ms-transform: rotate(0);
transform: rotate(0);
opacity: 1;
}
}
.rotateInDownLeft {
-webkit-animation-name: rotateInDownLeft;
animation-name: rotateInDownLeft;
}
@-webkit-keyframes rotateInDownRight {
0% {
-webkit-transform-origin: right bottom;
transform-origin: right bottom;
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
opacity: 0;
}
100% {
-webkit-transform-origin: right bottom;
transform-origin: right bottom;
-webkit-transform: rotate(0);
transform: rotate(0);
opacity: 1;
}
}
@keyframes rotateInDownRight {
0% {
-webkit-transform-origin: right bottom;
-ms-transform-origin: right bottom;
transform-origin: right bottom;
-webkit-transform: rotate(90deg);
-ms-transform: rotate(90deg);
transform: rotate(90deg);
opacity: 0;
}
100% {
-webkit-transform-origin: right bottom;
-ms-transform-origin: right bottom;
transform-origin: right bottom;
-webkit-transform: rotate(0);
-ms-transform: rotate(0);
transform: rotate(0);
opacity: 1;
}
}
.rotateInDownRight {
-webkit-animation-name: rotateInDownRight;
animation-name: rotateInDownRight;
}
@-webkit-keyframes rotateInUpLeft {
0% {
-webkit-transform-origin: left bottom;
transform-origin: left bottom;
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
opacity: 0;
}
100% {
-webkit-transform-origin: left bottom;
transform-origin: left bottom;
-webkit-transform: rotate(0);
transform: rotate(0);
opacity: 1;
}
}
@keyframes rotateInUpLeft {
0% {
-webkit-transform-origin: left bottom;
-ms-transform-origin: left bottom;
transform-origin: left bottom;
-webkit-transform: rotate(90deg);
-ms-transform: rotate(90deg);
transform: rotate(90deg);
opacity: 0;
}
100% {
-webkit-transform-origin: left bottom;
-ms-transform-origin: left bottom;
transform-origin: left bottom;
-webkit-transform: rotate(0);
-ms-transform: rotate(0);
transform: rotate(0);
opacity: 1;
}
}
.rotateInUpLeft {
-webkit-animation-name: rotateInUpLeft;
animation-name: rotateInUpLeft;
}
@-webkit-keyframes rotateInUpRight {
0% {
-webkit-transform-origin: right bottom;
transform-origin: right bottom;
-webkit-transform: rotate(-90deg);
transform: rotate(-90deg);
opacity: 0;
}
100% {
-webkit-transform-origin: right bottom;
transform-origin: right bottom;
-webkit-transform: rotate(0);
transform: rotate(0);
opacity: 1;
}
}
@keyframes rotateInUpRight {
0% {
-webkit-transform-origin: right bottom;
-ms-transform-origin: right bottom;
transform-origin: right bottom;
-webkit-transform: rotate(-90deg);
-ms-transform: rotate(-90deg);
transform: rotate(-90deg);
opacity: 0;
}
100% {
-webkit-transform-origin: right bottom;
-ms-transform-origin: right bottom;
transform-origin: right bottom;
-webkit-transform: rotate(0);
-ms-transform: rotate(0);
transform: rotate(0);
opacity: 1;
}
}
.rotateInUpRight {
-webkit-animation-name: rotateInUpRight;
animation-name: rotateInUpRight;
}
@-webkit-keyframes rotateOut {
0% {
-webkit-transform-origin: center center;
transform-origin: center center;
-webkit-transform: rotate(0);
transform: rotate(0);
opacity: 1;
}
100% {
-webkit-transform-origin: center center;
transform-origin: center center;
-webkit-transform: rotate(200deg);
transform: rotate(200deg);
opacity: 0;
}
}
@keyframes rotateOut {
0% {
-webkit-transform-origin: center center;
-ms-transform-origin: center center;
transform-origin: center center;
-webkit-transform: rotate(0);
-ms-transform: rotate(0);
transform: rotate(0);
opacity: 1;
}
100% {
-webkit-transform-origin: center center;
-ms-transform-origin: center center;
transform-origin: center center;
-webkit-transform: rotate(200deg);
-ms-transform: rotate(200deg);
transform: rotate(200deg);
opacity: 0;
}
}
.rotateOut {
-webkit-animation-name: rotateOut;
animation-name: rotateOut;
}
@-webkit-keyframes rotateOutDownLeft {
0% {
-webkit-transform-origin: left bottom;
transform-origin: left bottom;
-webkit-transform: rotate(0);
transform: rotate(0);
opacity: 1;
}
100% {
-webkit-transform-origin: left bottom;
transform-origin: left bottom;
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
opacity: 0;
}
}
@keyframes rotateOutDownLeft {
0% {
-webkit-transform-origin: left bottom;
-ms-transform-origin: left bottom;
transform-origin: left bottom;
-webkit-transform: rotate(0);
-ms-transform: rotate(0);
transform: rotate(0);
opacity: 1;
}
100% {
-webkit-transform-origin: left bottom;
-ms-transform-origin: left bottom;
transform-origin: left bottom;
-webkit-transform: rotate(90deg);
-ms-transform: rotate(90deg);
transform: rotate(90deg);
opacity: 0;
}
}
.rotateOutDownLeft {
-webkit-animation-name: rotateOutDownLeft;
animation-name: rotateOutDownLeft;
}
@-webkit-keyframes rotateOutDownRight {
0% {
-webkit-transform-origin: right bottom;
transform-origin: right bottom;
-webkit-transform: rotate(0);
transform: rotate(0);
opacity: 1;
}
100% {
-webkit-transform-origin: right bottom;
transform-origin: right bottom;
-webkit-transform: rotate(-90deg);
transform: rotate(-90deg);
opacity: 0;
}
}
@keyframes rotateOutDownRight {
0% {
-webkit-transform-origin: right bottom;
-ms-transform-origin: right bottom;
transform-origin: right bottom;
-webkit-transform: rotate(0);
-ms-transform: rotate(0);
transform: rotate(0);
opacity: 1;
}
100% {
-webkit-transform-origin: right bottom;
-ms-transform-origin: right bottom;
transform-origin: right bottom;
-webkit-transform: rotate(-90deg);
-ms-transform: rotate(-90deg);
transform: rotate(-90deg);
opacity: 0;
}
}
.rotateOutDownRight {
-webkit-animation-name: rotateOutDownRight;
animation-name: rotateOutDownRight;
}
@-webkit-keyframes rotateOutUpLeft {
0% {
-webkit-transform-origin: left bottom;
transform-origin: left bottom;
-webkit-transform: rotate(0);
transform: rotate(0);
opacity: 1;
}
100% {
-webkit-transform-origin: left bottom;
transform-origin: left bottom;
-webkit-transform: rotate(-90deg);
transform: rotate(-90deg);
opacity: 0;
}
}
@keyframes rotateOutUpLeft {
0% {
-webkit-transform-origin: left bottom;
-ms-transform-origin: left bottom;
transform-origin: left bottom;
-webkit-transform: rotate(0);
-ms-transform: rotate(0);
transform: rotate(0);
opacity: 1;
}
100% {
-webkit-transform-origin: left bottom;
-ms-transform-origin: left bottom;
transform-origin: left bottom;
-webkit-transform: rotate(-90deg);
-ms-transform: rotate(-90deg);
transform: rotate(-90deg);
opacity: 0;
}
}
.rotateOutUpLeft {
-webkit-animation-name: rotateOutUpLeft;
animation-name: rotateOutUpLeft;
}
@-webkit-keyframes rotateOutUpRight {
0% {
-webkit-transform-origin: right bottom;
transform-origin: right bottom;
-webkit-transform: rotate(0);
transform: rotate(0);
opacity: 1;
}
100% {
-webkit-transform-origin: right bottom;
transform-origin: right bottom;
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
opacity: 0;
}
}
@keyframes rotateOutUpRight {
0% {
-webkit-transform-origin: right bottom;
-ms-transform-origin: right bottom;
transform-origin: right bottom;
-webkit-transform: rotate(0);
-ms-transform: rotate(0);
transform: rotate(0);
opacity: 1;
}
100% {
-webkit-transform-origin: right bottom;
-ms-transform-origin: right bottom;
transform-origin: right bottom;
-webkit-transform: rotate(90deg);
-ms-transform: rotate(90deg);
transform: rotate(90deg);
opacity: 0;
}
}
.rotateOutUpRight {
-webkit-animation-name: rotateOutUpRight;
animation-name: rotateOutUpRight;
}
@-webkit-keyframes slideInDown {
0% {
opacity: 0;
-webkit-transform: translateY(-2000px);
transform: translateY(-2000px);
}
100% {
-webkit-transform: translateY(0);
transform: translateY(0);
}
}
@keyframes slideInDown {
0% {
opacity: 0;
-webkit-transform: translateY(-2000px);
-ms-transform: translateY(-2000px);
transform: translateY(-2000px);
}
100% {
-webkit-transform: translateY(0);
-ms-transform: translateY(0);
transform: translateY(0);
}
}
.slideInDown {
-webkit-animation-name: slideInDown;
animation-name: slideInDown;
}
@-webkit-keyframes slideInLeft {
0% {
opacity: 0;
-webkit-transform: translateX(-2000px);
transform: translateX(-2000px);
}
100% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
}
@keyframes slideInLeft {
0% {
opacity: 0;
-webkit-transform: translateX(-2000px);
-ms-transform: translateX(-2000px);
transform: translateX(-2000px);
}
100% {
-webkit-transform: translateX(0);
-ms-transform: translateX(0);
transform: translateX(0);
}
}
.slideInLeft {
-webkit-animation-name: slideInLeft;
animation-name: slideInLeft;
}
@-webkit-keyframes slideInRight {
0% {
opacity: 0;
-webkit-transform: translateX(2000px);
transform: translateX(2000px);
}
100% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
}
@keyframes slideInRight {
0% {
opacity: 0;
-webkit-transform: translateX(2000px);
-ms-transform: translateX(2000px);
transform: translateX(2000px);
}
100% {
-webkit-transform: translateX(0);
-ms-transform: translateX(0);
transform: translateX(0);
}
}
.slideInRight {
-webkit-animation-name: slideInRight;
animation-name: slideInRight;
}
@-webkit-keyframes slideOutLeft {
0% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
100% {
opacity: 0;
-webkit-transform: translateX(-2000px);
transform: translateX(-2000px);
}
}
@keyframes slideOutLeft {
0% {
-webkit-transform: translateX(0);
-ms-transform: translateX(0);
transform: translateX(0);
}
100% {
opacity: 0;
-webkit-transform: translateX(-2000px);
-ms-transform: translateX(-2000px);
transform: translateX(-2000px);
}
}
.slideOutLeft {
-webkit-animation-name: slideOutLeft;
animation-name: slideOutLeft;
}
@-webkit-keyframes slideOutRight {
0% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
100% {
opacity: 0;
-webkit-transform: translateX(2000px);
transform: translateX(2000px);
}
}
@keyframes slideOutRight {
0% {
-webkit-transform: translateX(0);
-ms-transform: translateX(0);
transform: translateX(0);
}
100% {
opacity: 0;
-webkit-transform: translateX(2000px);
-ms-transform: translateX(2000px);
transform: translateX(2000px);
}
}
.slideOutRight {
-webkit-animation-name: slideOutRight;
animation-name: slideOutRight;
}
@-webkit-keyframes slideOutUp {
0% {
-webkit-transform: translateY(0);
transform: translateY(0);
}
100% {
opacity: 0;
-webkit-transform: translateY(-2000px);
transform: translateY(-2000px);
}
}
@keyframes slideOutUp {
0% {
-webkit-transform: translateY(0);
-ms-transform: translateY(0);
transform: translateY(0);
}
100% {
opacity: 0;
-webkit-transform: translateY(-2000px);
-ms-transform: translateY(-2000px);
transform: translateY(-2000px);
}
}
.slideOutUp {
-webkit-animation-name: slideOutUp;
animation-name: slideOutUp;
}
@-webkit-keyframes slideInUp {
0% {
-webkit-transform: translateY(2000px);
transform: translateY(2000px);
}
100% {
opacity: 0;
-webkit-transform: translateY(0);
transform: translateY(0);
}
}
@keyframes slideInUp {
0% {
-webkit-transform: translateY(2000px);
-ms-transform: translateY(2000px);
transform: translateY(2000px);
}
100% {
opacity: 0;
-webkit-transform: translateY(0);
-ms-transform: translateY(0);
transform: translateY(0);
}
}
.slideInUp {
-webkit-animation-name: slideInUp;
animation-name: slideInUp;
}
@-webkit-keyframes slideOutDown {
0% {
-webkit-transform: translateY(0);
transform: translateY(0);
}
100% {
opacity: 0;
-webkit-transform: translateY(2000px);
transform: translateY(2000px);
}
}
@keyframes slideOutDown {
0% {
-webkit-transform: translateY(0);
-ms-transform: translateY(0);
transform: translateY(0);
}
100% {
opacity: 0;
-webkit-transform: translateY(2000px);
-ms-transform: translateY(2000px);
transform: translateY(2000px);
}
}
.slideOutDown {
-webkit-animation-name: slideOutDown;
animation-name: slideOutDown;
}
@-webkit-keyframes hinge {
0% {
-webkit-transform: rotate(0);
transform: rotate(0);
-webkit-transform-origin: top left;
transform-origin: top left;
-webkit-animation-timing-function: ease-in-out;
animation-timing-function: ease-in-out;
}
20%, 60% {
-webkit-transform: rotate(80deg);
transform: rotate(80deg);
-webkit-transform-origin: top left;
transform-origin: top left;
-webkit-animation-timing-function: ease-in-out;
animation-timing-function: ease-in-out;
}
40% {
-webkit-transform: rotate(60deg);
transform: rotate(60deg);
-webkit-transform-origin: top left;
transform-origin: top left;
-webkit-animation-timing-function: ease-in-out;
animation-timing-function: ease-in-out;
}
80% {
-webkit-transform: rotate(60deg) translateY(0);
transform: rotate(60deg) translateY(0);
-webkit-transform-origin: top left;
transform-origin: top left;
-webkit-animation-timing-function: ease-in-out;
animation-timing-function: ease-in-out;
opacity: 1;
}
100% {
-webkit-transform: translateY(700px);
transform: translateY(700px);
opacity: 0;
}
}
@keyframes hinge {
0% {
-webkit-transform: rotate(0);
-ms-transform: rotate(0);
transform: rotate(0);
-webkit-transform-origin: top left;
-ms-transform-origin: top left;
transform-origin: top left;
-webkit-animation-timing-function: ease-in-out;
animation-timing-function: ease-in-out;
}
20%, 60% {
-webkit-transform: rotate(80deg);
-ms-transform: rotate(80deg);
transform: rotate(80deg);
-webkit-transform-origin: top left;
-ms-transform-origin: top left;
transform-origin: top left;
-webkit-animation-timing-function: ease-in-out;
animation-timing-function: ease-in-out;
}
40% {
-webkit-transform: rotate(60deg);
-ms-transform: rotate(60deg);
transform: rotate(60deg);
-webkit-transform-origin: top left;
-ms-transform-origin: top left;
transform-origin: top left;
-webkit-animation-timing-function: ease-in-out;
animation-timing-function: ease-in-out;
}
80% {
-webkit-transform: rotate(60deg) translateY(0);
-ms-transform: rotate(60deg) translateY(0);
transform: rotate(60deg) translateY(0);
-webkit-transform-origin: top left;
-ms-transform-origin: top left;
transform-origin: top left;
-webkit-animation-timing-function: ease-in-out;
animation-timing-function: ease-in-out;
opacity: 1;
}
100% {
-webkit-transform: translateY(700px);
-ms-transform: translateY(700px);
transform: translateY(700px);
opacity: 0;
}
}
.hinge {
-webkit-animation-name: hinge;
animation-name: hinge;
}
/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */
@-webkit-keyframes rollIn {
0% {
opacity: 0;
-webkit-transform: translateX(-100%) rotate(-120deg);
transform: translateX(-100%) rotate(-120deg);
}
100% {
opacity: 1;
-webkit-transform: translateX(0px) rotate(0deg);
transform: translateX(0px) rotate(0deg);
}
}
@keyframes rollIn {
0% {
opacity: 0;
-webkit-transform: translateX(-100%) rotate(-120deg);
-ms-transform: translateX(-100%) rotate(-120deg);
transform: translateX(-100%) rotate(-120deg);
}
100% {
opacity: 1;
-webkit-transform: translateX(0px) rotate(0deg);
-ms-transform: translateX(0px) rotate(0deg);
transform: translateX(0px) rotate(0deg);
}
}
.rollIn {
-webkit-animation-name: rollIn;
animation-name: rollIn;
}
/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */
@-webkit-keyframes rollOut {
0% {
opacity: 1;
-webkit-transform: translateX(0px) rotate(0deg);
transform: translateX(0px) rotate(0deg);
}
100% {
opacity: 0;
-webkit-transform: translateX(100%) rotate(120deg);
transform: translateX(100%) rotate(120deg);
}
}
@keyframes rollOut {
0% {
opacity: 1;
-webkit-transform: translateX(0px) rotate(0deg);
-ms-transform: translateX(0px) rotate(0deg);
transform: translateX(0px) rotate(0deg);
}
100% {
opacity: 0;
-webkit-transform: translateX(100%) rotate(120deg);
-ms-transform: translateX(100%) rotate(120deg);
transform: translateX(100%) rotate(120deg);
}
}
.rollOut {
-webkit-animation-name: rollOut;
animation-name: rollOut;
}
\ No newline at end of file
/* custom */
.table {
font-size: 12px;
}
.table > tbody > tr > td.data {
padding-top: 6px;
padding-bottom: 6px;
padding-left: 10px;
padding-right: 10px;
font-size: 11px;
}
.table-bordered {
border: 1px solid #EBEBEB !important;
}
.table-toolbar {
display: inline-flex;
margin-bottom: 5px;
}
.table > tbody > tr > td.cell_selector {
padding-left: 5px;
}
.table > tbody > tr > td.maxwidth {
width: 100%;
word-wrap: break-word;
}
.page-selector {
width: 100px;float: left;
}
.selectable {
cursor: pointer;
}
.not-selectable {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.row-options {
padding-bottom: 2px;
padding-top: 2px;
min-width: 105px;
text-align: center;
vertical-align: middle;
}
.row-toolbar {
padding: 0px;
display: inline;
}
.row-toolbar .btn {
margin-bottom: 0px;
}
.sidebar-container .sidebar-option > .link-option > .pull-left {
margin-right: 10px;
}
.sidebar-container .sidebar-option > .link-option {
text-decoration: none;
/*color: inherit;*/
}
.sidebar-container .sidebar-option {
padding: 0px 0px;
}
.link-option {
color: #337ab7;
}
.control-label {
display: inline-block;
max-width: 100%;
margin-bottom: 2px;
font-weight: 500;
}
.suggets-label {
display: block;
max-width: 100%;
margin-bottom: 2px;
font-size: 11px;
font-weight: 200;
}
.field-legend {
font-weight: 700;
}
.mail-tools {
margin-bottom: 5px;
}
label > .control-label {
font-weight: 600;
width: 100%;
display: inline-block;
}
.form-group > .checkbox {
margin-bottom: 0px !important;
}
legend {
margin-bottom: 10px;
}
form .CustomValidationError {
position: relative;
font-size: 0.8em;
color: rgb(204, 78, 78);
text-align: left;
display: block;
}
form .CustomValidationError.checkboxradioerror {
display: block;
}
form .requiredFieldLabel:after {
content: " *";
color: red;
}
#login_form .form-group {
text-align: left;
}
.form-group {
margin-bottom: 15px;
}
.inputFail, form input.ng-dirty:not(.ValidationLiveSuccess) {
border-color: #a94442;
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
}
.inputSuccess, form input.ng-dirty.ValidationLiveSuccess {
border-color: #1C84C6;
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
}
::-moz-placeholder {
color: #A7A4A4;
opacity: 1;
font-weight: 100;
}
:-moz-placeholder { /* Firefox 18- */
color: #A7A4A4;
opacity: 1;
font-weight: 100;
}
:-ms-input-placeholder {
color: #A7A4A4;
font-weight: 100;
}
::-webkit-input-placeholder {
color: #A7A4A4;
font-weight: 100;
}
.letraS {
background-color:#193F67;
color:white;
border-radius: 2px 0 0 2px;
padding-right: 1px;
padding-left: 2px;
}
.letraG {
background-color:#193F67;
color:white;
padding-left: 1px;
padding-right: 2px;
}
.letraA {
background-color:#AA1835;
color:white;
border-radius: 0 2px 2px 0;
padding-right: 2px;
padding-left: 1px;
}
[date-picker-wrapper] {
position: absolute;
border: 2px;
min-width: 220px;
z-index: 10;
display: block;
font-size: 12px;
}
[date-picker-wrapper] > div {
-webkit-box-shadow: 0 0 3px rgba(86, 96, 117, 0.7);
-moz-box-shadow: 0 0 3px rgba(86, 96, 117, 0.7);
box-shadow: 0 0 3px rgba(86, 96, 117, 0.7);
border: 2px;
}
.thumbnail {
max-width: 200px;
max-height: 150px;
line-height: 20px;
margin-bottom: 5px;
}
#logo_cliente {
margin-bottom: 5px;
display: inline-flex !important;
}
#logo_cliente>img {
max-height: 51px;
padding: 8px;
width: auto;
}
.logo_byte {
margin-bottom: 5px;
display: inline-flex;
}
.logo_byte>a>img {
max-height: 80px;
padding: 10px;
width: auto;
}
.logo_byte_header {
text-align: center;
}
.progress {
max-width: 200px;
}
.note-editor {
border: 1px solid #e5e6e7;
border-radius: 4px;
}
.hr-line-dashed-home {
border-top: 1px dashed #e7eaec;
color: #ffffff;
background-color: #ffffff;
height: 1px;
margin: 10px 0px 0px 0px;
}
ul.nav.navbar-top-links.navbar-right.nav-main {
padding-top: 5px;
}
.font-topnavbar {
font-size: 12px;
}
.input-group .form-control {
margin-bottom: 0px;
}
/* configuración de filtros */
.ibox-filter.text-box {
padding-bottom: 0px;
padding-top: 15px;
}
.ibox-filter {
background-color: #ffffff;
color: inherit;
/*padding: 5px 20px 0px 20px;*/
border-color: #e7eaec;
border-image: none;
/*border-style: solid solid none;
border-width: 1px 0px;*/
margin-bottom: 5px;
}
.ibox-filter {
clear: both;
}
.form-control {
height: 31px;
}
tags-input {
display: block;
width: 100%;
}
tags-input *, tags-input *:before, tags-input *:after {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
tags-input .host {
position: relative;
/* margin-top: 5px; */
/* margin-bottom: 5px; */
height: 100%;
width: 100% !important;
display: table;
}
tags-input .host:active {
outline: none;
}
tags-input .tags {
padding: 1px;
overflow: hidden;
word-wrap: break-word;
cursor: text;
background-color: #fff;
border: 1px solid #e7eaec;
height: 100%;
border-radius: 3px;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
font-size: 12px;
}
tags-input .tags.focused {
outline: none;
-webkit-box-shadow: 0 0 3px 1px rgba(5, 139, 242, 0.6);
-moz-box-shadow: 0 0 3px 1px rgba(5, 139, 242, 0.6);
box-shadow: 0 0 3px 1px rgba(5, 139, 242, 0.6);
margin-right: 2px;
}
tags-input .tags .tag-list {
margin: 0;
padding: 0;
list-style-type: none;
}
tags-input .tags .tag-item {
margin-right: 2px;
padding: 0 5px;
display: inline-flex;
float: left;
height: 27px;
line-height: 25px;
border: 1px solid #acacac;
border-radius: 3px;
}
tags-input .tags .tag-item.selected {
background: -webkit-linear-gradient(top, #febbbb 0%, #fe9090 45%, #ff5c5c 100%);
background: linear-gradient(to bottom, #febbbb 0%, #fe9090 45%, #ff5c5c 100%);
}
tags-input .tags .tag-item .remove-button {
margin: 0 0 0 5px;
padding: 0;
border: none;
background: none;
cursor: pointer;
vertical-align: middle;
/* font: 14px Arial, sans-serif; */
/* font-size: 14px; */
color: rgba(177, 5, 5, 0.48);
display: inline;
}
tags-input .tags .tag-item .remove-button:active {
color: #ff0000;
}
tags-input .tags .input {
border: 0;
outline: none;
margin: 2px;
padding: 0;
padding-left: 5px;
float: left;
height: 23px;
}
tags-input .tags .input.invalid-tag {
color: #ff0000;
}
tags-input .tags .input::-ms-clear {
display: none;
}
tags-input.ng-invalid .tags {
-webkit-box-shadow: 0 0 3px 1px rgba(255, 0, 0, 0.6);
-moz-box-shadow: 0 0 3px 1px rgba(255, 0, 0, 0.6);
box-shadow: 0 0 3px 1px rgba(255, 0, 0, 0.6);
}
tags-input[disabled] .host:focus {
outline: none;
}
tags-input[disabled] .tags {
background-color: #eee;
cursor: default;
}
tags-input[disabled] .tags .tag-item {
opacity: 0.65;
background: -webkit-linear-gradient(top, #f0f9ff 0%, rgba(203, 235, 255, 0.75) 47%, rgba(161, 219, 255, 0.62) 100%);
background: linear-gradient(to bottom, #f0f9ff 0%, rgba(203, 235, 255, 0.75) 47%, rgba(161, 219, 255, 0.62) 100%);
}
tags-input[disabled] .tags .tag-item .remove-button {
cursor: default;
}
tags-input[disabled] .tags .tag-item .remove-button:active {
color: #585858;
}
tags-input[disabled] .tags .input {
background-color: #eee;
cursor: default;
}
tags-input .autocomplete {
/* margin-top: 5px; */
position: absolute;
padding: 5px 0;
z-index: 999;
width: 100%;
background-color: #fff;
border: 1px solid rgba(0, 0, 0, 0.2);
-webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
-moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
}
tags-input .autocomplete .suggestion-list {
margin: 0;
padding: 0;
list-style-type: none;
max-height: 280px;
overflow-y: auto;
position: relative;
}
tags-input .autocomplete .suggestion-item {
padding: 5px 10px;
cursor: pointer;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font: 16px "Helvetica Neue", Helvetica, Arial, sans-serif;
color: #000;
background-color: #fff;
}
tags-input .autocomplete .suggestion-item.selected {
color: #fff;
background-color: #0097cf;
}
tags-input .autocomplete .suggestion-item.selected em {
color: #fff;
background-color: #0097cf;
}
tags-input .autocomplete .suggestion-item em {
font: normal bold 16px "Helvetica Neue", Helvetica, Arial, sans-serif;
color: #000;
background-color: #fff;
}
.btn-group > button > span {
font-size: 11px;
}
.dropdown-title {
background: #f9f9f9;
padding: 5px 5px 0px 5px;
border-bottom: 1px solid #e7eaec;
}
.dropdown-menu .divider_0_padding {
height: 1px;
overflow: hidden;
background-color: #e5e5e5;
}
.dropdown-menu-item > a.ng-binding {
font-size: 11px;
}
.wizard-box-header {
background-color: #ffffff;
border-bottom: 1px solid #e7eaec;
padding: 0px 20px 20px 20px;
}
.wizard-box-content-tabs {
padding-top: 20px;
}
.lockscreen-box {
z-index: 100;
margin: 0 auto;
padding: 0px 20px 40px 20px;
}
.header_text {
font-size: 18px;
padding-left: 20px;
vertical-align: bottom;
font-weight: 600;
}
.glyphicon.glyphicon-calendar {
cursor: pointer;
}
.placeholder-label {
opacity: 0.5;
font-weight: 400;
}
.checkbox input[type=checkbox], .checkbox-inline input[type=checkbox], .radio input[type=radio], .radio-inline input[type=radio] {
position: relative !important;
margin-left: -16px !important;
}
.angucomplete-dropdown {
overflow-y: auto;
margin-top: 1px;
max-height: 210px; /* your preference*/
}
.input-group > div > .angucomplete-holder > .angucomplete-dropdown {
overflow-y: auto;
margin-top: 31px;
max-height: 210px;
}
.nav-tabs > li > a {
font-weight: 100;
}
// Pagination
.pagination {
display: inline-flex;
padding-left: 0;
margin: 10px 0;
border-radius: 4px;
}
.pagination .footable-page.active a {
background-color: #1ab394;
border-color: #1ab394;
color: white;
}
.paginationByte {
display: inline-flex;
padding-left: 0;
margin: 20px 0 !important;
border-radius: 4px;
}
.page-item.disabled {
cursor: not-allowed;
}
.page-item.active .page-link {
background-color: #f4f4f4;
border-color: #DDDDDD;
color: #212529;
}
.page-link {
position: relative;
display: block;
padding: 0.3rem 0.45rem;
margin-left: -1px;
line-height: 1.25;
background-color: #fff;
border: 1px solid #dee2e6;
}
.page-link:focus {
box-shadow: none;
}
.page-link:hover {
color: #676a6c;
}
// File-list
.file-list li {
padding: 5px 10px;
font-size: 11px;
border-radius: 2px;
border: 1px solid #e7eaec;
margin-bottom: 5px;
}
.file-list li a {
color: inherit;
}
.file-list li a:hover {
color: #1ab394;
}
// xxxxxxxxxxxxxxxxxxxxxx
.chosen-container.chosen-container-single.chosen-container-active {
cursor: pointer;
width: 100% !important;
}
.chosen-container {
width: 100% !important;
}
.chosen-container .chosen-results {
margin: 2px 0 0 !important;
padding: 5px 0 !important;
font-size: 12px !important;
font-family: "open sans" !important;
list-style: none !important;
background-color: #fff !important;
margin-bottom: 5px !important;
max-height: 80px !important;
}
.chosen-container-single .chosen-single {
background: #ffffff !important;
box-shadow: none !important;
box-sizing: border-box !important;
background-color: #FFFFFF !important;
border-radius: 4px !important;
cursor: pointer !important;
height: 31px !important;
margin: 0 !important;
overflow: hidden !important;
padding: 4px 12px !important;
position: relative !important;
width: 100% !important;
}
.tamanio-logo {
width: 350px;
margin: 30px 40px 50px 0;
}
.label-tabulacion {
width: 150px;
font-weight: 600 !important;
}
.text-view {
font-size: 12px;
}
ol {
list-style: none;
}
.note-editor ol {
list-style-type: decimal;
}
.alinear-programa {
width: 255px;
text-align: left;
margin-left: 5px;
}
.alinear-menu {
width: 215px;
text-align: left;
margin-left: 5px;
}
.alinear-accion {
width: 200px;
text-align: left;
}
.alinear-menu {
width: 215px;
text-align: left;
margin-left: 5px;
}
.chosen-choices {
height: 34px;
}
.chosen-container.chosen-container-multi {
width: 100% !important;
}
.chosen-container.chosen-container-multi.chosen-with-drop.chosen-container-active {
width: 100% !important;
}
tags-input .tags.focused {
border-color: #1ab394 !important;
outline: 0 !important;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
margin-right: 0px;
}
tags-input.ng-invalid .tags {
border-color: rgba(255, 0, 0, 0.6);
outline: 0;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
}
tags-input .tags {
border-radius: 4px;
}
.dual-list .list-group {
margin-top: 8px;
}
.list-left li, .list-right li {
cursor: pointer;
}
.list-arrows {
padding-top: 100px;
}
.list-arrows button {
margin-bottom: 20px;
}
.panel-no-padding {
padding: 0px !important;
}
.mail-box-header {
background-color: #ffffff;
border: 1px solid #e7eaec;
border-bottom: 0;
padding: 15px 20px 1px 20px;
}
.mail-box-content-tabs {
background-color: #ffffff;
/* border: 1px solid #e7eaec; */
/* border-bottom: 0; */
padding: 15px 20px 15px 20px;
}
.mail-box-header-tabs {
background-color: #ffffff;
border: 1px solid #e7eaec;
padding: 0px 20px 1px 20px;
border-left: none !important;
border-top: none !important;
border-right: none !important;
}
.ibox-title-widget {
background-color: #ffffff;
border-color: #e7eaec;
border-image: none;
border-style: solid solid none;
border-width: 4px 0px 0;
color: inherit;
margin-bottom: 0;
padding: 14px 15px 7px;
min-height: 48px;
}
.ibox-content-widget {
background-color: #ffffff;
color: inherit;
padding: 15px 20px 20px 20px;
border-color: #e7eaec;
border-image: none;
border-style: solid solid none;
border-width: 1px 0px;
}
.ibox-footer-widget {
color: inherit;
border-top: 1px solid #e7eaec;
font-size: 90%;
background: #ffffff;
padding: 10px 15px;
}
.content-widget {
min-height: 160px !important;
}
.navfloat {
opacity: 0;
padding: 5px;
background: #f3f3f4;
z-index: 1500;
display: none;
}
.navfloat ul {
margin: 0;
padding: 0;
}
.navfloat li {
float: right;
padding: 3px 8px 0px 8px;
margin: 0 30px 0 0;
color: #F00;
list-style-type: none;
}
.input-group-btn:last-child>.btn, .input-group-btn:last-child>.btn-group {
z-index: 0;
}
/* chosen */
select.form-control + .chosen-container.chosen-container-single .chosen-single {
display: inline-block;
width: 100%;
height: 34px;
padding: 6px 12px;
font-family: "open sans";
font-size: 12px;
line-height: 1.428571429;
color: #555;
vertical-align: middle;
background-color: #fff;
border: 1px solid #e5e6e7;
border-radius: 4px;
-webkit-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
background-image:none;
}
select.form-control + .chosen-container.chosen-container-single .chosen-single div {
top:4px;
color:#000;
}
select.form-control + .chosen-container .chosen-drop {
background-color: #FFF;
border: 1px solid #CCC;
border: 1px solid rgba(0, 0, 0, 0.15);
border-radius: 4px;
background-clip: padding-box;
margin: 1px 0 0;
}
select.form-control + .chosen-container .chosen-search input[type=text] {
display: inline-block;
width: 100%;
height: 31px;
padding: 5px 6px 4px 6px;
font-size: 12px;
font-family: "open sans";
line-height: 1.428571429;
color: #555;
vertical-align: middle;
background-color: #FFF;
border: 1px solid #CCC;
border-radius: 4px;
transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
background-image:none;
}
select.form-control + .chosen-container .chosen-results {
margin: 2px 0 0;
padding: 5px 0;
font-size: 12px;
font-family: "open sans";
list-style: none;
background-color: #fff;
margin-bottom: 5px;
}
select.form-control + .chosen-container .chosen-results li ,
select.form-control + .chosen-container .chosen-results li.active-result {
display: block;
padding: 3px 20px;
clear: both;
font-weight: normal;
line-height: 1.428571429;
color: #333;
white-space: nowrap;
background-image:none;
}
select.form-control + .chosen-container .chosen-results li:hover,
select.form-control + .chosen-container .chosen-results li.active-result:hover,
select.form-control + .chosen-container .chosen-results li.highlighted {
color: #FFF;
text-decoration: none;
background-color: #428BCA;
background-image:none;
}
select.form-control + .chosen-container-multi .chosen-choices {
display: inline-block;
width: 100%;
min-height: 31px;
padding: 1px;
font-size: 12px;
font-family: "open sans";
line-height: 1.428571429;
color: #555;
vertical-align: middle;
background-color: #FFF;
border: 1px solid #E5E6E7;
border-radius: 4px;
-webkit-transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
background-image:none;
}
select.form-control + .chosen-container-multi .chosen-choices li.search-field input[type="text"] {
height:auto;
font-family: "open sans";
padding: 5px 0px 0px 10px;
}
select.form-control + .chosen-container-multi .chosen-choices li.search-choice {
background-image: none;
padding: 3px 24px 2px 5px;
margin: 1px 6px -5px 2px;
font-size: 12px;
font-family: "open sans";
font-weight: normal;
line-height: 1.428571429;
text-align: center;
white-space: nowrap;
vertical-align: middle;
cursor: pointer;
border: 1px solid #ccc;
border-radius: 4px;
color: #333;
background-color: #FFF;
border-color: #CCC;
}
select.form-control + .chosen-container-multi .chosen-choices li.search-choice .search-choice-close {
top:5px;
right:6px;
}
select.form-control + .chosen-container-multi.chosen-container-active .chosen-choices,
select.form-control + .chosen-container.chosen-container-single.chosen-container-active .chosen-single,
select.form-control + .chosen-container .chosen-search input[type=text]:focus{
border-color: #1ab394;
outline: 0;
}
select.form-control + .chosen-container-multi .chosen-results li.result-selected{
display: list-item;
color: #ccc;
cursor: default;
background-color: white;
}
.chosen-container-active {
background-color: white;
}
.checkbox input[type=checkbox], .checkbox-inline input[type=checkbox], .radio input[type=radio], .radio-inline input[type=radio] {
position: relative !important;
margin-left: -16px !important;
}
.angucomplete-dropdown {
overflow-y: auto;
margin-top: 1px;
max-height: 210px; /* your preference*/
}
.input-group > div > .angucomplete-holder > .angucomplete-dropdown {
overflow-y: auto;
margin-top: 31px;
max-height: 210px;
}
/*truncate label for tables*/
.truncate-label {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis ;
margin-bottom: 0px;
}
.clsDatePicker {
z-index: 1000 !important;
}
.hr-border-line {
border-top: 1px dashed #e7eaec;
color: #ffffff;
background-color: #ffffff;
height: 1px;
margin-top: 10px;
margin-bottom: 15px;
}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
/*
bootstrap table theme
*/
.ngx-datatable.theme {
box-shadow: none;
font-size: 13px; }
.ngx-datatable.theme .datatable-header {
height: unset !important; }
.ngx-datatable.theme .datatable-header .datatable-header-cell {
vertical-align: bottom;
padding: 0.75rem;
border-bottom: 1px solid #d1d4d7; }
.ngx-datatable.theme .datatable-header .datatable-header-cell .datatable-header-cell-label {
line-height: 24px; }
.ngx-datatable.theme .datatable-body .datatable-body-row {
padding: 0.75rem;
vertical-align: top;
border-top: 1px solid #d1d4d7; }
.ngx-datatable.theme .datatable-body .datatable-body-row.datatable-row-even {
background-color: rgba(0, 0, 0, 0.05); }
.ngx-datatable.theme .datatable-body .datatable-body-row.active {
background-color: #1483ff;
color: #FFF; }
.ngx-datatable.theme .datatable-body .datatable-body-row .datatable-body-cell {
text-align: left;
vertical-align: top; }
.ngx-datatable.theme .datatable-footer {
background: #424242;
color: #ededed;
margin-top: -1px; }
.ngx-datatable.theme .datatable-footer .page-count {
line-height: 50px;
height: 50px;
padding: 0 1.2rem; }
.ngx-datatable.theme .datatable-footer .datatable-pager {
margin: 0 10px;
vertical-align: top; }
.ngx-datatable.theme .datatable-footer .datatable-pager ul li {
margin: 10px 0px; }
.ngx-datatable.theme .datatable-footer .datatable-pager ul li:not(.disabled).active a, .ngx-datatable.theme .datatable-footer .datatable-pager ul li:not(.disabled):hover a {
background-color: #545454;
font-weight: bold; }
.ngx-datatable.theme .datatable-footer .datatable-pager a {
height: 22px;
min-width: 24px;
line-height: 22px;
padding: 0;
border-radius: 3px;
margin: 0 3px;
text-align: center;
vertical-align: top;
text-decoration: none;
vertical-align: bottom;
color: #ededed; }
.ngx-datatable.theme .datatable-footer .datatable-pager .datatable-icon-left,
.ngx-datatable.theme .datatable-footer .datatable-pager .datatable-icon-skip,
.ngx-datatable.theme .datatable-footer .datatable-pager .datatable-icon-right,
.ngx-datatable.theme .datatable-footer .datatable-pager .datatable-icon-prev {
font-size: 18px;
line-height: 27px;
padding: 0 3px; }
.ngx-datatable.theme .datatable-summary-row .datatable-body-row .datatable-body-cell {
font-weight: bold; }
.ngx-datatable.theme {
background: #FFF;
box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2), 0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12);
/**
* Shared Styles
*/
/**
* Global Row Styles
*/
/**
* Header Styles
*/
/**
* Body Styles
*/
/**
* Footer Styles
*/ }
.ngx-datatable.theme.striped .datatable-row-odd {
background: #eee; }
.ngx-datatable.theme.single-selection .datatable-body-row.active,
.ngx-datatable.theme.single-selection .datatable-body-row.active .datatable-row-group, .ngx-datatable.theme.multi-selection .datatable-body-row.active,
.ngx-datatable.theme.multi-selection .datatable-body-row.active .datatable-row-group, .ngx-datatable.theme.multi-click-selection .datatable-body-row.active,
.ngx-datatable.theme.multi-click-selection .datatable-body-row.active .datatable-row-group {
background-color: #304FFE;
color: #FFF; }
.ngx-datatable.theme.single-selection .datatable-body-row.active:hover,
.ngx-datatable.theme.single-selection .datatable-body-row.active:hover .datatable-row-group, .ngx-datatable.theme.multi-selection .datatable-body-row.active:hover,
.ngx-datatable.theme.multi-selection .datatable-body-row.active:hover .datatable-row-group, .ngx-datatable.theme.multi-click-selection .datatable-body-row.active:hover,
.ngx-datatable.theme.multi-click-selection .datatable-body-row.active:hover .datatable-row-group {
background-color: #193AE4;
color: #FFF; }
.ngx-datatable.theme.single-selection .datatable-body-row.active:focus,
.ngx-datatable.theme.single-selection .datatable-body-row.active:focus .datatable-row-group, .ngx-datatable.theme.multi-selection .datatable-body-row.active:focus,
.ngx-datatable.theme.multi-selection .datatable-body-row.active:focus .datatable-row-group, .ngx-datatable.theme.multi-click-selection .datatable-body-row.active:focus,
.ngx-datatable.theme.multi-click-selection .datatable-body-row.active:focus .datatable-row-group {
background-color: #2041EF;
color: #FFF; }
.ngx-datatable.theme:not(.cell-selection) .datatable-body-row:hover,
.ngx-datatable.theme:not(.cell-selection) .datatable-body-row:hover .datatable-row-group {
background-color: #eee;
transition-property: background;
transition-duration: .3s;
transition-timing-function: linear; }
.ngx-datatable.theme:not(.cell-selection) .datatable-body-row:focus,
.ngx-datatable.theme:not(.cell-selection) .datatable-body-row:focus .datatable-row-group {
background-color: #ddd; }
.ngx-datatable.theme.cell-selection .datatable-body-cell:hover,
.ngx-datatable.theme.cell-selection .datatable-body-cell:hover .datatable-row-group {
background-color: #eee;
transition-property: background;
transition-duration: .3s;
transition-timing-function: linear; }
.ngx-datatable.theme.cell-selection .datatable-body-cell:focus,
.ngx-datatable.theme.cell-selection .datatable-body-cell:focus .datatable-row-group {
background-color: #ddd; }
.ngx-datatable.theme.cell-selection .datatable-body-cell.active,
.ngx-datatable.theme.cell-selection .datatable-body-cell.active .datatable-row-group {
background-color: #304FFE;
color: #FFF; }
.ngx-datatable.theme.cell-selection .datatable-body-cell.active:hover,
.ngx-datatable.theme.cell-selection .datatable-body-cell.active:hover .datatable-row-group {
background-color: #193AE4;
color: #FFF; }
.ngx-datatable.theme.cell-selection .datatable-body-cell.active:focus,
.ngx-datatable.theme.cell-selection .datatable-body-cell.active:focus .datatable-row-group {
background-color: #2041EF;
color: #FFF; }
.ngx-datatable.theme .empty-row {
height: 50px;
text-align: left;
padding: .5rem 1.2rem;
vertical-align: top;
border-top: 0; }
.ngx-datatable.theme .loading-row {
text-align: left;
padding: .5rem 1.2rem;
vertical-align: top;
border-top: 0; }
.ngx-datatable.theme .datatable-header .datatable-row-left,
.ngx-datatable.theme .datatable-body .datatable-row-left {
background-color: #FFF;
background-position: 100% 0;
background-repeat: repeat-y;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAABCAYAAAD5PA/NAAAAFklEQVQIHWPSkNeSBmJhTQVtbiDNCgASagIIuJX8OgAAAABJRU5ErkJggg==); }
.ngx-datatable.theme .datatable-header .datatable-row-right,
.ngx-datatable.theme .datatable-body .datatable-row-right {
background-position: 0 0;
background-color: #fff;
background-repeat: repeat-y;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAABCAYAAAD5PA/NAAAAFklEQVQI12PQkNdi1VTQ5gbSwkAsDQARLAIGtOSFUAAAAABJRU5ErkJggg==); }
.ngx-datatable.theme .datatable-header {
border-bottom: 1px solid rgba(0, 0, 0, 0.12); }
.ngx-datatable.theme .datatable-header .datatable-header-cell {
text-align: left;
padding: .9rem 1.2rem;
font-weight: 400;
color: rgba(0, 0, 0, 0.54);
vertical-align: bottom;
font-size: 12px;
font-weight: 500; }
.ngx-datatable.theme .datatable-header .datatable-header-cell .datatable-header-cell-wrapper {
position: relative; }
.ngx-datatable.theme .datatable-header .datatable-header-cell.longpress .draggable::after {
transition: transform 400ms ease, opacity 400ms ease;
opacity: .5;
transform: scale(1); }
.ngx-datatable.theme .datatable-header .datatable-header-cell .draggable::after {
content: " ";
position: absolute;
top: 50%;
left: 50%;
margin: -30px 0 0 -30px;
height: 60px;
width: 60px;
background: #eee;
border-radius: 100%;
opacity: 1;
filter: none;
transform: scale(0);
z-index: 9999;
pointer-events: none; }
.ngx-datatable.theme .datatable-header .datatable-header-cell.dragging .resize-handle {
border-right: none; }
.ngx-datatable.theme .datatable-header .resize-handle {
border-right: solid 1px #eee; }
.ngx-datatable.theme .datatable-body .datatable-row-detail {
background: #f5f5f5;
padding: 10px; }
.ngx-datatable.theme .datatable-body .datatable-group-header {
background: #f5f5f5;
border-bottom: solid 1px #D9D8D9;
border-top: solid 1px #D9D8D9; }
.ngx-datatable.theme .datatable-body .datatable-body-row .datatable-body-cell {
text-align: left;
padding: .9rem 1.2rem;
vertical-align: top;
border-top: 0;
color: rgba(0, 0, 0, 0.87);
transition: width 0.3s ease;
font-size: 14px;
font-weight: 400; }
.ngx-datatable.theme .datatable-body .datatable-body-row .datatable-body-group-cell {
text-align: left;
padding: .9rem 1.2rem;
vertical-align: top;
border-top: 0;
color: rgba(0, 0, 0, 0.87);
transition: width 0.3s ease;
font-size: 14px;
font-weight: 400; }
.ngx-datatable.theme .datatable-body .progress-linear {
display: block;
position: relative;
width: 100%;
height: 5px;
padding: 0;
margin: 0;
position: absolute; }
.ngx-datatable.theme .datatable-body .progress-linear .container {
display: block;
position: relative;
overflow: hidden;
width: 100%;
height: 5px;
-webkit-transform: translate(0, 0) scale(1, 1);
transform: translate(0, 0) scale(1, 1);
background-color: #aad1f9; }
.ngx-datatable.theme .datatable-body .progress-linear .container .bar {
transition: all .2s linear;
-webkit-animation: query 0.8s infinite cubic-bezier(0.39, 0.575, 0.565, 1);
animation: query 0.8s infinite cubic-bezier(0.39, 0.575, 0.565, 1);
transition: -webkit-transform .2s linear;
transition: transform .2s linear;
background-color: #106cc8;
position: absolute;
left: 0;
top: 0;
bottom: 0;
width: 100%;
height: 5px; }
.ngx-datatable.theme .datatable-footer {
border-top: 1px solid rgba(0, 0, 0, 0.12);
font-size: 12px;
font-weight: 400;
color: rgba(0, 0, 0, 0.54); }
.ngx-datatable.theme .datatable-footer .page-count {
line-height: 50px;
height: 50px;
padding: 0 1.2rem; }
.ngx-datatable.theme .datatable-footer .datatable-pager {
margin: 0 10px; }
.ngx-datatable.theme .datatable-footer .datatable-pager li {
vertical-align: middle; }
.ngx-datatable.theme .datatable-footer .datatable-pager li.disabled a {
color: rgba(0, 0, 0, 0.26) !important;
background-color: transparent !important; }
.ngx-datatable.theme .datatable-footer .datatable-pager li.active a {
background-color: rgba(158, 158, 158, 0.2);
font-weight: bold; }
.ngx-datatable.theme .datatable-footer .datatable-pager a {
height: 22px;
min-width: 24px;
line-height: 22px;
padding: 0 6px;
border-radius: 3px;
margin: 6px 3px;
text-align: center;
vertical-align: top;
color: rgba(0, 0, 0, 0.54);
text-decoration: none;
vertical-align: bottom; }
.ngx-datatable.theme .datatable-footer .datatable-pager a:hover {
color: rgba(0, 0, 0, 0.75);
background-color: rgba(158, 158, 158, 0.2); }
.ngx-datatable.theme .datatable-footer .datatable-pager .datatable-icon-left,
.ngx-datatable.theme .datatable-footer .datatable-pager .datatable-icon-skip,
.ngx-datatable.theme .datatable-footer .datatable-pager .datatable-icon-right,
.ngx-datatable.theme .datatable-footer .datatable-pager .datatable-icon-prev {
font-size: 20px;
line-height: 20px;
padding: 0 3px; }
.ngx-datatable.theme .datatable-summary-row .datatable-body-row {
background-color: #ddd; }
.ngx-datatable.theme .datatable-summary-row .datatable-body-row:hover {
background-color: #ddd; }
.ngx-datatable.theme .datatable-summary-row .datatable-body-row .datatable-body-cell {
font-weight: bold; }
/**
* Checkboxes
**/
.datatable-checkbox {
position: relative;
margin: 0;
cursor: pointer;
vertical-align: middle;
display: inline-block;
box-sizing: border-box;
padding: 0; }
.datatable-checkbox input[type='checkbox'] {
position: relative;
margin: 0 1rem 0 0;
cursor: pointer;
outline: none; }
.datatable-checkbox input[type='checkbox']:before {
-webkit-transition: all 0.3s ease-in-out;
-moz-transition: all 0.3s ease-in-out;
transition: all 0.3s ease-in-out;
content: "";
position: absolute;
left: 0;
z-index: 1;
width: 1rem;
height: 1rem;
border: 2px solid #f2f2f2; }
.datatable-checkbox input[type='checkbox']:checked:before {
-webkit-transform: rotate(-45deg);
-moz-transform: rotate(-45deg);
-ms-transform: rotate(-45deg);
transform: rotate(-45deg);
height: .5rem;
border-color: #009688;
border-top-style: none;
border-right-style: none; }
.datatable-checkbox input[type='checkbox']:after {
content: "";
position: absolute;
top: 0;
left: 0;
width: 1rem;
height: 1rem;
background: #fff;
cursor: pointer; }
/**
* Progress bar animations
*/
@keyframes query {
0% {
opacity: 1;
transform: translateX(35%) scale(0.3, 1); }
100% {
opacity: 0;
transform: translateX(-50%) scale(0, 1); } }
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
/* IE6-8 compat */
src: url("roboto-70dd177f96584df1740ce193446c80d294ffc1ad.eot");
src: local("Roboto"),
local("Roboto-Regular"),
url("data:application/x-font-woff2;base64,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") format("woff2"),
url("data:application/x-font-woff2;base64,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") format("woff2"),
url("data:application/x-font-woff2;base64,d09GMgABAAAAAAMcAA4AAAAABdQAAALIAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGiYbcBw2BmAAWBEMCoIYgXsLEAABNgIkAxwEIAWCdAcgG7QEAB4HuUnzSsxYfoQjHr636//XPj09rr4PUEToO4IRQRHJlBgf/nKvtf1oamttuvHbwyKKIA440WqDfeCcvOaBRdtIBzbRsjUOrG390v1OEaV+MDndbbsEe4CJ6bp/iJAUgC4UykIICU00BQJ1IyWo586v9UDtOea0AbX/oWQN6pBdlx0oami1BOLgfacd9AiEkoRQlXSiRg8spQAhlPu7qad8NB/EQzzGHwNAVjozLpaTX5GPgeh7bmVv2S8BEOVMoLZgRbOIVN9lvLDsf/arXJH0o7gWSpPzO/VDUyFZLyoBoE5OpdYPKOWDvstaLS755UMCNEEvgDwDEmUhqap1924DFVCghungAFCgCXJAGn4p29N0KMrV9sVxbUcft1jpD95qOygOjkx18odf1s/9+uP1ccon3zTO++oj60/7eIUfrvX6iH/8JxuOm5psrO/X8N66tb8Y9qz8zmezfVuhqbQ/dd6R/8ZR31yfxbazY1tm5aU3vX/R9MoNd95au/HSifHagW9fMqt+86131G+8aOZ7j0f2RqdH7n+zU/rt4H/e7vPQw68U6V/dO11+2Kxv58+nbuq/6sYt6dgVvVLkru2PMIR6PlTk/z1Dwv+jW/MV+fsCaWCHc37YPHxH29Tfqt2r4Nkf2w8H3ovVv/7tv/dqI6uHgZoEgsoh/zepLfq75/+LayMpAACV7Hx7AYh/yE92ZNbPPn/+/9EUqLhIFz0aAQqSNIhWoGo/KlGqYTtMNjRtZ5PCQd3srlsSNjfEgy3r5b1rYa2POfYOnk6W5hYuaB4ubk/Qivaq4htEXLYjcYymbWzQOpXmOTI1cUac3BAyh4490V6Ouedn5q42BCcDxMnZ0t4OzcPBzSso+ovx4BuT7KZ2Vj15EOGE7qGD4GA1kgXCob4TAWewJBHYfVPizKmmLCuvoSvPzsPBRQW0DiIDAAAAAA==") format("woff2"),
url("data:application/x-font-woff2;base64,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") format("woff2"),
url("data:application/x-font-woff2;base64,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") format("woff2"),
url("data:application/x-font-woff2;base64,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") format("woff2"),
url("data:application/x-font-woff2;base64,d09GMgABAAAAACsIAA4AAAAAVHAAACqxAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGmQbmWQcg3wGYACHbBEMCvAE2SYLg3IAATYCJAOHYAQgBYJ0ByAbL0azoqzvUpziv07gxlB4DbUXLomlMJ2KzM681XQRJRADNl/GTXHdO/QLHl1szuTaToSWEZLMEjzfn7xzlXyzfbWxlrGnkXNAc7tfMaIGYhSgYBQtLSlRLdGjQnLQo0toGfSGSpSiEmXRYtBmHOm0ZmTJMKO1Hohqbu+qB1rtKnYuQE6iAxZMs0o6KWkfoWjv+++olO3AP9Pz7LzqbyIwEBpQr8EBzu2bVJtA58gmjph8C7KhpijuvXb/c1pwSYSuq6zR3aY/jEh4VHt+Ts0ogjsehf3/15W2uvNXtuRV4JtY5oS36MKdzxn7pExRpaikJ2kV6c/fwYDG5nFAHtPMrmPAnQlMACsgrgi5ShdXoZLLlARFly51lxahKJvoqGaE0YqmlGWpfk+OtbSOoukdc1hrEEZCYJRRPGi7j8/+6JKgsACwMRQGfGQhlFlDhAiBiBYNESsWgoQEkSQJIkUaRK0GKP2+QCBQwAhgDARIECEQYBgBsjBrrq1pCMf2CCF6wLF9iE7ucOxAO38vOAYDiP8QSAfsRfQCPJCABAMFZAz1JkQRDLBuulrFqlgSSTfLSJkt22UtaWYWFGfZzsfy2SyZNbNXjpoPOysFezG378XCVi+WixTZolkFyi0MDa9iJc8eU7bLSEaocg26bosPGDUBAgmxHyAQqjBwGDHhwOec8y646BoBwkSIEiNOkhQZsm5Qo06TDj36DBgzZc6CFRv5ChQp1m/AoCHDRowaM+6hRyZMmzFrzrwX1m14bdOWbTt27dn32RdfffMdQjyew5DESQqBDC4vcEFwBDcBbMGFEFz4wtjVwQ8Qx0k5VqjEDlWCGjRgAKMrNo63zGKbebxnJUFaEBcGlxKgzBzI2CCGMIwRjJovW/EKS1jGClbNtXasYwOvsYlt7GAXe9g3D9r2AR/xyfwc730pIyxi8PBAa6CYYhEd5bDEY4FkbJKKXTKx7AUCTARKsOdj+omdhoeJ54yji0WM8xz0Co/zokMLKdIlRSUMZpzksWfLG+xwAFjBhB3BYsOib+BcjX0ShAUs4hmer/UwHDaMLmIlgUq8pwqoQQNGZCBIM3E+NgWKIhQHa0GwDmzgNTbNr9h8w/e1MlKJXapQgwaMkIY1rGMDr7F5w2jqWJkSYoEdjgGCbWAHu9jD/lqx2CIOAYUoQRk5il0LWMAinuH5Whlp4qYD3Ss2iCgmkcECo20n2AF2sYf9O452JoaZxgGLWIXGHG/Jxxd2foyiHvthvA0RnSmzYIgN+iawxBSFgXoiNo7nTA1RV+kZd4XH02c+chVIMSgpBpTGHERBUCDUMUNYYIRqujCgPdfndMIRVfM4w+N1m7assbaNnXzSmxYOvbbb2qZorAbiryC+MMFaJzvodlVyhAwST78PRIOh9Me6/AAi2PgeU40bBQqxd9miA0C83b8mYO79x+Z9f1+p4au6T/G+/Zjt/efmvf8k52PWxxOjS+TWhP2+7ea8b1tvqzfk5Pv2ubwYyOP+Xvec79qLqupptwrsCDHWRh8wy8Vb2ONKEDxJVEKUtll2aV9ZW+R6N8u5bJHayDjHHViDPygfiQ0cvMuxZEDs9PbC3cMM4o3T4p2S2IHNtn5ERsUszr5/baRh93IsIZb6quN/joAxhxTxrPDyXUVgX7GC65LRWz64jxHi+x1vV0P053wexzmFNXH3gh20wT1a+Bqhl4tRF/SGpyQ2iZSg1OEnWerZW95rodVsk0dxEb9vRuw+vDc9apPva2KeoHi2zbr2++Yr0oV6GsQr1ThhLM444RoHwzmCjaMQHgganwswLhNBT5wsAmUqjlITfoJmy5P0GDrFmPMyb3mGJWtnJbc8J1+J88ru6lX9Nl2zZZ+Rz76zgCJmATvMDrPjOG6Bo/Dzo85xduc54gLHusoZXOOMBDgXYY4Q4ZzEOTMJzkCSHyPFj5DmbGQ4E1nOSpnj3OR0VMJDDjbDAxPrwzAARzMM6ZxtxgF6C5zAitOz5iySBV36Fx1WCHE8DYwOKwE/rowf198SMWAUytgdYzduAta0eYgFzzF4IS2ZvLQKZ63lIes24W21x9i2D50kcnpf04fJZOyMPeLEriEXpc04BS6LUC4pR7nKDxPmKKIc5XrIQmAzBkbPDjEOxsoYGRtRF6tBaKhASGNohonQjMARJpyJWYglMAkew0fMYsFRUjlKWntErjxclDJ2xsnYGWfE6QEEFzCcQJHJUIyeMYJuwiaERoa2MPzAJ1iGl+y/dLZciX9dLyY6WThcAd1q2ytzg/ka+oa85tr68n2lN9LR7Ke5sbwx31xHK9pSXyPjqDM/wAxqYsEkNOxB9TsBUOdMt+fB3p5w+b/lWQKEDnR1tgPpS6Zw09oHejt4gPHBAZ5EsAQSOgowlAMlas1t8MDuCSAzN4HNWaqISChm2yck+INATlOyYFqEXAbUBBb1iWmspRaKV5Lc6AnWwHXVCV3MvaqbYem9OOACtA4nQNyKQYO6oLIM7tClIsHIXZPG4K4WzVpRtGnXoTNvLXHs6e4Wyo+/Hr2oaPrcg4LgdBIolfQyYEG7rMIgzVqbUV52y2ut1dBjwDy0Deid52ydTXRUQA7E3xf+gb37RQFuyNWAunyj4MYNDV7EDAfd2rc3BpBugUmpwLrkYOGBkSJVaNai35gpbx34jwgmg3wvY/llXupQ3EO5h3NP4D7GfYqbl5ufW5hbkluJ25+7mYeXl/Dv////+w8wErcKlVrcNWDctHc+JMGkjzd8PPcR7hPjF+KWuGGMb206GUPYYxDE/4KfN2Se5JX6+/D/rv87PyKvJfUPO2bttkhhgg2v3WLl6ur31eNWspEmdyHgKVgeWBMHb2E6/64+ZbR+U7+pP/wYsRYseua5F+LEe+mVJctWrCJJ+K19pxMlOfDBR598luwLJkC2Dja6CJIceYGCDkehqtfgflyLO7CHeicewF14EIfgIfl4TT4BOBZPyhcb5UuAB/GyfEMCb+ItHIe38T5exwf4ECfgI3yOd+QXgJPwJX7ER+pPOBk/4w98jT/xF07B3/J/RTkAnKaG8puRFtOcrqfNlS00Zxj5PkIt5CdAc5aR39GcbeT3NOcYXdaca3RDNecZ3XDNBXo3XpmguVDvpijTNBfr3QxlFs1lRje75kqjm1tzld4triyh+V3vllOW11xtdGtqrjW6IzXXGd0dmuuN2WbX3GDMPk5zozEIzW1G/M27fXmdjYeK/ylt4q9C+okQbeRH2sQ19PKTOAW6NpFPWx+BhYY0ompAhWhDlvrNBBLdVAdU1GZFgPIv3XotlM2GAFXDHoGyUMXUVpJROQCk9ZKhGxGXvBzhgqfcgDS2WuCryWZVDdI6V4RLLd+hTNfH/FAAd90W33ALHNi68TiNIYig5UOxnzktRZZOAK345+0vG+9MTI6GsmHKOJTnnvxoE5oYS0Mj4CCp+9J5m691DHZx7MdlpaXxmI/IrWSF1RJ8Pm9zAfwX8zZzK8OsOcPUsHhgopLksZL6syVz8OejbR8QmTcuxdJO1lg0YeMVE0S4esMciydeWAFYUMhDsZ0aTVUmVjEKXJAol+3dfroY7WI6nFDJefXVfLj3+lMSGvPqefZa2GJCNQ57N056MFCWlqLrl4rMjLBiiwxTBHIrqQZw+O+scKCBcNVdY4fcsFTMDQI4oJowbskgPmbXUlHxYXvjgXDwdlkxEo8zoe2LtJDuSG/O+42EmEwLVDerTd561XCH0kU75+7Og7z0y5Wf2riVRO/tTKOepZMLJ0fazH2MlZ0YO9VjWbOrI07W45UFPUqMKAg96oSoOrxgHi5ykN0NrY9CKK4/JmHZE6pthPvOjaadnvPas/9abUSDFbzEd96GqU0loKo9xucbkXAk9oXvluOzwkHjL1K8o4aEgTzqDFE4V8FLy8sRDJOnFJ1fqCbD0w7XQXV4S4Ba0DILDYj74/pivdAGejOSt9JteLv06Q3Eyt4N88FwFEQ5iJaxHySKndtI/615sNetEPKc1xq2ONrV6QUoUeAY+kYWuooF5DiZb9OWgOY5zw26nSSBVm6F6mSmaOd+WzFebCm8gtMhrP+PdKv/esV349/H+apOxqf+Pzf1cd7SXLx3/Ovbax8mJFzQTbXEovw5jXZ9NWfsV2uKpisJpf2ng6GDlbYr7WOaEdUC4BSTdDzA+jgGJ//oss+NI1ZmZOhHcJvcDkMvciSVufbfqqEG90fVMaaTqpYEbbEPOyFGQoFCFftRwIotBe4TnmKGFDPtyVRkfL2g9a/YubBwpCJYzqk89/x0obLv2uwBixODju0V9TGYfWtMR27TZ+aPmhrcPzmrmAvKiV7Va62yeeg2CxNqV6B3gG6+hNl420/Vnsp0L947hcYOYUF0M3indNtOn6kH0+Mu06b2Lgm3RUqexFa4uKamnNHfXL6kvL1Du9uU7nK2v7Lcp6Dk9dvhDmTP4iBUMISi/DGmqCJEluqEUt6hglkdaItv/ywF7uSW+Siqohx7LkJgZulg5sRlofZ1aX6n3vy0Konw0oCHLe8oHBwEFwBXhsuVcxMDLqi/lC1Fudwpgwv/Kn8qiOHku0kbt9c16AhnxD1CnkoTNvUtnTMYqHuQlgMFYyMb4TdYsYTMy8Mdn4J7uQ7dJWFFAx5NlOr+XlVv4Y8agkGU4kJMAql91054Y4eYNjWelw15OllF11adHro0kOlsKj9YdqjUAzifeHHXFa4X4ZPu1reE7z0YhezKNCWCgtwy6HTNLKWm/4vaNRjlxhU3glWJx0C+rtwaWttjQMgdIW1qwL5Dh9zjPq1zS8gVvShFLh2zqtso0SZypUfFywbPNmxtyXPrTqAM8Xa4MiPEqsBmivNxu4oZuDCdwHHcfMhpe1jldVe6n+wUY3Al1JOZISR32SG0I9XTs083jMshSqNAg+QxylnlyoZY+SrYiVUfYBq7EOk7kH9ii4aQR6QUFxS4OzVpY1GqsrEjaXGoF0sL5dLhtFlDqAjbWbSzghA2qADpmnd5ocfdHgUsLkzXDJnGrMD1mQx4s7uhFgSZ6cVUqv1KvNZfmwRf2/q1S8fe4HCmwMSVXnT672F7ipX9R1F7/sr/P6yPIXJNzL5azNkEk0gZXfbWrsqLdAfhzRZ3MLcva8hZF/9Xwi+vetRTWwgN1dWsgL66PTZLhrfX2SRDjJILR7TF4XwQh9s5RZNp2RAna+TnAiIOt6W5Wgk3bf6m7GH6QGK+DRJ/itwMzRAu5pFEAdUNyVNUsbxPyKvHUEKjfhWvxqYUaFznu62/14l01p4L+qGWArcE0joajrWGqL8st42GyVp05xYiGJ6LSrU0nmzZzUm8sam3NtYMCiqFwvmR3hWeuZO7KBtelS6qlE9Xj4x4B5czHUOPZMFX5WRFAwooNLxjz9fzL05AuR4+5aw4SO0gN1Ah4ljZBHp+w3pD6sMhz6EsmsS2Yx3PwKUX+TibC9YMprOYP/Ezqsc12iLSV72b7tZpGfPcFLOj8/jxnovpr9vyhSpt/6LFj2mb6FO8zclttsw8MZ3KC2eTXw6GfpQ3eZDUOea8x+uCIl6o6sRQ/0GXAjKacMzzyOpWFSs3u4K+6/A4u1XU794rPExtFvGiYvlCdp9ToIUk1L/uEtdIqO9TuklbOGHZhA2abFkjsYT25obROmVT5nTUXNRC6JiysCQ08ijgBRR92tpzFgmV5/2VjTr5EEaes++6QpAk5odzUtBGuPdKy0WkXti9kwas4GnzTHhdlpMiL4vqXiqR7qv5+y/lY9HQAsQEvHgMStoX0fROqcmXurYNpzBMQ7M1ZsHp/jCZ/ffsGgMBYWhS3uDOc+OxglB3cnbjviDR+M8N1rZvxTZpes6qS2bblIYYZa638OBTvinakght6Zqj+r3qo/mqPieZZ721P6fjM9iwaZ5D3jQbgh1stExeS1jbvpxujPMjgKWMoJ0sAUvHHqMceMAY9LoSjVglIlZoMC+qg/lDQ0y5Blc8PMLNQz3cgN0o+KSTN+ylMieU88KfQrxOIfnq8g6S6JXsUCkn9crJouCVjB2epLxb2GE96feaqRmlvPj2KsWDaHSQZVREgdC83NB0Zc2DmVqOV7lLdVy0nae9afF3iEERoV634oIF7BsDdUvdGiaedhP6c/qpbLNvx6gpmbmk2NwIwOUUxNY2xMbXNCaqxNXWRsc01KYk4bRNHNVVjO2M1LSNnHKMnPTPdFyLra3H1dWlqJgQI6ljdX4AqRrZG6nrGDuoqZjaG/745CJ/2Z/oIg+OJFf/1hp/2wB5skrtcF993vDdeFPTHC89N23FGMXo8rr/Zd3UjxVbopr8mJLzArK+qJ4d4m1fT1cbGhNYkIY688Y2gBygr3hN0FhW0cFUU9/GC1gXMjm9o2ElF+K0N4LLDwyilPlCMr1pj/EnwDAm9bhhg78Nn0+cWnDLjgGIKa36F3wwi1Xl9ykMoH1ArnLPmriUnLTT4feJVd03CiwGzupnV8yu5F3xxpsU0lue97ySL2Q+yhJmRT3dcSTcHC68Zs5rzXtCe7L/D7qBBvE8LipWMejkuq5MJ/tHwHTqff57INsKkImtAldbiGlACS/nx10pA7kqT+Vlqd2tVRG00Hf55et7O8uXURK9TDuxi+T06AVk+fxu4lpKUtwc6jW8oM34J9azj50EYVr892vekYZlRsSkTL/kgpJU6iPU9xePd+bbnrGfj699BUcchFJikNx4IvzP0xN9qS1/Nocnt14M2YS2uV4K4otpvT3yvy+C5W6aX25SJCktJfZ2cUIWkgLidlsT+RP6NP18z/PDH0fPfR4fnTCBpy/UFrabtC6luskmjm/h1tY/oV4Ofl5gu9fKFk6ODIzOai3OKqPEhSiJ0IHI17ZS3mfo/98na8TY8QcbjPPrX5gnZ9Byf1WyjOv1MTNkm3LfU0ZKnZWvQiLSe3LzMnpBwUiVr0t1iC/3CGfBc5AdEfEkNthd8xWI6wu6/291evbP2r3AqPu+ArbXvBs8eneeDQ7sPqP3swktKvyVl/8jKy02Jjud3fGYJ4nk7x2XuBKXuJKUAsIbURJKFQa2kbQwp7XELK+tx2GJz38oHBZr0CHpY86WnNtEf33L/tOqxPeMgXp36euQ0GxaYW76ANDF+v4ZEeYJyxLmCR0BmeqrCpUKcgoVCiDYnpyDeiBqF5olahc2AI6FSKBgkqZBDMnA2tPVM9D1Vpi7BRWp3Bjrvj870dZa2eDhrqpbMCA9i3/yeFR+Y/z47HBXn0idqGGyvnp65jvCE5aaYNSDbFe92xd1ZIUvEN5m+6asYjsIcTfztR9dH+sIYvjK+J3swT8wY955qf0scfGJoOsv57X2WsZjjITl7rD9g58Oqy135NZ9mNN0802lvZzOWOOvfAuXCyjYA+mZcPvEsDHeUUo97wJltP3owfd6aAAsZWlvf3jgll+Jw8UA7sTeqJG/q+/F65lkSEXJoXSnbhTyRuZFeASneJBPgFb05LG3p37to8R8xVIfZwjT17S+P4zi2hw80lJbnNc7zfo7bW/0cHtFY8bxjh4up/jBmboyUXhoNamrEv+dYYRZlBAwsfKN47/Rj/eEBQRkUZVBmOXSUsBSssvm5oNAeijWIXYAsBRS2dgnB9Aa6FdzxbtQ2jlq84SRidtqQq5cm4fen1oYEOXmHRxjAQj6usrd71F5TVVFr4QNdKNgsHKlUk/7AeIKcRCCvniIINBFGaSb+bUz8+Lj8sOBiMSUmKCsXCDBsZq23t0bb3CaNPVeOoa/+spbcC1pL/ULFhmEY4coJ0dqrsKf2ZVfZ3c4uVmcfXK+gGB7vavT68wr8/b2gyov6pUvzs79oJvVsEiWpaujNNPXZ4kjT11nM+UZGptbGerJcgsPEPQUZ1/3NCfqq/vv2VNU2mMW1B9wkZDE/Ng4esDy+dE8fvO7cYlZUXVGUkx1cTrKEXQJDXPxAsFG6McxwUKfVdh19e9AYWgoSyz0A/KE60EXlH5Nn/YX0x9oGmvZ90Nm4xt+dTEx61GMoJEr02Tm1jlyfXZ4QgU5H/jBKPHbzbXJgmbC2lLetl/U45DBuLq8wvSycG+zvFA3pyeh9tXebRzz7/LQxNTx24NxQwXVBZVhi7n+oBZAmAcsoR+whLmyW6B+h7ICTwH7ipXn4DiCrK89eFnWcreyurml7BUk/zuGaZvlGaU08nRRZmBj4nj/+WYC+kcVe/aPc62nhlnObA5yHaK0Ekb4uLy4vDj8+Vq5sJQBOK8YY3ll4/HM4vKm03Xn66+fLT+ZWQfH+bCXL087ZJ4eOM1P6BKIl8iXns0Q3IxhL/ueBtxd7/sBl9hfEAJ0vSGAiqdQ+HFXKAB5UaF+FFowmPkTaxCO1fTdX2++uHj7wmITSETl5+TnwMmal+UI3yqc/0+vFxXfUfGkM6UBaFudRnZ+RF+HeAcVmh4xb8QksG+Ohq7+lMtnwvYl1aTYjFdlJdNw3MTPDhRQ7D9eXx546p2BD28EHFBlvJOT1y6gezH3M58m9eg0zBs2dMZnPwWZGIfsIDqzVoxlQN2Ig9cyhh9Ol/l9fZ6Q0/3hBV1LK51LOsk1rWhi4Exf4SOw5vu5c7X/gVe0CBVw0Ij380oYu7cr/KMX15s/RaLoln7UL2hOzJ8BTY4lDu5PvJWhf5bSo+e2DqG1ltHl7SPJ9gk6QvI+JgnTBL8Jn/wq9qxTLHSpCUXwrqmJ3OR9l3q/UW6NPve9qLmdiz3xHfldE9jw/d26ODjmlYIPauCe/fFxNmDVQdLYxiswqzkhLz/Zyuv2wINtQeqnntzphFa9sn3DosaE/BngNOgJzRs1QcU8pj4Bfxdvb/MEGz4tNBVwQAUjqiR1/NQVT48I8zAPd+DslOwRPy4jmPNdRFZOwaCPcOqyl6hY2d4CqF/8gsNVr7rSPlDXYb1meCHgBRjl3wjAUSOJCQpMmXit1yKq1WwT6IgNXqBO+LsSI5wTQhmcJ2mju++6FYq4qJLA0SmJTQgrfmjXf7CSYM5fHv53JYm8zCb4j7ks+NdaStYSm+AfKr6z9kVq2p2l8fb6pdSkuhcgv8H+ff3K4KhPOD0VsC8b8EE+KY+GN/hwveie4rnEeoMcrH52U3zJLFjz/d86PzrgFUXn0QjYl1SMdxBt5L3An146Wslc/B3jTIJJehWpdB4u+OXkCXbLFQFVshMVbp5RJ3YfBHhOa/joH5GqMdD2041f62nt3byfQ9OM8rR38jVRUXRV5JRpMtIPNsl8d5caM27hU2NLxVgmexBdIw3hSIAcboI8US4vKifPHZanyqEcHpGbXD5KHsWBUJS7e+RMS+dDGBmg9n17OK9cykGVpMCHX2zDN+4fUZJMOxIneR+UKv4rtBSVo1Myj81PhA0tksdRI9nLbHCRdfhiLny7e5D83I7Lg3fxZ87PnGcevHZci7DHwjp8aey4yLoj8xKvElMeh7WLBo/jec8jZ69OgEReSL5FIp/BUc1CkVgI8qQItm/eG/88nzn/aRrpvrvWLsRHnFY4NvG61rTW7M0kivBUHhSZcwH3IBcIvybkcPRL7zoNOvW2Hh+bVuAjUgTb1qB39mA+c/7zxL3O9buCoP2Zvoz2PEn1tkh9ttqZi9oGbtYVSEXP0xTNlButFT8HNa39bKChqR7mOYeYcjXD76OhFuOYHUxn2oqNGH1IPrpF3W7nGT++dGb+0QkK9wZ1NZerfw6bOxGVolfbgCfdqyIZ82UowZdqBQvGIDZ4uqU7pRV49PiXvYcPlufa+t0jw7xdowsj8OgbpaD0wacsdmaqLDo+IZqUnOpcPDHpXZWVF52QlVsaNDxSFpyTH5uYV+hZ9XjEqSydHJsgiQoLI84Nh2wMh/rMhtE8I8E+vsNBC/cDeDqOCucteE1hI5TuKIUrKQwqyIbL3pGNoJNV/DlkMR+mHX5I+0YDlczW+1RDJQGVBMd69Nimz8PryuLJPk+pSExHXkniHX9bszSXaZmua/1elkXetC4TeYGbCY61DOMr79HrT6kRdUUp6RVEe+XrOiS5Uzr1Kj62ElGnGs0Oqx/TIag7Kt8U1YmTP65H0eIwcFQ2TfYAnJHFjob8un3LRQ//T0H5k1Fhc0VZ6b3Zbi/Kg9niiqbq3CwHa0MLa/ekMN9g9yRrS0sDp3+xzeVnCXfk2O+Un21uLOUh1FZWcNSUnSE2TNDM1Mei1MZoZhOjHSbq02Oj6pNdJuA60GakYRQVFB3m7F0b1OwhkhCurC0qXMHo3BSdFF+YTpK2O6prEXrJ5Bwt3UcfTGWFrUFqPYiGj6+8AWbPsfPEMVuuqaKSo76Ep7mphJuj+BHU/0U/TY+zsD4mIuy2XIggFMoYY9ky56jcrDZEdOvtEhXERF5MTUvaMRmE3nBVkCsAf3bAJafYzSWryNUtK9fFNTf33yExtZsSkmrqYtfVtT3U1eB8trFHvkdZXVl0fnRpHSfnZ8UCRWgsMvG4dNTDSVnwj7TGTQ2JUmJtNr4w0svFzc1AuzWDDGw5twzVVaQFrmzdlFAXulBqXxUanlQc7HJd2Vz+SM55sltDeGLcnQj3sivaUoo3VaWEfYsRU+AYgzVGvlw4JCIZAlW3iv3HZfK5aZJ1eKIlqTFbV3Uhmt0VIOEN3+L/Li7Q/3vLDFgKZD3/ZbKqXrtLTIeTHQXHsuzKfcg4Nx1j4WuXf9rhT8fDflGp2TPxKHt/AtDVOJT1DRUV9w3UqpfTBkXuD96pwjra+hoaWBOdtB1sfQ30bDwRW9CoA9fzkTYBPQMM9pyefkRPx3AfCypSsfa4Z2ThYUdL+V0PH3mtrAHpQMpduVw8gQE+4MdiK/LEduM6ltJT0MGxqJ2veogwaMQe/PDUEpiqqumoaAeGqmqrsmUtz9KMuu5lpfTrapti9GyL0slv7/e7GOyV7vJidvitmrSyf4k0hE9GzuGLXeoZxUQnr9p07GoFdZm7r8fwGvia3wjZl/3c5MJS+A5nv3IJHIwconv7miBBAyyFeo/3UHp5XnBYeV4CgBLVZHpym9Y50l4ecXtCWVjduo9slKBZPtHWrdd5yeJiESvpkqi7j5W+iJrNvSzjJD2z5ElDa2c305d8oL3GiU3okDNat0qr62vOL91oWV41cvcMdXFN8dTrIZA/dvb5teoL6stqtxi7zr6DLb/nuNaWB7k5wRr7NxJKg2/45KmWqh3a2/RHUjwNtFwtRdEifjmNbMnHTsfFZ4Gw8qEfdIVWZf5/npFJCa+igldJ2d7vJ6Ojq4N9rw2lpr7IVrXvj4k17xYQL9sXvZt8L0rVARfLfJgpWdUys/JBXWrtcFREwXovKMyavu19ayMRHKUWYhqqHlz9mdAa+qUO/bOWTPayuqCaHe70ZKhQrizs72pihosRr1pOuMPEk5xesSFbL+OuVdXkuhdOnd3GXgatLgoptS+poEBcV88/XQVVzCd2SDxII5okDXwyQLeNk1j1NzeFBRpFm5PZ/uZVhTdw3PzZ8EuuNAizrCJ33NeJOd2DxaNlcBOZlJgb2gZb/orgvy8T05Me+ks7yDkNE32mtv7u+E/iGqpHSPeC3NUiEmO/JjzxlnWQsR/zIS3RXfvXi+8pf5aSVL442V3xPDmhckFhetEht+pQEsuxiMRcEHDcZyjMbchpKGT6yuoDvAFRJmH+FpahAc2hIb2hIepG1xQUBQUU5e0VlASF5JVB+M2SR2i85YUOW5nmExfKBMNw7sEpVmf8bCR4Tl8SV7wCbG85XFUsI1FZib3+t2zHgT6Hy0XFMhpFzuiJAQfbMUg95qJqHonKDKQ6Otk/gtTLLirmiagCKrXGw3526UbT40ircbedBnw1xsTL29LC18OKz8TT09rKy8sUTvIhqWn8sRz8cWnA4td1Y28WT0fSkHSo8nT+p4vi/AoWJZyMQg91zNzxd+LhKA86GfzjxFksY3t4e1J7RDs99sSpz26kUxyVHrxeNZQJbN/tiKikKJB5w5OSJJKSmGR+1IecTk73OWr+ZTz7ocXDHL0YkG1PUcxXhIkE885adk0+uu/TKH2qOFzQN8jFzd16mbzcpDa4iwtjHcI4NB/OuiedIbXLWyMQmvt72pwuSgP2OTVB3UuGXoVY4ephvUJeeckZymjKokp2raG/k3HqXg3yJH2pz1Nnj+/wlNyHj5IvrqvxW5DUo2rzcjPKk5HIx4TsSxK3RWwspczlrlpoPjKfaJxQ78D0IlwsO+6XpliePlg6P58uUarKb0lLKW6C8vTqopaUtPwmpKQEN5Acj+7oGEqJQ3cCfiLufw/pXHSPcW8obQjCOgVjK8O2VnkYwTtGMHMlzupQg9wJ9aj0xJDw8gxSSG0E1rGY3j5aXkVdSVZLU12tEXhjT8WyMyJcL1U0iYGkjCD/ssK4lNo7+cLTy6+fYCIyhTUvsfIa6hvekNHSDr+pATU0S1qtZdZojDskKwQGiiVLxrqVB7OVB0eQm4Ka7a/AX6BzXkBEJF1P4qiIloTsDXUJEVENicj6dZtycH1T4Oo7n1kevq6iJOcUmJoUGVJVHp1UXIPK/ktSOWxv58XahZZaX7gpbaCtIy2lYaAor6YF499A/sDtfycMPX/pn7+PSuzwY6fiDq19/AdgboQ/APoI8f34OWewOh2HbYQEL//nX1yelOKfxytGQlyR3EA+bolXu6DElekIfMgpedF2NbuOFBYt7dlcTjWnfJNShMCNtRLMxW668zZoPi9XfeYJcGtvOeM8fwiY+UkR8IIRUCpIN1idq2DthERl/SLFFOQ+UDi4fOAuLlEpapvarnaonayL44B9wtz4kOcqJYEk1pQckPqT0z0anWF0SR7SzU8Jk5x0kzw7Z4ak2fjOLsxV8jspQHJASk5Ol9PDzQi7kqwUdckBRJPTQ66HW/hIIWvZbynsJNdP4qpw43qWnG5nZIZ3S9pGPh2XkBJYUy4lsTw5INGS0430cPNFysizxJRyNt0CyDxIO8IxetIPLntk7I9xURvLFE2yrxilCtnshqrGR4GqJg2bHBNi53cPl6UjZW6P0pn/wQiY7tKc56/JA2EMKX0rE7tJA9NsSjVg1k0Gct8GUmR7enawAmmGw8ZVM2bcZCZ2zT1VliGtpNlxZqW5bWUxZwQMpxQMQIGrrVhBb/EO0P9U3RA4Kb4uz6rkwmAlGZm13pJfHEvHDRWU4NLFCLRz20JX8DS8L//71qc6p2za8MoUvY+eKJcqmPuOg3TlyqQDuCC+zqQZYrk4faXQzWkpba+LAt7CIqgDjOOmdpMMcQc6QXk6VsuZydW3C18+nZlR3U6ANrMv9tTEu23vN7x9MgUNlPC8jWgAde2+AlTS/V8D6Vh3FwrIm0GPLayNheLOfbr8LdOG0PEKjN2Hnk4cms72xf2VuhWm8RNb5H5jBfXeoniegLPdA1it7crR/IosWA6U/narNivB5/pgPXU9MQbSPu0/fATyMtD/v4gFce/lr9lGpILyYdtlgRMwIj2AVqm+bVSifpbqgw2Ta6DxR3HAdk3nyuNvfEol5DMwF61cSeX5T0CeY9zbivsFNqzSv+OPDgHAYz/7VQBeX/q//Tr+d2GowBA/YCgUQAL9AwdMAEPXy2j/1Km5c7Wev0oqR4X078sLmkdDRSZLrHuCaiSvtsS1/uSUnDjne+LzQ/yF6ERNop2ynMyi+PJxGUUT4anAD2iEFawhiiLEQQs+T7Rj+oCU2lyo7FSro4J6FamM0+hf49bEnai/NTRRQe2GhpoqgYc71E9o67yCfEVPdSPaMKGi3bf3R4Ot5SiBjan2xHrWPfW1n24dI9gEpLbDTvSPkmkYkKiTWOsE43xaVlF1Xp4Y+mJKrpTA5BAS1ZxnjZBaBVjWWDZVhlUeJx3ckG11kZo+Sktb0T8sWPSjkj4aUqrbUxMyWCjHqWxyl4L7jpair64SyxqeHhoule8ulEe4JDBNxnLps1bEHM1XrHNFKdWWa61l0TrxwIWxph3Z9T3zYsqpp8aiZMsug25VL7d76uENNUrPf8XUm+zyAQW6Y7I5RlhNVFS2KGYu2ek3f0ShpRoPZsCttsSoJ0q3J8G7PKLUD41Po8SMxBew0tTWISm9QdqVIrJmUqmJLGqJ3PRLcb+SS1+JXRnRkFuElDFhlROk66CAK2yrqurdkJEK2coNCaR8Z/M8l/yKdB50rqhdcjOXk2/xwMM1K9Wk8gGxGsmmIeBcs9RXL6drCune/NMygCFLsXQ0CAV0IQsxWMAYktCB2r7SlSCmE3OnNyt0jKt7QQx02OdnBJlYg4aix1Z6gXk1YRwBqcQ6YlbdjJhGLOuU9U2/GtPk6U2l+xhWE8ZxlUjsIqDZSrOYRmBeCPAXbzgXQ9hHyiiQoeaEgwBD3IKGVHoAO4NyJIKJ9UgUFm6N6NZGDIzE4hc8EueEsgfKwhCNIm8+QhC5cubCHzchAgQvJjcV3pZyD05rVePFwdVA3odHWl9V+DUFTiZ2QhTYI0dX/cibPcGfZCqdBfBgl4OxSeTHVXgZxtW5wq6TsmOv11H27sqBTFf68yHp2oUFBVfjwIcqHbhwcrUExI5rkSuHDi+y9Kav0aRGkTJtBpRdsaJNILE4vXDjqAIA") format("woff2"),
url("roboto-42c8ae79841c592a26633f10ee9a26c75bcf9273.woff") format("woff"),
url("roboto-70dd177f96584df1740ce193446c80d294ffc1ad.eot") format("embedded-opentype"),
url("roboto-5ecb6ee26f6ce4d35a9c1dcb8054fd6bb3d5c961.ttf") format("truetype");
}
export const environment = {
production: true
};
// This file can be replaced during build by using the `fileReplacements` array.
// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
// The list of file replacements can be found in `angular.json`.
export const environment = {
production: false
};
/*
* For easier debugging in development mode, you can import the following file
* to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
*
* This import should be commented out in production mode because it will have a negative impact
* on performance if an error is thrown.
*/
// import 'zone.js/dist/zone-error'; // Included with Angular CLI.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Bytebot</title>
<base href="./">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico"><!-- inline spinner styles to be able to display spinner right away -->
<style type="text/css">
body, html {
height: 100%;
background-color: #2f4050;
}
.logo {
width: 200px;
height: 200px;
opacity: 0.5;
background: url(assets/images/logo_byte_menu-min.png) center center no-repeat;
}
.app-loading {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
}
.app-loading .spinner {
height: 330px;
width: 330px;
animation: rotate 2s linear infinite;
transform-origin: center center;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
}
.app-loading .spinner .path {
stroke-dasharray: 1, 200;
stroke-dashoffset: 0;
animation: dash 1.5s ease-in-out infinite;
stroke-linecap: round;
stroke: #78828B;
}
@keyframes rotate {
100% {
transform: rotate(360deg);
}
}
@keyframes dash {
0% {
stroke-dasharray: 1, 200;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 89, 200;
stroke-dashoffset: -35px;
}
100% {
stroke-dasharray: 89, 200;
stroke-dashoffset: -124px;
}
}
</style>
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<script>
if (global === undefined) {
var global = window;
}
</script>
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500&display=swap" rel="stylesheet">
</head>
<body class="mat-typography">
<byte-root>
<!-- loading layout replaced by app after startupp -->
<div class="app-loading">
<div class="logo"></div>
<svg class="spinner" viewBox="25 25 50 50">
<circle class="path" cx="50" cy="50" r="20" fill="none" stroke-width="2" stroke-miterlimit="10"/>
</svg>
</div>
</byte-root>
</body>
</html>
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
/**
* This file includes polyfills needed by Angular and is loaded before the app.
* You can add your own extra polyfills to this file.
*
* This file is divided into 2 sections:
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
* file.
*
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
*
* Learn more in https://angular.io/guide/browser-support
*/
/***************************************************************************************************
* BROWSER POLYFILLS
*/
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
// import 'classlist.js'; // Run `npm install --save classlist.js`.
/**
* Web Animations `@angular/platform-browser/animations`
* Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
* Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
*/
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
/**
* By default, zone.js will patch all possible macroTask and DomEvents
* user can disable parts of macroTask/DomEvents patch by setting following flags
* because those flags need to be set before `zone.js` being loaded, and webpack
* will put import in the top of bundle, so user need to create a separate file
* in this directory (for example: zone-flags.ts), and put the following flags
* into that file, and then add the following code before importing zone.js.
* import './zone-flags.ts';
*
* The flags allowed in zone-flags.ts are listed here.
*
* The following flags will work for all browsers.
*
* (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
* (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
* (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
*
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
* with the following flag, it will bypass `zone.js` patch for IE/Edge
*
* (window as any).__Zone_enable_cross_context_check = true;
*
*/
/***************************************************************************************************
* Zone JS is required by default for Angular itself.
*/
import 'zone.js/dist/zone'; // Included with Angular CLI.
/***************************************************************************************************
* APPLICATION IMPORTS
*/
/* You can add global styles to this file, and also import other style files */
@import "./assets/styles/style";
@import "~@angular/material/prebuilt-themes/indigo-pink.css";
// @import url('https://fonts.googleapis.com/css?family=Roboto');
@import "./assets/styles/google-robot.css";
$fontcolor: #676a6c;
html, body { height: 100%; }
body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }
.hr-line-dashed {
margin: 10px 0;
}
.wrapper-content {
padding: 5px 5px 40px;
}
.mat-menu-panel-columns {
.mat-menu-content {
padding-top: 0px !important;
padding-bottom: 0px !important;
}
min-height: 10px !important;
}
.mat-horizontal-content-container {
padding: 0px 0px 10px 0px !important;
}
.mat-horizontal-stepper-header-container {
margin: 3px 30px !important;
}
.mat-step-header .mat-step-label {
span.description {
color: $fontcolor;
font-size: 10px;
}
}
label.mat-checkbox-layout {
margin-bottom: 0px !important;
}
.mat-slide-toggle {
margin-bottom: 5px !important;
}
.table > thead > tr > th.mat-header-cell {
vertical-align: middle !important;
}
//------ dyna-form
.mail-box-content {
background-color: #ffffff;
border: 1px solid #e7eaec;
padding: 10px 10px;
}
.mat-menu-panel {
min-height: 10px !important;
.mat-menu-content:not(:empty) {
padding: 0;
button {
margin: 7px 5px;
height: 25px;
line-height: 0px !important;
}
}
}
.mail-box-header {
padding: 10px 20px 8px;
h1, h2, h3, h4, h5 {
margin: 0 0 5px;
font-weight: 500;
}
.icon {
padding: 5px 10px 0 0;
}
}
.material-icons {
font-size: 22px;
}
.mail-box-header {
.title {
margin-bottom: 1px !important;
}
.grid-title {
padding-top: 5px;
margin-bottom: 0 !important;
}
}
.fa-1_5x {
font-size: 1.5em !important;
}
$fontcolor: #676a6c;
button {
color: $fontcolor;
font-size: 10px;
.btn-label {
padding-left: 5px;
}
margin-left: 2px;
}
.legend {
display: block;
width: 100%;
padding: 0;
margin-bottom: 20px;
font-size: 21px;
line-height: inherit;
color: #333;
border: 0;
border-bottom: 1px solid #e5e5e5;
h4 {
margin: 0 0 5px;
}
}
.group-title {
font-size: 70%;
color: #676a6c;
font-weight: 500;
}
/* FIn de estilos XDF */
.mat-button-toggle-label-content {
line-height: 10px !important;
}
.mat-icon {
font-size: 16px;
}
.panel-viewer-wrapper {
border: 1px solid rgba(0, 0, 0, 0.03);
box-shadow: 0 2px 1px -1px rgba(0, 0, 0, 0.2), 0 1px 1px 0 rgba(0, 0, 0, 0.14), 0 1px 3px 0 rgba(0, 0, 0, 0.12);
margin: 4px 0 10px;
}
.panel-viewer-title {
padding: 12px 0px 12px 20px;
font-size: 13px;
color: rgba(0, 0, 0, 0.54);
background: rgba(0, 0, 0, 0.03);
.mat-icon-button {
line-height: 0px !important;
}
}
.panel-viewer-body {
padding: 10px 30px 10px 30px;
background-color: #ffffff;
}
.amd-form-control {
width: 100%;
}
.cdk-global-scrollblock {
position: fixed;
overflow-y: inherit;
/*width: inherit;*/
width: -moz-available; /* WebKit-based browsers will ignore this. */
width: -webkit-fill-available; /* Mozilla-based browsers will ignore this. */
width: stretch;
}
// Z-index para la barra de menu
.navbar-static-side {
z-index: 999;
position: absolute;
}
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
import 'zone.js/dist/zone-testing';
import { getTestBed } from '@angular/core/testing';
import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting
} from '@angular/platform-browser-dynamic/testing';
declare const require: any;
// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
// Then we find all the tests.
const context = require.context('./', true, /\.spec\.ts$/);
// And load the modules.
context.keys().map(context);
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "../../out-tsc/app",
"types": []
},
"files": [
"src/main.ts",
"src/polyfills.ts"
],
"include": [
"src/**/*.ts"
],
"exclude": [
"src/test.ts",
"src/**/*.spec.ts"
]
}
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "../../out-tsc/spec",
"types": [
"jasmine",
"node"
]
},
"files": [
"src/test.ts",
"src/polyfills.ts"
],
"include": [
"src/**/*.spec.ts",
"src/**/*.d.ts"
]
}
{
"extends": "../../tslint.json",
"rules": {
"directive-selector": [
true,
"attribute",
"byte",
"camelCase"
],
"component-selector": [
true,
"element",
"byte",
"kebab-case"
]
}
}
\ No newline at end of file
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"sourceMap": true,
"declaration": false,
"downlevelIteration": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"resolveJsonModule": true,
"module": "esnext",
"moduleResolution": "node",
"importHelpers": true,
"target": "es5",
"typeRoots": [
"node_modules/@types"
],
"lib": [
"es2018",
"dom"
]
},
"angularCompilerOptions": {
"fullTemplateTypeCheck": true,
"strictInjectionParameters": true
}
}
{
"extends": "tslint:recommended",
"rulesDirectory": [
"codelyzer"
],
"rules": {
"no-string-literal": false,
"array-type": false,
"arrow-parens": false,
"deprecation": {
"severity": "warning"
},
"import-blacklist": [
true,
"rxjs/Rx"
],
"interface-name": false,
"max-classes-per-file": false,
"max-line-length": [
false,
240
],
"member-access": false,
"member-ordering": [
true,
{
"order": [
"static-field",
"instance-field",
"static-method",
"instance-method"
]
}
],
"no-consecutive-blank-lines": false,
"no-console": [
true,
"debug",
"info",
"time",
"timeEnd",
"trace"
],
"no-empty": false,
"no-inferrable-types": [
true,
"ignore-params"
],
"no-non-null-assertion": true,
"no-redundant-jsdoc": true,
"no-switch-case-fall-through": true,
"no-var-requires": false,
"object-literal-key-quotes": [
true,
"as-needed"
],
"object-literal-sort-keys": false,
"ordered-imports": false,
"quotemark": [
true,
"single"
],
"trailing-comma": false,
"component-class-suffix": true,
"contextual-lifecycle": true,
"directive-class-suffix": true,
"no-conflicting-lifecycle": true,
"no-host-metadata-property": true,
"no-input-rename": true,
"no-inputs-metadata-property": true,
"no-output-native": true,
"no-output-on-prefix": true,
"no-output-rename": true,
"no-outputs-metadata-property": true,
"template-banana-in-box": true,
"template-no-negated-async": true,
"use-lifecycle-interface": true,
"use-pipe-transform-interface": true
}
}
/*
*
* INSPINIA - Responsive Admin Theme
* version 2.8
*
*/
$(document).ready(function () {
// Fast fix bor position issue with Propper.js
// Will be fixed in Bootstrap 4.1 - https://github.com/twbs/bootstrap/pull/24092
Popper.Defaults.modifiers.computeStyle.gpuAcceleration = false;
// Add body-small class if window less than 768px
if ($(window).width() < 769) {
$('body').addClass('body-small')
} else {
$('body').removeClass('body-small')
}
// Collapse ibox function
$('.collapse-link').on('click', function (e) {
e.preventDefault();
var ibox = $(this).closest('div.ibox');
var button = $(this).find('i');
var content = ibox.children('.ibox-content');
content.slideToggle(200);
button.toggleClass('fa-chevron-up').toggleClass('fa-chevron-down');
ibox.toggleClass('').toggleClass('border-bottom');
setTimeout(function () {
ibox.resize();
ibox.find('[id^=map-]').resize();
}, 50);
});
// Close ibox function
$('.close-link').on('click', function (e) {
e.preventDefault();
var content = $(this).closest('div.ibox');
content.remove();
});
// Fullscreen ibox function
$('.fullscreen-link').on('click', function (e) {
e.preventDefault();
var ibox = $(this).closest('div.ibox');
var button = $(this).find('i');
$('body').toggleClass('fullscreen-ibox-mode');
button.toggleClass('fa-expand').toggleClass('fa-compress');
ibox.toggleClass('fullscreen');
setTimeout(function () {
$(window).trigger('resize');
}, 100);
});
// Run menu of canvas
$('body.canvas-menu .sidebar-collapse').slimScroll({
height: '100%',
railOpacity: 0.9
});
// Open close right sidebar
$('.right-sidebar-toggle').on('click', function (e) {
e.preventDefault();
$('#right-sidebar').toggleClass('sidebar-open');
});
// Initialize slimscroll for right sidebar
$('.sidebar-container').slimScroll({
height: '100%',
railOpacity: 0.4,
wheelStep: 10
});
// Open close small chat
$('.open-small-chat').on('click', function (e) {
e.preventDefault();
$(this).children().toggleClass('fa-comments').toggleClass('fa-times');
$('.small-chat-box').toggleClass('active');
});
// Initialize slimscroll for small chat
$('.small-chat-box .content').slimScroll({
height: '234px',
railOpacity: 0.4
});
// Small todo handler
$('.check-link').on('click', function () {
var button = $(this).find('i');
var label = $(this).next('span');
button.toggleClass('fa-check-square').toggleClass('fa-square-o');
label.toggleClass('todo-completed');
return false;
});
// Append config box / Only for demo purpose
// Uncomment on server mode to enable XHR calls
//$.get("skin-config.html", function (data) {
// if (!$('body').hasClass('no-skin-config'))
// $('body').append(data);
//});
// Tooltips demo
$('.tooltip-demo').tooltip({
selector: "[data-toggle=tooltip]",
container: "body"
});
// Move right sidebar top after scroll
$(window).scroll(function () {
if ($(window).scrollTop() > 0 && !$('body').hasClass('fixed-nav')) {
$('#right-sidebar').addClass('sidebar-top');
} else {
$('#right-sidebar').removeClass('sidebar-top');
}
});
$("[data-toggle=popover]")
.popover();
// Add slimscroll to element
$('.full-height-scroll').slimscroll({
height: '100%'
})
});
// Fixed Sidebar
$(window).bind("load", function () {
if ($("body").hasClass('fixed-sidebar')) {
$('.sidebar-collapse').slimScroll({
height: '100%',
railOpacity: 0.9
});
}
});
function fix_height() {
var heightWithoutNavbar = $("body > #wrapper").height() - 62;
$(".sidebar-panel").css("min-height", heightWithoutNavbar + "px");
var navbarheight = $('nav.navbar-default').height();
var wrapperHeight = $('#page-wrapper').height();
if (navbarheight > wrapperHeight) {
$('#page-wrapper').css("min-height", navbarheight + "px");
}
if (navbarheight < wrapperHeight) {
$('#page-wrapper').css("min-height", $(window).height() + "px");
}
if ($('body').hasClass('fixed-nav')) {
if (navbarheight > wrapperHeight) {
$('#page-wrapper').css("min-height", navbarheight + "px");
} else {
$('#page-wrapper').css("min-height", $(window).height() - 60 + "px");
}
}
}
$(window).bind("load resize scroll", function () {
// Full height of sidebar
setTimeout(function () {
if (!$("body").hasClass('body-small')) {
fix_height();
}
})
});
// Minimalize menu when screen is less than 768px
$(window).bind("resize", function () {
if ($(this).width() < 769) {
$('body').addClass('body-small')
} else {
$('body').removeClass('body-small')
}
});
// Local Storage functions
// Set proper body class and plugins based on user configuration
$(document).ready(function () {
if (localStorageSupport()) {
var collapse = localStorage.getItem("collapse_menu");
var fixedsidebar = localStorage.getItem("fixedsidebar");
var fixednavbar = localStorage.getItem("fixednavbar");
var boxedlayout = localStorage.getItem("boxedlayout");
var fixedfooter = localStorage.getItem("fixedfooter");
var body = $('body');
if (fixedsidebar == 'on') {
body.addClass('fixed-sidebar');
$('.sidebar-collapse').slimScroll({
height: '100%',
railOpacity: 0.9
});
}
if (collapse == 'on') {
if (body.hasClass('fixed-sidebar')) {
if (!body.hasClass('body-small')) {
body.addClass('mini-navbar');
}
} else {
if (!body.hasClass('body-small')) {
body.addClass('mini-navbar');
}
}
}
if (fixednavbar == 'on') {
$(".navbar-static-top").removeClass('navbar-static-top').addClass('navbar-fixed-top');
body.addClass('fixed-nav');
}
if (boxedlayout == 'on') {
body.addClass('boxed-layout');
}
if (fixedfooter == 'on') {
$(".footer").addClass('fixed');
}
}
});
// check if browser support HTML5 local storage
function localStorageSupport() {
return (('localStorage' in window) && window['localStorage'] !== null)
}
// For demo purpose - animation css script
function animationHover(element, animation) {
element = $(element);
element.hover(
function () {
element.addClass('animated ' + animation);
},
function () {
//wait for animation to finish before removing classes
window.setTimeout(function () {
element.removeClass('animated ' + animation);
}, 2000);
});
}
// Dragable panels
function WinMove() {
var element = "[class*=col]";
var handle = ".ibox-title";
var connect = "[class*=col]";
$(element).sortable(
{
handle: handle,
connectWith: connect,
tolerance: 'pointer',
forcePlaceholderSize: true,
opacity: 0.8
})
.disableSelection();
}
/*!
* metismenu - v2.7.7
* A jQuery menu plugin
* https://github.com/onokumus/metismenu#readme
*
* Made by Osman Nuri Okumus <onokumus@gmail.com> (https://github.com/onokumus)
* Under MIT License
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('jquery')) :
typeof define === 'function' && define.amd ? define(['jquery'], factory) :
(global.metisMenu = factory(global.jQuery));
}(this, (function ($) { 'use strict';
$ = $ && $.hasOwnProperty('default') ? $['default'] : $;
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
function _objectSpread(target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i] != null ? arguments[i] : {};
var ownKeys = Object.keys(source);
if (typeof Object.getOwnPropertySymbols === 'function') {
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) {
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
}));
}
ownKeys.forEach(function (key) {
_defineProperty(target, key, source[key]);
});
}
return target;
}
var Util = function ($$$1) {
// eslint-disable-line no-shadow
var TRANSITION_END = 'transitionend';
var Util = {
// eslint-disable-line no-shadow
TRANSITION_END: 'mmTransitionEnd',
triggerTransitionEnd: function triggerTransitionEnd(element) {
$$$1(element).trigger(TRANSITION_END);
},
supportsTransitionEnd: function supportsTransitionEnd() {
return Boolean(TRANSITION_END);
}
};
function getSpecialTransitionEndEvent() {
return {
bindType: TRANSITION_END,
delegateType: TRANSITION_END,
handle: function handle(event) {
if ($$$1(event.target).is(this)) {
return event.handleObj.handler.apply(this, arguments); // eslint-disable-line prefer-rest-params
}
return undefined;
}
};
}
function transitionEndEmulator(duration) {
var _this = this;
var called = false;
$$$1(this).one(Util.TRANSITION_END, function () {
called = true;
});
setTimeout(function () {
if (!called) {
Util.triggerTransitionEnd(_this);
}
}, duration);
return this;
}
function setTransitionEndSupport() {
$$$1.fn.mmEmulateTransitionEnd = transitionEndEmulator; // eslint-disable-line no-param-reassign
// eslint-disable-next-line no-param-reassign
$$$1.event.special[Util.TRANSITION_END] = getSpecialTransitionEndEvent();
}
setTransitionEndSupport();
return Util;
}($);
var MetisMenu = function ($$$1) {
// eslint-disable-line no-shadow
var NAME = 'metisMenu';
var DATA_KEY = 'metisMenu';
var EVENT_KEY = "." + DATA_KEY;
var DATA_API_KEY = '.data-api';
var JQUERY_NO_CONFLICT = $$$1.fn[NAME];
var TRANSITION_DURATION = 350;
var Default = {
toggle: true,
preventDefault: true,
activeClass: 'active',
collapseClass: 'collapse',
collapseInClass: 'in',
collapsingClass: 'collapsing',
triggerElement: 'a',
parentTrigger: 'li',
subMenu: 'ul'
};
var Event = {
SHOW: "show" + EVENT_KEY,
SHOWN: "shown" + EVENT_KEY,
HIDE: "hide" + EVENT_KEY,
HIDDEN: "hidden" + EVENT_KEY,
CLICK_DATA_API: "click" + EVENT_KEY + DATA_API_KEY
};
var MetisMenu =
/*#__PURE__*/
function () {
// eslint-disable-line no-shadow
function MetisMenu(element, config) {
this.element = element;
this.config = _objectSpread({}, Default, config);
this.transitioning = null;
this.init();
}
var _proto = MetisMenu.prototype;
_proto.init = function init() {
var self = this;
var conf = this.config;
$$$1(this.element).find(conf.parentTrigger + "." + conf.activeClass).has(conf.subMenu).children(conf.subMenu).attr('aria-expanded', true).addClass(conf.collapseClass + " " + conf.collapseInClass);
$$$1(this.element).find(conf.parentTrigger).not("." + conf.activeClass).has(conf.subMenu).children(conf.subMenu).attr('aria-expanded', false).addClass(conf.collapseClass);
$$$1(this.element).find(conf.parentTrigger).has(conf.subMenu).children(conf.triggerElement).on(Event.CLICK_DATA_API, function (e) {
// eslint-disable-line func-names
var eTar = $$$1(this);
var paRent = eTar.parent(conf.parentTrigger);
var sibLings = paRent.siblings(conf.parentTrigger).children(conf.triggerElement);
var List = paRent.children(conf.subMenu);
if (conf.preventDefault) {
e.preventDefault();
}
if (eTar.attr('aria-disabled') === 'true') {
return;
}
if (paRent.hasClass(conf.activeClass)) {
eTar.attr('aria-expanded', false);
self.hide(List);
} else {
self.show(List);
eTar.attr('aria-expanded', true);
if (conf.toggle) {
sibLings.attr('aria-expanded', false);
}
}
if (conf.onTransitionStart) {
conf.onTransitionStart(e);
}
});
};
_proto.show = function show(element) {
var _this = this;
if (this.transitioning || $$$1(element).hasClass(this.config.collapsingClass)) {
return;
}
var elem = $$$1(element);
var startEvent = $$$1.Event(Event.SHOW);
elem.trigger(startEvent);
if (startEvent.isDefaultPrevented()) {
return;
}
elem.parent(this.config.parentTrigger).addClass(this.config.activeClass);
if (this.config.toggle) {
this.hide(elem.parent(this.config.parentTrigger).siblings().children(this.config.subMenu + "." + this.config.collapseInClass).attr('aria-expanded', false));
}
elem.removeClass(this.config.collapseClass).addClass(this.config.collapsingClass).height(0);
this.setTransitioning(true);
var complete = function complete() {
// check if disposed
if (!_this.config || !_this.element) {
return;
}
elem.removeClass(_this.config.collapsingClass).addClass(_this.config.collapseClass + " " + _this.config.collapseInClass).height('').attr('aria-expanded', true);
_this.setTransitioning(false);
elem.trigger(Event.SHOWN);
};
if (!Util.supportsTransitionEnd()) {
complete();
return;
}
elem.height(element[0].scrollHeight).one(Util.TRANSITION_END, complete).mmEmulateTransitionEnd(TRANSITION_DURATION);
};
_proto.hide = function hide(element) {
var _this2 = this;
if (this.transitioning || !$$$1(element).hasClass(this.config.collapseInClass)) {
return;
}
var elem = $$$1(element);
var startEvent = $$$1.Event(Event.HIDE);
elem.trigger(startEvent);
if (startEvent.isDefaultPrevented()) {
return;
}
elem.parent(this.config.parentTrigger).removeClass(this.config.activeClass); // eslint-disable-next-line no-unused-expressions
elem.height(elem.height())[0].offsetHeight;
elem.addClass(this.config.collapsingClass).removeClass(this.config.collapseClass).removeClass(this.config.collapseInClass);
this.setTransitioning(true);
var complete = function complete() {
// check if disposed
if (!_this2.config || !_this2.element) {
return;
}
if (_this2.transitioning && _this2.config.onTransitionEnd) {
_this2.config.onTransitionEnd();
}
_this2.setTransitioning(false);
elem.trigger(Event.HIDDEN);
elem.removeClass(_this2.config.collapsingClass).addClass(_this2.config.collapseClass).attr('aria-expanded', false);
};
if (!Util.supportsTransitionEnd()) {
complete();
return;
}
if (elem.height() === 0 || elem.css('display') === 'none') {
complete();
} else {
elem.height(0).one(Util.TRANSITION_END, complete).mmEmulateTransitionEnd(TRANSITION_DURATION);
}
};
_proto.setTransitioning = function setTransitioning(isTransitioning) {
this.transitioning = isTransitioning;
};
_proto.dispose = function dispose() {
$$$1.removeData(this.element, DATA_KEY);
$$$1(this.element).find(this.config.parentTrigger).has(this.config.subMenu).children(this.config.triggerElement).off('click');
this.transitioning = null;
this.config = null;
this.element = null;
};
MetisMenu.jQueryInterface = function jQueryInterface(config) {
// eslint-disable-next-line func-names
return this.each(function () {
var $this = $$$1(this);
var data = $this.data(DATA_KEY);
var conf = _objectSpread({}, Default, $this.data(), typeof config === 'object' && config ? config : {});
if (!data && /dispose/.test(config)) {
this.dispose();
}
if (!data) {
data = new MetisMenu(this, conf);
$this.data(DATA_KEY, data);
}
if (typeof config === 'string') {
if (data[config] === undefined) {
throw new Error("No method named \"" + config + "\"");
}
data[config]();
}
});
};
return MetisMenu;
}();
/**
* ------------------------------------------------------------------------
* jQuery
* ------------------------------------------------------------------------
*/
$$$1.fn[NAME] = MetisMenu.jQueryInterface; // eslint-disable-line no-param-reassign
$$$1.fn[NAME].Constructor = MetisMenu; // eslint-disable-line no-param-reassign
$$$1.fn[NAME].noConflict = function () {
// eslint-disable-line no-param-reassign
$$$1.fn[NAME] = JQUERY_NO_CONFLICT; // eslint-disable-line no-param-reassign
return MetisMenu.jQueryInterface;
};
return MetisMenu;
}($);
return MetisMenu;
})));
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment