stuff
This commit is contained in:
+5
-12
@@ -41,32 +41,25 @@ steps:
|
||||
repo: registry.frontblock.me/vendor/admin
|
||||
tags: ${DRONE_BUILD_CREATED}
|
||||
|
||||
- name: archive static files
|
||||
- name: archive plugin files
|
||||
image: alpine:3.9
|
||||
commands:
|
||||
- apk add --no-cache zip tar
|
||||
- mkdir dist
|
||||
- zip -9r ./dist/${DRONE_REPO_NAME}.zip static
|
||||
- tar -czf ./dist/${DRONE_REPO_NAME}.tar.gz static
|
||||
- apk add --no-cache zip
|
||||
- zip -9r ./dist/plugin.zip static
|
||||
when:
|
||||
event:
|
||||
- tag
|
||||
|
||||
- name: release static files
|
||||
- name: release plugin archive
|
||||
image: plugins/gitea-release
|
||||
settings:
|
||||
base_url: https://gitea.frontblock.me
|
||||
api_key:
|
||||
from_secret: release_token
|
||||
files:
|
||||
- dist/*
|
||||
- plugin.zip
|
||||
checksum:
|
||||
- md5
|
||||
- sha1
|
||||
- sha256
|
||||
- sha512
|
||||
- adler32
|
||||
- crc32
|
||||
when:
|
||||
event:
|
||||
- tag
|
||||
|
||||
Generated
+1066
-644
File diff suppressed because it is too large
Load Diff
+5
-3
@@ -3,9 +3,11 @@
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"tsc": "tsc",
|
||||
"start": "npm run build; node lib/backendsrc/FrontblockAdmin.js",
|
||||
"build": "tsc; webpack --display-error-details --config static.webpack.config.prod.js --progress --colors",
|
||||
"clean": "rm -rf lib",
|
||||
"start": "npm run build; node lib/FrontblockAdmin.js",
|
||||
"build": "npm run clean; npm run build-backend; npm run build-frontend",
|
||||
"build-backend": "tsc; webpack --display-error-details --config static.webpack.config.prod.js --progress --colors",
|
||||
"build-frontend": "cd src/frontend; npm run build; cp -r dist/* ../../static",
|
||||
"clean": "rm -rf lib static; rm -rf src/frontend/dist",
|
||||
"update-frontblock": "rm -rf node_modules/frontblock*; npm install"
|
||||
},
|
||||
"repository": {
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
import { Greeter } from '../index';
|
||||
test('My Greeter', () => {
|
||||
expect(Greeter('Carl')).toBe('Hello Carl');
|
||||
});
|
||||
@@ -1,13 +1,13 @@
|
||||
'use strict'
|
||||
|
||||
import * as Logger from 'log4js'
|
||||
import { Plugin, socketioRPC } from 'frontblock-generic/Plugin';
|
||||
import { Plugin, socketioRPC, ConfigLoader } from 'frontblock-generic/Plugin';
|
||||
import { ErrorResponse, SuccessResponse } from 'frontblock-generic/Types';
|
||||
import { PluginManager } from './PluginManager'
|
||||
import { PluginManagerPlugin } from './PluginManager/Plugin'
|
||||
import express = require('express');
|
||||
import http = require('http');
|
||||
import bsock = require('bsock');
|
||||
|
||||
import { type } from 'os';
|
||||
|
||||
const kfs = require("key-file-storage").default('kfs')
|
||||
|
||||
@@ -51,6 +51,8 @@ export type rpcInfo =
|
||||
info: hookRPC | unhookRPC | callRPC
|
||||
}
|
||||
|
||||
export type AdminConf = { httpPort: number}
|
||||
|
||||
/**
|
||||
* FrontblockAdmin
|
||||
*
|
||||
@@ -59,27 +61,29 @@ export type rpcInfo =
|
||||
*
|
||||
* The list of available plugins is published via the frontblock API and downloaded via gitea-releases
|
||||
*/
|
||||
export class FrontblockAdmin{
|
||||
private plugins: Plugin[] = []
|
||||
export class FrontblockAdmin extends ConfigLoader<AdminConf>{
|
||||
|
||||
private hookToUids:{[hookName:string]:string[]} = {}
|
||||
private express
|
||||
private httpServer
|
||||
private io = bsock.createServer()
|
||||
private wsServer = http.createServer()
|
||||
private pm: PluginManager
|
||||
private pm: PluginManagerPlugin
|
||||
|
||||
constructor(){
|
||||
if(!('admin.conf' in kfs)){
|
||||
logger.info('Generating ./kfs/admin.conf')
|
||||
kfs['admin.conf'] = { httpPort: 8080 }
|
||||
}
|
||||
this.pm = new PluginManager()
|
||||
super("FrontblockAdmin")
|
||||
this.pm = new PluginManagerPlugin()
|
||||
|
||||
this.initialize()
|
||||
}
|
||||
|
||||
getDefaultConfig(): AdminConf {
|
||||
return {httpPort: 8080}
|
||||
}
|
||||
|
||||
private async initialize(){
|
||||
//this.startWebsocket()
|
||||
//this.startWebserver()
|
||||
this.startWebsocket()
|
||||
this.startWebserver()
|
||||
}
|
||||
|
||||
private initApis(socket){
|
||||
@@ -104,14 +108,15 @@ export class FrontblockAdmin{
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
//translate RPCs to socket-bound function metadata
|
||||
this.plugins.forEach(plugin => {
|
||||
const pluginName = plugin.name
|
||||
plugin.exportRPCs().forEach(rpc => {
|
||||
const info = this.rpcToRpcInfo(pluginName, rpc)
|
||||
const loadedPlugins = this.pm.getLoadedPlugins()
|
||||
for(const name in loadedPlugins){
|
||||
loadedPlugins[name].exportRPCs().forEach(rpc => {
|
||||
const info = this.rpcToRpcInfo(name, rpc)
|
||||
rpcInfos.push(info)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
//Hook up all the functions
|
||||
for(const api of rpcInfos){
|
||||
@@ -161,7 +166,7 @@ export class FrontblockAdmin{
|
||||
return
|
||||
}
|
||||
|
||||
let port:number = kfs.FrontblockAdmin.httpPort
|
||||
let port:number = this.conf.httpPort
|
||||
this.express = express()
|
||||
this.express.use(express.static('static'))
|
||||
|
||||
@@ -184,7 +189,7 @@ export class FrontblockAdmin{
|
||||
|
||||
private restartWebserver(port:number){
|
||||
this.stopWebserver()
|
||||
kfs['admin.conf'] = { httpPort: port }
|
||||
kfs[this.name+".conf"] = <AdminConf>{ httpPort: port }
|
||||
this.startWebserver()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
import { default as PluginManager } from "./PluginManager";
|
||||
import { Plugin } from "frontblock-generic/Plugin";
|
||||
import * as Logger from 'log4js';
|
||||
|
||||
Logger.configure({
|
||||
appenders:
|
||||
{
|
||||
"PluginManager/Plugin": { type: 'stdout' },
|
||||
//app: { type: 'file', filename: 'application.log' }
|
||||
},
|
||||
categories:
|
||||
{
|
||||
default: { appenders: [ 'PluginManager/Plugin' ], level: 'debug' }
|
||||
}
|
||||
})
|
||||
const logger = Logger.getLogger("PluginManager/Plugin")
|
||||
|
||||
|
||||
export class PluginManagerPlugin extends PluginManager implements Plugin{
|
||||
name: string;
|
||||
|
||||
constructor(){
|
||||
super()
|
||||
|
||||
this.loadedPlugins[this.name] = this
|
||||
}
|
||||
|
||||
exportRPCs(): import("frontblock-generic/Plugin").socketioRPC[] {
|
||||
return [
|
||||
{
|
||||
name: "getAvailablePluginNames",
|
||||
visibility: "private",
|
||||
rpc: async() => { return await this.getAvailablePluginNames() },
|
||||
type: 'call'
|
||||
},
|
||||
{
|
||||
name: "getInstalledPlugins",
|
||||
visibility: "private",
|
||||
rpc: async() => { return await this.getInstalledPlugins() },
|
||||
type: 'call'
|
||||
},
|
||||
{
|
||||
name: "getLoadedPlugins",
|
||||
visibility: "private",
|
||||
rpc: async () => { return this.getLoadedPlugins() },
|
||||
type: 'call'
|
||||
},
|
||||
{
|
||||
name: "installPlugin",
|
||||
visibility: "private",
|
||||
rpc: async(pluginName:string) => { return await this.installPlugin(pluginName) },
|
||||
type: 'call'
|
||||
},
|
||||
{
|
||||
name: "uninstallPlugin",
|
||||
visibility: "private",
|
||||
rpc: async(pluginName:string) => { return await this.uninstallPlugin(pluginName) },
|
||||
type: 'call'
|
||||
},
|
||||
{
|
||||
name: "loadPlugin",
|
||||
visibility: "private",
|
||||
rpc: async(pluginName:string) => { return await this.loadPlugin(pluginName) },
|
||||
type: 'call'
|
||||
},
|
||||
{
|
||||
name: "unloadPlugin",
|
||||
visibility: "private",
|
||||
rpc: async(pluginName:string) => { return this.unloadPlugin(pluginName) },
|
||||
type: 'call'
|
||||
},
|
||||
{
|
||||
name: "updateConfig",
|
||||
visibility: "private",
|
||||
rpc: async(conf) => { return this.updateConfig(conf) },
|
||||
type: 'call'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
async start(): Promise<void> {
|
||||
await this.installPlugin("admin") //self-update
|
||||
}
|
||||
|
||||
stop(): void {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
}
|
||||
@@ -5,32 +5,53 @@ import fetch = require('node-fetch');
|
||||
import fs = require('fs');
|
||||
import path = require('path')
|
||||
import unzip = require('unzip')
|
||||
import { Plugin, ConfigLoader } from 'frontblock-generic/Plugin';
|
||||
import { SemVer } from "semver";
|
||||
|
||||
Logger.configure({
|
||||
appenders:
|
||||
{
|
||||
"plugin-manager": { type: 'stdout' },
|
||||
"PluginManager": { type: 'stdout' },
|
||||
//app: { type: 'file', filename: 'application.log' }
|
||||
},
|
||||
categories:
|
||||
{
|
||||
default: { appenders: [ 'plugin-manager' ], level: 'debug' }
|
||||
default: { appenders: [ 'PluginManager' ], level: 'debug' }
|
||||
}
|
||||
})
|
||||
const logger = Logger.getLogger("plugin-manager")
|
||||
const logger = Logger.getLogger("PluginManager")
|
||||
|
||||
|
||||
export class PluginManager{
|
||||
|
||||
private installDir: string
|
||||
private cacheDir: string
|
||||
private loadedPlugins: string[]
|
||||
|
||||
constructor(installDir: string = './plugins'){
|
||||
this.installDir = installDir
|
||||
this.cacheDir = path.join(installDir, '.cache')
|
||||
this.initialize()
|
||||
type PluginVersion = {
|
||||
installed?: SemVer,
|
||||
cached?: SemVer,
|
||||
loaded?: SemVer
|
||||
}
|
||||
export type PluginVersioning = {
|
||||
[pluginName in string]?: PluginVersion | string
|
||||
}
|
||||
export type PluginMap = {[pluginName:string]: Plugin}
|
||||
|
||||
export type PluginManagerConfig = {
|
||||
resourceLocation: string,
|
||||
installDir:string
|
||||
}
|
||||
|
||||
export default class PluginManager extends ConfigLoader<PluginManagerConfig&PluginVersioning>{
|
||||
|
||||
private cacheDir: string
|
||||
protected loadedPlugins: PluginMap = {}
|
||||
|
||||
constructor(){
|
||||
super("PluginManager")
|
||||
this.cacheDir = path.join(this.conf.installDir, '.cache')
|
||||
this.initialize()
|
||||
this.loadPlugin("../../../../../../apiclient")
|
||||
}
|
||||
|
||||
getDefaultConfig(): PluginManagerConfig&PluginVersioning{
|
||||
return {resourceLocation: "https://gitea.frontblock.me/api/v1/repos/fb-vendor/", installDir: "./plugins"}
|
||||
}
|
||||
|
||||
|
||||
private initialize() {
|
||||
logger.info('Initializing manager')
|
||||
@@ -39,9 +60,9 @@ export class PluginManager{
|
||||
fs.access(this.cacheDir, async err => {
|
||||
if (err && err.code === 'ENOENT') {
|
||||
await fs.promises.mkdir(this.cacheDir, {recursive: true})
|
||||
logger.info('Manager installed to ' + this.installDir)
|
||||
logger.info('Manager installed to ' + this.conf.installDir)
|
||||
} else {
|
||||
logger.info('Manager already installed at ' + this.installDir)
|
||||
logger.info('Manager already installed at ' + this.conf.installDir)
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
@@ -49,7 +70,9 @@ export class PluginManager{
|
||||
}
|
||||
}
|
||||
|
||||
public async getAvailablePlugins(): Promise<string[] | void> {
|
||||
|
||||
public async getAvailablePluginNames(): Promise<string[]> {
|
||||
//TODO query api
|
||||
return [
|
||||
'apiclient',
|
||||
'paymentmanager',
|
||||
@@ -58,20 +81,21 @@ export class PluginManager{
|
||||
]
|
||||
}
|
||||
|
||||
public async getInstalledPlugins(): Promise<string[] | void> {
|
||||
public async getInstalledPlugins(): Promise<string[]> {
|
||||
try {
|
||||
const installed = await fs.promises.readdir(this.installDir)
|
||||
const installed = await fs.promises.readdir(this.conf.installDir)
|
||||
return installed.filter( entry => entry[0] != '.')
|
||||
} catch (error) {
|
||||
logger.error(error)
|
||||
return
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
public async getLoadedPlugins(): Promise<string[] | void> {
|
||||
public getLoadedPlugins(): PluginMap {
|
||||
return this.loadedPlugins
|
||||
}
|
||||
|
||||
|
||||
private async downloadFile(url: URL, dest: string) {
|
||||
try {
|
||||
fs.access(path.dirname(dest), err => {
|
||||
@@ -93,7 +117,9 @@ export class PluginManager{
|
||||
|
||||
private async downloadPlugin(pluginName: string) {
|
||||
try {
|
||||
const response = await fetch('https://gitea.frontblock.me/api/v1/repos/fb-vendor/' + pluginName + '/releases')
|
||||
logger.info("Downloading Plugin")
|
||||
|
||||
const response = await fetch(this.conf.resourceLocation + pluginName + '/releases')
|
||||
if (!response.ok) throw new Error(response.statusText)
|
||||
|
||||
const releases = await response.json()
|
||||
@@ -116,21 +142,36 @@ export class PluginManager{
|
||||
public async installPlugin(pluginName: string) {
|
||||
try {
|
||||
await this.downloadPlugin(pluginName)
|
||||
//TODO do something
|
||||
} catch (error) {
|
||||
logger.debug(error)
|
||||
logger.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
public uninstallPlugin(pluginName: string) {
|
||||
|
||||
public async uninstallPlugin(pluginName: string) {
|
||||
//TODO check for exists
|
||||
logger.info("Deleting plugin", pluginName)
|
||||
await fs.promises.rmdir(path.join(this.conf.installDir,pluginName))
|
||||
}
|
||||
|
||||
|
||||
public async loadPlugin() {
|
||||
|
||||
public async loadPlugin(pluginName:string) {
|
||||
const pth = path.join(this.conf.installDir, pluginName, "Plugin")
|
||||
logger.info("Loading plugin from fs", pth)
|
||||
const clazz = await import(pth)
|
||||
let obj:Plugin = new clazz.default()
|
||||
await obj.start()
|
||||
this.loadedPlugins[pluginName] = obj
|
||||
}
|
||||
|
||||
public async unloadPlugin() {
|
||||
|
||||
public unloadPlugin(pluginName:string):void {
|
||||
if(this.loadedPlugins[pluginName] == null){
|
||||
logger.warn("Cannt unload plugin: Unknown:", pluginName)
|
||||
return
|
||||
}
|
||||
logger.info("Unloading plugin ", pluginName)
|
||||
this.loadedPlugins[pluginName].stop()
|
||||
delete this.loadedPlugins[pluginName]
|
||||
}
|
||||
}
|
||||
Vendored
-5
@@ -1,5 +0,0 @@
|
||||
export default class Controller {
|
||||
private $rootScope;
|
||||
static $inject: string[];
|
||||
constructor($rootScope: any);
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
export default class Controller {
|
||||
|
||||
static $inject = ['$rootScope']
|
||||
|
||||
constructor(private $rootScope){
|
||||
|
||||
}
|
||||
}
|
||||
Vendored
-7
@@ -1,7 +0,0 @@
|
||||
import './index.scss';
|
||||
import rootCtrl from './controller';
|
||||
declare const _default: {
|
||||
template: string;
|
||||
controller: typeof rootCtrl;
|
||||
};
|
||||
export default _default;
|
||||
@@ -1,34 +0,0 @@
|
||||
<div class="grid">
|
||||
<aside class="sidenav">
|
||||
<div class="sidenav__profile">
|
||||
<a class="sidenav__brand-link" href="#">Front<span class="text-light">block</span></a>
|
||||
<i class="fas fa-times sidenav__brand-close"></i>
|
||||
</div>
|
||||
<div class="row row--align-v-center row--align-h-center">
|
||||
<ul class="navlist">
|
||||
<li class="navlist__heading">wallets<i class="far fa-file-alt"></i></li>
|
||||
<!--
|
||||
<a ui-sref="btc" ui-sref-active="active">
|
||||
<div class="navlist__subheading row row--align-v-center">
|
||||
<span class="navlist__subheading-icon"><i class="fas fa-briefcase-medical"></i></span>
|
||||
<span class="navlist__subheading-title">Bitcoin</span>
|
||||
</div>
|
||||
</a>
|
||||
-->
|
||||
<a ui-sref="todolist" ui-sref-active="active">
|
||||
<div class="navlist__subheading row row--align-v-center">
|
||||
<span class="navlist__subheading-icon"><i class="fas fa-users"></i></span>
|
||||
<span class="navlist__subheading-title">ANOTHER ONE</span>
|
||||
</div>
|
||||
</a>
|
||||
</ul>
|
||||
</div>
|
||||
</aside>
|
||||
<main class="main">
|
||||
<div ui-view class="view"></div>
|
||||
</main>
|
||||
<footer class="footer">
|
||||
<p><span class="footer__copyright">©</span> MIT license (open source)</p>
|
||||
<p>by <a href="https://frontblock.me" target="_blank" class="footer__signature">Frontblock.me</a></p>
|
||||
</footer>
|
||||
</div>
|
||||
@@ -1,6 +0,0 @@
|
||||
|
||||
|
||||
.view {
|
||||
height: 100%;
|
||||
min-height: 300px;
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
const html = require('./index.html').default
|
||||
import './index.scss'
|
||||
import rootCtrl from './controller'
|
||||
|
||||
export default {
|
||||
template: html,
|
||||
controller: rootCtrl
|
||||
}
|
||||
Vendored
-2
@@ -1,2 +0,0 @@
|
||||
declare const _default: string;
|
||||
export default _default;
|
||||
@@ -1,7 +0,0 @@
|
||||
import angular = require('angular')
|
||||
import Root from './Root'
|
||||
|
||||
export default angular
|
||||
.module('components', [])
|
||||
.component('root', Root)
|
||||
.name
|
||||
Vendored
-5
@@ -1,5 +0,0 @@
|
||||
declare function routerRegister($urlRouterProvider: any, $stateProvider: any): void;
|
||||
declare namespace routerRegister {
|
||||
var $inject: string[];
|
||||
}
|
||||
export default routerRegister;
|
||||
@@ -1,34 +0,0 @@
|
||||
const routePathes: Array<string> = [
|
||||
'todo-list'
|
||||
]
|
||||
|
||||
let routes: Array<object> = []
|
||||
|
||||
routePathes.forEach(path => {
|
||||
const parentRoutes = require(`../views/${path}/route`).default
|
||||
const { children } = parentRoutes
|
||||
let childRoutes: Array<object> = []
|
||||
|
||||
if (children && children.length > 0) {
|
||||
childRoutes = children.map(childRoute => {
|
||||
childRoute.name = `${parentRoutes.name}.${childRoute.name}`
|
||||
return childRoute
|
||||
})
|
||||
}
|
||||
|
||||
delete parentRoutes.children
|
||||
childRoutes.push(parentRoutes)
|
||||
routes = routes.concat(childRoutes)
|
||||
})
|
||||
|
||||
function routerRegister($urlRouterProvider, $stateProvider): void {
|
||||
$urlRouterProvider.otherwise('views')
|
||||
|
||||
routes.forEach(route => {
|
||||
$stateProvider.state(route)
|
||||
})
|
||||
}
|
||||
|
||||
routerRegister.$inject = ['$urlRouterProvider', '$stateProvider']
|
||||
|
||||
export default routerRegister
|
||||
Vendored
-2
@@ -1,2 +0,0 @@
|
||||
declare const _default: string;
|
||||
export default _default;
|
||||
@@ -1,7 +0,0 @@
|
||||
import angular = require('angular')
|
||||
import todosVisible from './todosVisible'
|
||||
|
||||
export default angular
|
||||
.module('filters', [])
|
||||
.filter('todosVisible', () => todosVisible)
|
||||
.name
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
export default function (todos: any, type: string): Array<object>;
|
||||
@@ -1,12 +0,0 @@
|
||||
export default function (todos, type: string): Array<object> {
|
||||
switch (type) {
|
||||
case 'All':
|
||||
return todos
|
||||
case 'Todo':
|
||||
return todos.filter(todo => !todo.complete)
|
||||
case 'Done':
|
||||
return todos.filter(todo => todo.complete)
|
||||
default:
|
||||
throw new Error('Unknown type ' + type)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"project": {
|
||||
"name": "dashboard"
|
||||
},
|
||||
"apps": [
|
||||
{
|
||||
"root": "src",
|
||||
"outDir": "dist",
|
||||
"assets": [
|
||||
"assets",
|
||||
"favicon.ico"
|
||||
],
|
||||
"index": "index.html",
|
||||
"main": "main.ts",
|
||||
"polyfills": "polyfills.ts",
|
||||
"test": "test.ts",
|
||||
"tsconfig": "tsconfig.app.json",
|
||||
"testTsconfig": "tsconfig.spec.json",
|
||||
"prefix": "app",
|
||||
"styles": [
|
||||
"../node_modules/@clr/ui/clr-ui.min.css",
|
||||
"styles.css"
|
||||
],
|
||||
"scripts": [
|
||||
"../node_modules/systemjs/dist/system.js"
|
||||
],
|
||||
"environmentSource": "environments/environment.ts",
|
||||
"environments": {
|
||||
"dev": "environments/environment.ts",
|
||||
"prod": "environments/environment.prod.ts"
|
||||
}
|
||||
}
|
||||
],
|
||||
"e2e": {
|
||||
"protractor": {
|
||||
"config": "./protractor.conf.js"
|
||||
}
|
||||
},
|
||||
"lint": [
|
||||
{
|
||||
"project": "src/tsconfig.app.json",
|
||||
"exclude": "**/node_modules/**"
|
||||
},
|
||||
{
|
||||
"project": "src/tsconfig.spec.json",
|
||||
"exclude": "**/node_modules/**"
|
||||
},
|
||||
{
|
||||
"project": "e2e/tsconfig.e2e.json",
|
||||
"exclude": "**/node_modules/**"
|
||||
}
|
||||
],
|
||||
"test": {
|
||||
"karma": {
|
||||
"config": "./karma.conf.js"
|
||||
}
|
||||
},
|
||||
"defaults": {
|
||||
"styleExt": "css",
|
||||
"component": {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
# Editor configuration, see http://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
|
||||
@@ -0,0 +1,44 @@
|
||||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# compiled output
|
||||
/dist
|
||||
/dist-server
|
||||
/tmp
|
||||
/out-tsc
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# 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
|
||||
|
||||
# misc
|
||||
/.sass-cache
|
||||
/connect.lock
|
||||
/coverage
|
||||
/libpeerconnection.log
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
testem.log
|
||||
/typings
|
||||
|
||||
# e2e
|
||||
/e2e/*.js
|
||||
/e2e/*.map
|
||||
|
||||
# System Files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
@@ -0,0 +1,7 @@
|
||||
# Dashboard
|
||||
|
||||
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.7.4.
|
||||
|
||||
## Development server
|
||||
|
||||
Run `yarn start` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
|
||||
@@ -0,0 +1,14 @@
|
||||
import { AppPage } from './app.po';
|
||||
|
||||
describe('dashboard App', () => {
|
||||
let page: AppPage;
|
||||
|
||||
beforeEach(() => {
|
||||
page = new AppPage();
|
||||
});
|
||||
|
||||
it('should display welcome message', () => {
|
||||
page.navigateTo();
|
||||
expect(page.getParagraphText()).toEqual('Welcome to app!');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
import { browser, by, element } from 'protractor';
|
||||
|
||||
export class AppPage {
|
||||
navigateTo() {
|
||||
return browser.get('/');
|
||||
}
|
||||
|
||||
getParagraphText() {
|
||||
return element(by.css('app-root h1')).getText();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/e2e",
|
||||
"baseUrl": "./",
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"jasminewd2",
|
||||
"node"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// 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/cli'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage-istanbul-reporter'),
|
||||
require('@angular/cli/plugins/karma')
|
||||
],
|
||||
client:{
|
||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
coverageIstanbulReporter: {
|
||||
reports: [ 'html', 'lcovonly' ],
|
||||
fixWebpackSourcePaths: true
|
||||
},
|
||||
angularCli: {
|
||||
environment: 'dev'
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false
|
||||
});
|
||||
};
|
||||
Generated
+13122
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"name": "dashboard",
|
||||
"version": "0.0.0",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve --aot=true --proxy-config proxy.conf.json",
|
||||
"build": "ng build --prod --aot=false",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "^5.2.0",
|
||||
"@angular/common": "^5.2.0",
|
||||
"@angular/compiler": "^5.2.0",
|
||||
"@angular/core": "^5.2.0",
|
||||
"@angular/forms": "^5.2.0",
|
||||
"@angular/http": "^5.2.0",
|
||||
"@angular/platform-browser": "^5.2.0",
|
||||
"@angular/platform-browser-dynamic": "^5.2.0",
|
||||
"@angular/router": "^5.2.0",
|
||||
"@clr/ui": "^0.11.15",
|
||||
"core-js": "^2.4.1",
|
||||
"rxjs": "^5.5.6",
|
||||
"systemjs": "^0.21.3",
|
||||
"zone.js": "^0.8.19"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/cli": "~1.7.4",
|
||||
"@angular/compiler-cli": "^5.2.0",
|
||||
"@angular/language-service": "^5.2.0",
|
||||
"@types/jasmine": "~2.8.3",
|
||||
"@types/jasminewd2": "~2.0.2",
|
||||
"@types/node": "~6.0.60",
|
||||
"@types/systemjs": "^0.20.6",
|
||||
"codelyzer": "^4.0.1",
|
||||
"jasmine-core": "~2.8.0",
|
||||
"jasmine-spec-reporter": "~4.2.1",
|
||||
"karma": "~2.0.0",
|
||||
"karma-chrome-launcher": "~2.2.0",
|
||||
"karma-coverage-istanbul-reporter": "^1.2.1",
|
||||
"karma-jasmine": "~1.1.0",
|
||||
"karma-jasmine-html-reporter": "^0.2.2",
|
||||
"protractor": "~5.1.2",
|
||||
"ts-node": "~4.1.0",
|
||||
"tslint": "~5.9.1",
|
||||
"typescript": "~2.5.3"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// Protractor configuration file, see link for more information
|
||||
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
||||
|
||||
const { SpecReporter } = require('jasmine-spec-reporter');
|
||||
|
||||
exports.config = {
|
||||
allScriptsTimeout: 11000,
|
||||
specs: [
|
||||
'./e2e/**/*.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: 'e2e/tsconfig.e2e.json'
|
||||
});
|
||||
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"/widgets-repo/*": {
|
||||
"target": "http://localhost:4201",
|
||||
"secure": false,
|
||||
"pathRewrite": {
|
||||
"^/widgets-repo": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<div class="main-container">
|
||||
<header class="header-6">
|
||||
<div class="branding">
|
||||
<a class="nav-link">
|
||||
<span class="title">Dashboard and Widgets</span>
|
||||
</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="content-container">
|
||||
<div class="content-area">
|
||||
<app-dashboard></app-dashboard>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,8 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.css']
|
||||
})
|
||||
export class AppComponent {}
|
||||
@@ -0,0 +1,43 @@
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
|
||||
import { COMPILER_OPTIONS, CompilerFactory, Compiler } from '@angular/core';
|
||||
import { JitCompilerFactory } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
import { DashboardModule } from './dashboard/dashboard.module';
|
||||
|
||||
export function createCompiler(fn: CompilerFactory): Compiler {
|
||||
return fn.createCompiler();
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
HttpClientModule,
|
||||
DashboardModule
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
provide: COMPILER_OPTIONS,
|
||||
useValue: {},
|
||||
multi: true
|
||||
},
|
||||
{
|
||||
provide: CompilerFactory,
|
||||
useClass: JitCompilerFactory,
|
||||
deps: [COMPILER_OPTIONS]
|
||||
},
|
||||
{
|
||||
provide: Compiler,
|
||||
useFactory: createCompiler,
|
||||
deps: [CompilerFactory]
|
||||
}
|
||||
],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
||||
@@ -0,0 +1,12 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { DashboardComponent } from './dashboard/dashboard.component';
|
||||
import { DashboardService } from './dashboard.service';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule],
|
||||
declarations: [DashboardComponent],
|
||||
providers: [DashboardService],
|
||||
exports: [DashboardComponent]
|
||||
})
|
||||
export class DashboardModule { }
|
||||
@@ -0,0 +1,17 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
import { WidgetConfig } from './widget-config.model';
|
||||
|
||||
@Injectable()
|
||||
export class DashboardService {
|
||||
|
||||
constructor(private http: HttpClient) { }
|
||||
|
||||
private readonly url = 'widgets-repo/widgets.config.json';
|
||||
|
||||
getWidgetConfigs(): Observable<WidgetConfig[]> {
|
||||
return this.http.get<WidgetConfig[]>(this.url);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<div class="card-columns">
|
||||
<div #content></div>
|
||||
</div>
|
||||
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Set existing vendor modules into SystemJS registry.
|
||||
* This way SystemJS won't make HTTP requests to fetch imported modules
|
||||
* needed by the dynamicaly loaded Widgets.
|
||||
*/
|
||||
import { System } from 'systemjs';
|
||||
declare const SystemJS: System;
|
||||
|
||||
import * as angularCore from '@angular/core';
|
||||
import * as angularCommon from '@angular/common';
|
||||
import * as angularCommonHttp from '@angular/common/http';
|
||||
import * as angularForms from '@angular/forms';
|
||||
import * as angularAnimations from '@angular/animations';
|
||||
import * as angularPlatformBrowser from '@angular/platform-browser';
|
||||
import * as angularPlatformBrowserDynamic from '@angular/platform-browser-dynamic';
|
||||
|
||||
SystemJS.set('@angular/core', SystemJS.newModule(angularCore));
|
||||
SystemJS.set('@angular/common', SystemJS.newModule(angularCommon));
|
||||
SystemJS.set('@angular/common/http', SystemJS.newModule(angularCommonHttp));
|
||||
SystemJS.set('@angular/forms', SystemJS.newModule(angularForms));
|
||||
SystemJS.set('@angular/animations', SystemJS.newModule(angularAnimations));
|
||||
SystemJS.set('@angular/platform-browser', SystemJS.newModule(angularPlatformBrowser));
|
||||
SystemJS.set('@angular/platform-browser-dynamic', SystemJS.newModule(angularPlatformBrowserDynamic));
|
||||
|
||||
SystemJS.config({ meta: { '*': { authorization: true } } });
|
||||
/** --------- */
|
||||
|
||||
import { AfterViewInit, Component, Compiler, Injector, OnInit, ViewChild, ViewContainerRef } from '@angular/core';
|
||||
import { DashboardService } from '../dashboard.service';
|
||||
import { WidgetConfig } from '../widget-config.model';
|
||||
|
||||
@Component({
|
||||
selector: 'app-dashboard',
|
||||
templateUrl: './dashboard.component.html',
|
||||
styleUrls: ['./dashboard.component.css']
|
||||
})
|
||||
export class DashboardComponent implements AfterViewInit {
|
||||
|
||||
@ViewChild('content', { read: ViewContainerRef }) content: ViewContainerRef;
|
||||
|
||||
constructor(private compiler: Compiler, private dashboardService: DashboardService,
|
||||
private injector: Injector) { }
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.loadWidgets();
|
||||
}
|
||||
|
||||
private async loadWidgets() {
|
||||
const widgets = await this.dashboardService.getWidgetConfigs().toPromise();
|
||||
widgets.forEach((widget) => this.createWidget(widget));
|
||||
}
|
||||
|
||||
private async createWidget(widget: WidgetConfig) {
|
||||
// import external module bundle
|
||||
console.log(`Importing module bundle: ${widget.moduleBundlePath}`);
|
||||
const module = await SystemJS.import(widget.moduleBundlePath);
|
||||
|
||||
// compile module
|
||||
const moduleFactory = await this.compiler.compileModuleAsync(module[widget.moduleName]);
|
||||
|
||||
// resolve component factory
|
||||
const moduleRef = moduleFactory.create(this.injector);
|
||||
const componentProvider = moduleRef.injector.get(widget.name);
|
||||
const componentFactory = moduleRef.componentFactoryResolver.resolveComponentFactory(componentProvider);
|
||||
|
||||
// compile component
|
||||
console.log(`Creating widget: ${widget.name}`);
|
||||
this.content.createComponent(componentFactory);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export interface WidgetConfig {
|
||||
name: string;
|
||||
moduleBundlePath: string;
|
||||
moduleName: string;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export const environment = {
|
||||
production: true
|
||||
};
|
||||
@@ -0,0 +1,8 @@
|
||||
// The file contents for the current environment will overwrite these during build.
|
||||
// The build system defaults to the dev environment which uses `environment.ts`, but if you do
|
||||
// `ng build --env=prod` then `environment.prod.ts` will be used instead.
|
||||
// The list of which env maps to which file can be found in `.angular-cli.json`.
|
||||
|
||||
export const environment = {
|
||||
production: false
|
||||
};
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 5.3 KiB |
@@ -0,0 +1,14 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Dashboard</title>
|
||||
<base href="/">
|
||||
<script src="FrontblockLib.js"></script>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,12 @@
|
||||
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.log(err));
|
||||
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* 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/docs/ts/latest/guide/browser-support.html
|
||||
*/
|
||||
|
||||
/***************************************************************************************************
|
||||
* BROWSER POLYFILLS
|
||||
*/
|
||||
|
||||
/** IE9, IE10 and IE11 requires all of the following polyfills. **/
|
||||
// import 'core-js/es6/symbol';
|
||||
// import 'core-js/es6/object';
|
||||
// import 'core-js/es6/function';
|
||||
// import 'core-js/es6/parse-int';
|
||||
// import 'core-js/es6/parse-float';
|
||||
// import 'core-js/es6/number';
|
||||
// import 'core-js/es6/math';
|
||||
// import 'core-js/es6/string';
|
||||
// import 'core-js/es6/date';
|
||||
// import 'core-js/es6/array';
|
||||
// import 'core-js/es6/regexp';
|
||||
// import 'core-js/es6/map';
|
||||
// import 'core-js/es6/weak-map';
|
||||
// import 'core-js/es6/set';
|
||||
|
||||
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
|
||||
// import 'classlist.js'; // Run `npm install --save classlist.js`.
|
||||
|
||||
/** IE10 and IE11 requires the following for the Reflect API. */
|
||||
// import 'core-js/es6/reflect';
|
||||
|
||||
|
||||
/** Evergreen browsers require these. **/
|
||||
// Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove.
|
||||
import 'core-js/es7/reflect';
|
||||
|
||||
|
||||
/**
|
||||
* Required to support Web Animations `@angular/platform-browser/animations`.
|
||||
* Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation
|
||||
**/
|
||||
// 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
|
||||
*/
|
||||
|
||||
// (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__BLACK_LISTED_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
|
||||
*/
|
||||
@@ -0,0 +1 @@
|
||||
/* You can add global styles to this file, and also import other style files */
|
||||
@@ -0,0 +1,20 @@
|
||||
// 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);
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/app",
|
||||
"baseUrl": "./",
|
||||
"module": "es2015",
|
||||
"types": []
|
||||
},
|
||||
"exclude": [
|
||||
"test.ts",
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/spec",
|
||||
"baseUrl": "./",
|
||||
"module": "commonjs",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"node"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"test.ts"
|
||||
],
|
||||
"include": [
|
||||
"**/*.spec.ts",
|
||||
"**/*.d.ts"
|
||||
]
|
||||
}
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
/* SystemJS module definition */
|
||||
declare var module: NodeModule;
|
||||
interface NodeModule {
|
||||
id: string;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"compileOnSave": false,
|
||||
"compilerOptions": {
|
||||
"outDir": "./static/out-tsc",
|
||||
"sourceMap": true,
|
||||
"declaration": false,
|
||||
"moduleResolution": "node",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"target": "es5",
|
||||
"typeRoots": [
|
||||
"node_modules/@types"
|
||||
],
|
||||
"lib": [
|
||||
"es2017",
|
||||
"dom"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
{
|
||||
"rulesDirectory": [
|
||||
"node_modules/codelyzer"
|
||||
],
|
||||
"rules": {
|
||||
"arrow-return-shorthand": true,
|
||||
"callable-types": true,
|
||||
"class-name": true,
|
||||
"comment-format": [
|
||||
true,
|
||||
"check-space"
|
||||
],
|
||||
"curly": true,
|
||||
"deprecation": {
|
||||
"severity": "warn"
|
||||
},
|
||||
"eofline": true,
|
||||
"forin": true,
|
||||
"import-blacklist": [
|
||||
true,
|
||||
"rxjs",
|
||||
"rxjs/Rx"
|
||||
],
|
||||
"import-spacing": true,
|
||||
"indent": [
|
||||
true,
|
||||
"spaces"
|
||||
],
|
||||
"interface-over-type-literal": true,
|
||||
"label-position": true,
|
||||
"max-line-length": [
|
||||
true,
|
||||
140
|
||||
],
|
||||
"member-access": false,
|
||||
"member-ordering": [
|
||||
true,
|
||||
{
|
||||
"order": [
|
||||
"static-field",
|
||||
"instance-field",
|
||||
"static-method",
|
||||
"instance-method"
|
||||
]
|
||||
}
|
||||
],
|
||||
"no-arg": true,
|
||||
"no-bitwise": true,
|
||||
"no-console": [
|
||||
true,
|
||||
"debug",
|
||||
"info",
|
||||
"time",
|
||||
"timeEnd",
|
||||
"trace"
|
||||
],
|
||||
"no-construct": true,
|
||||
"no-debugger": true,
|
||||
"no-duplicate-super": true,
|
||||
"no-empty": false,
|
||||
"no-empty-interface": true,
|
||||
"no-eval": true,
|
||||
"no-inferrable-types": [
|
||||
true,
|
||||
"ignore-params"
|
||||
],
|
||||
"no-misused-new": true,
|
||||
"no-non-null-assertion": true,
|
||||
"no-shadowed-variable": true,
|
||||
"no-string-literal": false,
|
||||
"no-string-throw": true,
|
||||
"no-switch-case-fall-through": true,
|
||||
"no-trailing-whitespace": true,
|
||||
"no-unnecessary-initializer": true,
|
||||
"no-unused-expression": true,
|
||||
"no-use-before-declare": true,
|
||||
"no-var-keyword": true,
|
||||
"object-literal-sort-keys": false,
|
||||
"one-line": [
|
||||
true,
|
||||
"check-open-brace",
|
||||
"check-catch",
|
||||
"check-else",
|
||||
"check-whitespace"
|
||||
],
|
||||
"prefer-const": true,
|
||||
"quotemark": [
|
||||
true,
|
||||
"single"
|
||||
],
|
||||
"radix": true,
|
||||
"semicolon": [
|
||||
true,
|
||||
"always"
|
||||
],
|
||||
"triple-equals": [
|
||||
true,
|
||||
"allow-null-check"
|
||||
],
|
||||
"typedef-whitespace": [
|
||||
true,
|
||||
{
|
||||
"call-signature": "nospace",
|
||||
"index-signature": "nospace",
|
||||
"parameter": "nospace",
|
||||
"property-declaration": "nospace",
|
||||
"variable-declaration": "nospace"
|
||||
}
|
||||
],
|
||||
"unified-signatures": true,
|
||||
"variable-name": false,
|
||||
"whitespace": [
|
||||
true,
|
||||
"check-branch",
|
||||
"check-decl",
|
||||
"check-operator",
|
||||
"check-separator",
|
||||
"check-type"
|
||||
],
|
||||
"directive-selector": [
|
||||
true,
|
||||
"attribute",
|
||||
"app",
|
||||
"camelCase"
|
||||
],
|
||||
"component-selector": [
|
||||
true,
|
||||
"element",
|
||||
"app",
|
||||
"kebab-case"
|
||||
],
|
||||
"no-output-on-prefix": true,
|
||||
"use-input-property-decorator": true,
|
||||
"use-output-property-decorator": true,
|
||||
"use-host-property-decorator": true,
|
||||
"no-input-rename": true,
|
||||
"no-output-rename": true,
|
||||
"use-life-cycle-interface": true,
|
||||
"use-pipe-transform-interface": true,
|
||||
"component-class-suffix": true,
|
||||
"directive-class-suffix": true
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Vendored
-2
@@ -1,2 +0,0 @@
|
||||
/// <reference path="type.d.ts" />
|
||||
import './index.scss';
|
||||
@@ -1,13 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<script src="FrontblockLib.js"></script>
|
||||
<meta charset="UTF-8">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<root></root>
|
||||
</body>
|
||||
</html>
|
||||
-897
@@ -1,897 +0,0 @@
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
font-family: "Open Sans","Helvetica Neue",Helvetica,Arial,sans-serif; }
|
||||
|
||||
a {
|
||||
text-decoration: none; }
|
||||
|
||||
.break-word {
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.text-light {
|
||||
font-weight: 300; }
|
||||
|
||||
.monospace {
|
||||
font-family: monospace;
|
||||
font-size: 90%
|
||||
}
|
||||
|
||||
.text-bold {
|
||||
font-weight: bold; }
|
||||
|
||||
.row {
|
||||
}
|
||||
.row--align-v-center {
|
||||
align-items: center; }
|
||||
.row--align-h-center {
|
||||
justify-content: center; }
|
||||
|
||||
.grid {
|
||||
position: relative;
|
||||
display: grid;
|
||||
grid-template-columns: 100%;
|
||||
grid-template-rows: 50px 1fr 50px;
|
||||
grid-template-areas: 'header' 'main' 'footer';
|
||||
height: 100vh;
|
||||
overflow-x: hidden; }
|
||||
.grid--noscroll {
|
||||
overflow-y: hidden; }
|
||||
|
||||
.header {
|
||||
grid-area: header;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background-color: #F9FAFC; }
|
||||
.header__menu {
|
||||
position: fixed;
|
||||
padding: 13px;
|
||||
left: 12px;
|
||||
background-color: #DADAE3;
|
||||
border-radius: 50%;
|
||||
z-index: 1; }
|
||||
.header__menu:hover {
|
||||
cursor: pointer; }
|
||||
.header__search {
|
||||
margin-left: 55px;
|
||||
font-size: 20px;
|
||||
color: #777; }
|
||||
.header__input {
|
||||
border: none;
|
||||
background: transparent;
|
||||
padding: 12px;
|
||||
font-size: 20px;
|
||||
color: #777; }
|
||||
.header__input:focus {
|
||||
outline: none;
|
||||
border: none; }
|
||||
.header__avatar {
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
border-radius: 50%;
|
||||
border: 2px solid rgba(255, 255, 255, 0.2);
|
||||
position: relative;
|
||||
margin: 0 26px;
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
cursor: pointer; }
|
||||
.header__avatar:after {
|
||||
position: absolute;
|
||||
content: "";
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
background: none;
|
||||
border-left: 2px solid #777;
|
||||
border-bottom: 2px solid #777;
|
||||
transform: rotate(-45deg) translateY(-50%);
|
||||
top: 50%;
|
||||
right: -18px; }
|
||||
|
||||
.dropdown {
|
||||
position: absolute;
|
||||
top: 54px;
|
||||
right: -16px;
|
||||
width: 220px;
|
||||
height: auto;
|
||||
z-index: 1;
|
||||
background-color: #fff;
|
||||
border-radius: 4px;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
transition: all .3s;
|
||||
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 0 0 1px rgba(0, 0, 0, 0.08); }
|
||||
.dropdown__list {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style-type: none; }
|
||||
.dropdown__list-item {
|
||||
padding: 12px 24px;
|
||||
color: #777;
|
||||
text-transform: capitalize; }
|
||||
.dropdown__list-item:hover {
|
||||
background-color: rgba(0, 0, 0, 0.1); }
|
||||
.dropdown__icon {
|
||||
color: #1BBAE1; }
|
||||
.dropdown__title {
|
||||
margin-left: 10px; }
|
||||
.dropdown:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
top: -6px;
|
||||
right: 30px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 4px solid transparent;
|
||||
border-right: 4px solid transparent;
|
||||
border-bottom: 6px solid #FFF; }
|
||||
.dropdown--active {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
transform: translateY(0); }
|
||||
|
||||
.sidenav {
|
||||
position: fixed;
|
||||
grid-area: sidenav;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
background-color: #394263;
|
||||
color: #FFF;
|
||||
width: 220px;
|
||||
transform: translateX(-245px);
|
||||
transition: all .6s ease-in-out;
|
||||
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 0 0 1px rgba(0, 0, 0, 0.08);
|
||||
z-index: 2; }
|
||||
.sidenav__brand {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 16px;
|
||||
height: 50px;
|
||||
background-color: rgba(0, 0, 0, 0.15); }
|
||||
.sidenav__brand-icon {
|
||||
margin-top: 2px;
|
||||
font-size: 14px;
|
||||
color: rgba(255, 255, 255, 0.5); }
|
||||
.sidenav__brand-close {
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
top: 8px;
|
||||
visibility: visible;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
cursor: pointer; }
|
||||
.sidenav__brand-link {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: #FFF;
|
||||
margin: 0 15px;
|
||||
letter-spacing: 1.5px; }
|
||||
.sidenav__profile {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-height: 90px;
|
||||
background-color: rgba(255, 255, 255, 0.1); }
|
||||
.sidenav__profile-avatar {
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
border-radius: 50%;
|
||||
border: 2px solid rgba(255, 255, 255, 0.2);
|
||||
height: 64px;
|
||||
width: 64px;
|
||||
margin: 0 15px; }
|
||||
.sidenav__profile-title {
|
||||
font-size: 17px;
|
||||
letter-spacing: 1px; }
|
||||
.sidenav__arrow {
|
||||
position: absolute;
|
||||
content: "";
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
top: 50%;
|
||||
right: 20px;
|
||||
border-left: 2px solid rgba(255, 255, 255, 0.5);
|
||||
border-bottom: 2px solid rgba(255, 255, 255, 0.5);
|
||||
transform: translateY(-50%) rotate(225deg); }
|
||||
.sidenav__sublist {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 10px 0 0; }
|
||||
.sidenav--active {
|
||||
transform: translateX(0); }
|
||||
|
||||
.navlist {
|
||||
width: 220px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background-color: #394263;
|
||||
list-style-type: none; }
|
||||
.navlist__heading {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 16px 16px 3px;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
text-transform: uppercase;
|
||||
font-size: 15px; }
|
||||
.navlist__subheading {
|
||||
position: relative;
|
||||
padding: 10px 30px;
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
text-transform: capitalize; }
|
||||
.navlist__subheading-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 12px;
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
width: 12px; }
|
||||
.navlist__subheading-title {
|
||||
margin: 0 15px; }
|
||||
.navlist__subheading:after {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 6px;
|
||||
width: 6px;
|
||||
top: 17px;
|
||||
right: 25px;
|
||||
border-left: 1px solid rgba(255, 255, 255, 0.5);
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.5);
|
||||
transform: rotate(225deg);
|
||||
transition: all .2s; }
|
||||
.navlist__subheading:hover {
|
||||
background-color: #303753;
|
||||
cursor: pointer; }
|
||||
.navlist__subheading--open {
|
||||
background-color: #303753; }
|
||||
.navlist__subheading--open:after {
|
||||
transform: rotate(315deg); }
|
||||
.navlist .sublist {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
list-style-type: none;
|
||||
background-color: #262c43;
|
||||
visibility: visible;
|
||||
overflow: hidden;
|
||||
max-height: 220px;
|
||||
transition: all .4s ease-in-out; }
|
||||
.navlist .sublist__item {
|
||||
padding: 8px;
|
||||
text-transform: capitalize;
|
||||
padding: 8px 30px;
|
||||
color: #D3D3D3; }
|
||||
.navlist .sublist__item:first-child {
|
||||
padding-top: 15px; }
|
||||
.navlist .sublist__item:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
cursor: pointer; }
|
||||
.navlist .sublist--hidden {
|
||||
visibility: hidden;
|
||||
max-height: 0; }
|
||||
|
||||
.errorDisplay {
|
||||
background: rgba(180, 55, 87, 0.5);
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.main {
|
||||
grid-area: main;
|
||||
background-color: #EAEDF1;
|
||||
color: #394263; }
|
||||
.main__cards {
|
||||
display: block;
|
||||
column-count: 1;
|
||||
column-gap: 20px;
|
||||
margin: 20px; }
|
||||
|
||||
.main-header {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
height: 250px;
|
||||
color: #FFF;
|
||||
background-size: cover;
|
||||
margin-bottom: 20px; }
|
||||
.main-header__intro-wrapper {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 160px;
|
||||
padding: 12px 30px;
|
||||
background: rgba(255, 255, 255, 0.12);
|
||||
font-size: 26px;
|
||||
letter-spacing: 1px; }
|
||||
.main-header__welcome {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center; }
|
||||
.main-header__welcome-title {
|
||||
margin-bottom: 8px;
|
||||
font-size: 26px; }
|
||||
.main-header__welcome-subtitle {
|
||||
font-size: 18px; }
|
||||
|
||||
.quickview {
|
||||
display: grid;
|
||||
grid-auto-flow: column;
|
||||
grid-gap: 60px; }
|
||||
.quickview__item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column; }
|
||||
.quickview__item-total {
|
||||
margin-bottom: 2px;
|
||||
font-size: 32px; }
|
||||
.quickview__item-description {
|
||||
font-size: 16px;
|
||||
text-align: center; }
|
||||
|
||||
.main-overview {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(265px, 1fr));
|
||||
grid-auto-rows: 94px;
|
||||
grid-gap: 30px;
|
||||
margin: 20px; }
|
||||
|
||||
.overviewcard {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 12px;
|
||||
background-color: #FFF;
|
||||
transform: translateY(0);
|
||||
transition: all .3s; }
|
||||
.overviewcard-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 60px;
|
||||
width: 60px;
|
||||
border-radius: 50%;
|
||||
font-size: 21px;
|
||||
color: #fff; }
|
||||
.overviewcard-icon--document {
|
||||
background-color: #e67e22; }
|
||||
.overviewcard-icon--calendar {
|
||||
background-color: #27ae60; }
|
||||
.overviewcard-icon--mail {
|
||||
background-color: #e74c3c; }
|
||||
.overviewcard-icon--photo {
|
||||
background-color: #af64cc; }
|
||||
.overviewcard-description {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center; }
|
||||
.overviewcard-title {
|
||||
font-size: 18px;
|
||||
color: #1BBAE1;
|
||||
margin: 0; }
|
||||
.overviewcard-subtitle {
|
||||
margin: 2px;
|
||||
color: #777; }
|
||||
.overviewcard:hover {
|
||||
transform: translateY(-3px);
|
||||
box-shadow: 0 5px 5px rgba(0, 0, 0, 0.1);
|
||||
cursor: pointer; }
|
||||
|
||||
.card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
background-color: #fff;
|
||||
margin-bottom: 20px;
|
||||
-webkit-column-break-inside: avoid; }
|
||||
.card__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 50px;
|
||||
background-color: #394263;
|
||||
color: #FFF; }
|
||||
.card__header-title {
|
||||
margin: 0 20px;
|
||||
font-size: 20px;
|
||||
letter-spacing: 1.2px; }
|
||||
.card__header-link {
|
||||
font-size: 16px;
|
||||
color: #1BBAE1;
|
||||
letter-spacing: normal;
|
||||
display: inline-block; }
|
||||
.card__main {
|
||||
position: relative;
|
||||
padding-right: 20px;
|
||||
background-color: #FFF; }
|
||||
.card__main:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 120px;
|
||||
bottom: 0;
|
||||
width: 2px;
|
||||
background-color: #f0f0f0; }
|
||||
.card__secondary {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
|
||||
grid-auto-rows: 100px;
|
||||
grid-gap: 25px;
|
||||
padding: 20px;
|
||||
background-color: #FFF; }
|
||||
.card__photo {
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
background-color: slategray;
|
||||
transform: scale(1);
|
||||
transition: transform .3s ease-in-out;
|
||||
width: 100%;
|
||||
height: 100%; }
|
||||
.card__photo:hover {
|
||||
transform: scale(1.1);
|
||||
cursor: pointer; }
|
||||
.card__photo-wrapper {
|
||||
overflow: hidden; }
|
||||
.card__row {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
margin: 15px 15px 15px; }
|
||||
.card__icon {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
content: "";
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
top: 0;
|
||||
left: 121px;
|
||||
transform: translateX(-50%);
|
||||
border-radius: 50%;
|
||||
color: #FFF;
|
||||
background-color: #1BBAE1;
|
||||
z-index: 1; }
|
||||
.card__row:nth-child(even) .card__icon {
|
||||
background-color: #e74c3c; }
|
||||
.card__time {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
justify-content: flex-end;
|
||||
max-width: 80px;
|
||||
margin-left: 15px;
|
||||
text-align: right;
|
||||
font-size: 14px;
|
||||
line-height: 2; }
|
||||
.card__detail {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
padding-left: 12px;
|
||||
margin-left: 48px;
|
||||
transform: translateX(0);
|
||||
transition: all .3s; }
|
||||
.card__detail:hover {
|
||||
background-color: #f0f0f0;
|
||||
transform: translateX(4px);
|
||||
cursor: pointer; }
|
||||
.card__source {
|
||||
line-height: 1.8;
|
||||
color: #1BBAE1; }
|
||||
.card__note {
|
||||
margin: 10px 0;
|
||||
color: #777; }
|
||||
.card--finance {
|
||||
position: relative; }
|
||||
|
||||
.settings {
|
||||
display: flex;
|
||||
margin: 8px;
|
||||
align-self: flex-start;
|
||||
background-color: rgba(255, 255, 255, 0.5);
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
border-radius: 2px; }
|
||||
.settings__block {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 4px;
|
||||
color: #394263;
|
||||
font-size: 11px; }
|
||||
.settings__block:not(:last-child) {
|
||||
border-right: 1px solid rgba(0, 0, 0, 0.1); }
|
||||
.settings__icon {
|
||||
padding: 0px 3px;
|
||||
font-size: 12px; }
|
||||
.settings__icon:hover {
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
cursor: pointer; }
|
||||
.settings:hover {
|
||||
background-color: #fff;
|
||||
cursor: pointer; }
|
||||
|
||||
.documents {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(105px, 1fr));
|
||||
grid-auto-rows: 214px;
|
||||
grid-gap: 12px;
|
||||
height: auto;
|
||||
background-color: #FFF; }
|
||||
|
||||
.document {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 15px 0 0;
|
||||
flex-direction: column; }
|
||||
.document__img {
|
||||
width: 105px;
|
||||
height: 136px;
|
||||
background-size: cover;
|
||||
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.12), 0 1px 5px 0 rgba(0, 0, 0, 0.2);
|
||||
cursor: pointer;
|
||||
transition: transform .3s ease; }
|
||||
.document__img:hover {
|
||||
transform: translateY(-4px); }
|
||||
.document__title {
|
||||
margin: 8px 0 2px;
|
||||
color: #777; }
|
||||
.document__date {
|
||||
font-size: 10px; }
|
||||
|
||||
#chartdiv {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
font-size: 11px;
|
||||
min-width: 0; }
|
||||
|
||||
.footer {
|
||||
grid-area: footer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 16px;
|
||||
color: #777;
|
||||
background-color: #FFF; }
|
||||
.footer__copyright {
|
||||
color: #1BBAE1; }
|
||||
.footer__icon {
|
||||
color: #e74c3c; }
|
||||
.footer__signature {
|
||||
color: #1BBAE1;
|
||||
cursor: pointer;
|
||||
font-weight: bold; }
|
||||
|
||||
@media only screen and (min-width: 46.875em) {
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: 220px calc(100% - 220px);
|
||||
grid-template-rows: 0px 1fr 50px;
|
||||
grid-template-areas: 'sidenav header' 'sidenav main' 'sidenav footer';
|
||||
height: 100vh; }
|
||||
.grid__no-head {
|
||||
display: grid;
|
||||
grid-template-columns: 220px calc(100% - 220px);
|
||||
grid-template-rows: 0px 1fr 0px;
|
||||
grid-template-areas: 'sidenav header' 'sidenav main' 'sidenav footer';
|
||||
height: calc(100%); }
|
||||
.sidenav {
|
||||
position: relative;
|
||||
transform: translateX(0); }
|
||||
.sidenav__brand-close {
|
||||
visibility: hidden; }
|
||||
.main-header__intro-wrapper {
|
||||
padding: 0 30px; }
|
||||
.header__menu {
|
||||
display: none; }
|
||||
.header__search {
|
||||
margin-left: 20px; }
|
||||
.header__avatar {
|
||||
width: 40px;
|
||||
height: 40px; } }
|
||||
|
||||
@media only screen and (min-width: 65.625em) {
|
||||
.main__cards {
|
||||
column-count: 2; }
|
||||
.main-header__intro-wrapper {
|
||||
flex-direction: row; }
|
||||
.main-header__welcome {
|
||||
align-items: flex-start; } }
|
||||
|
||||
table {
|
||||
border-spacing: 1;
|
||||
border-collapse: collapse;
|
||||
background: white;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
}
|
||||
table * {
|
||||
position: relative;
|
||||
}
|
||||
table td, table th {
|
||||
padding-left: 8px;
|
||||
}
|
||||
table thead tr {
|
||||
height: 50px;
|
||||
background: #394263;
|
||||
}
|
||||
table tbody tr {
|
||||
height: 50px;
|
||||
}
|
||||
table tbody tr:last-child {
|
||||
border: 0;
|
||||
}
|
||||
table td, table th {
|
||||
text-align: left;
|
||||
}
|
||||
table td.l, table th.l {
|
||||
text-align: right;
|
||||
}
|
||||
table td.c, table th.c {
|
||||
text-align: center;
|
||||
}
|
||||
table td.r, table th.r {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
.table100-head th{
|
||||
color: #fff;
|
||||
line-height: 1.2;
|
||||
font-weight: unset;
|
||||
}
|
||||
|
||||
tbody tr:nth-child(even) {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
tbody tr {
|
||||
font-size: 15px;
|
||||
color: #808080;
|
||||
line-height: 1.2;
|
||||
font-weight: unset;
|
||||
}
|
||||
|
||||
tbody tr:hover {
|
||||
color: #555555;
|
||||
background-color: #f5f5f5;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.column1 {
|
||||
padding-left: 40px;
|
||||
width: 280px;
|
||||
}
|
||||
|
||||
.column2 {
|
||||
width: 280px;
|
||||
}
|
||||
|
||||
.column3 {
|
||||
width: 280px;
|
||||
}
|
||||
|
||||
.column4 {
|
||||
width: 280px;
|
||||
}
|
||||
|
||||
.column5 {
|
||||
width: 170px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.column6 {
|
||||
width: 222px;
|
||||
text-align: right;
|
||||
padding-right: 62px;
|
||||
}
|
||||
|
||||
|
||||
@media screen and (max-width: 1050px) {
|
||||
table {
|
||||
display: block;
|
||||
}
|
||||
table > *, table tr, table td, table th {
|
||||
display: block;
|
||||
}
|
||||
table thead {
|
||||
display: none;
|
||||
}
|
||||
table tbody tr {
|
||||
height: auto;
|
||||
padding: 37px 0;
|
||||
}
|
||||
table tbody tr td {
|
||||
padding-left: 40% !important;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
table tbody tr td:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
table tbody tr td:before {
|
||||
font-size: 14px;
|
||||
color: #999999;
|
||||
line-height: 1.2;
|
||||
font-weight: unset;
|
||||
position: absolute;
|
||||
width: 40%;
|
||||
left: 30px;
|
||||
top: 0;
|
||||
}
|
||||
table.t1 tbody tr td:nth-child(1):before {
|
||||
content: "Address";
|
||||
}
|
||||
table.t1 tbody tr td:nth-child(2):before {
|
||||
content: "Balance";
|
||||
}
|
||||
table.t1 tbody tr td:nth-child(3):before {
|
||||
content: "Unconfirmed";
|
||||
}
|
||||
table.t1 tbody tr td:nth-child(4):before {
|
||||
content: "Total";
|
||||
}
|
||||
|
||||
|
||||
table.t2 tbody tr td:nth-child(1):before {
|
||||
content: "Type";
|
||||
}
|
||||
table.t2 tbody tr td:nth-child(2):before {
|
||||
content: "Value";
|
||||
}
|
||||
|
||||
|
||||
table.t3 tbody tr:nth-child(1) td:nth-child(1) {
|
||||
display: none;
|
||||
}
|
||||
table.t3 tbody tr:nth-child(1) td:nth-child(2):before {
|
||||
content: "To";
|
||||
|
||||
}
|
||||
table.t3 tbody tr:nth-child(2) td:nth-child(1){
|
||||
display: none;
|
||||
}
|
||||
table.t3 tbody tr:nth-child(2) td:nth-child(2):before {
|
||||
content: "Amount";
|
||||
|
||||
}
|
||||
|
||||
.column4,
|
||||
.column5,
|
||||
.column6 {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.column4,
|
||||
.column5,
|
||||
.column6,
|
||||
.column1,
|
||||
.column2,
|
||||
.column3 {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
tbody tr {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 576px) {
|
||||
.container-table100 {
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.qtip {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
color: #3bb4e5;
|
||||
border-bottom: 0.05em dotted #3bb4e5;
|
||||
box-sizing: border-box;
|
||||
font-style: normal;
|
||||
transition:all .25s ease-in-out;
|
||||
z-index: 10000
|
||||
}
|
||||
.qtip:hover {color:#069;border-bottom:0.05em dotted #069}
|
||||
/*the tip*/
|
||||
.qtip:before {
|
||||
content: attr(data-tip);
|
||||
font-size: 14px;
|
||||
position: absolute;
|
||||
background: rgba(10, 20, 30, 0.85);
|
||||
color: #fff;
|
||||
line-height: 1.2em;
|
||||
padding: 0.5em;
|
||||
font-style: normal;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
|
||||
min-width: 120px;
|
||||
text-align: center;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: all .3s ease-in-out;
|
||||
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5);
|
||||
font-family: sans-serif;
|
||||
letter-spacing: 0;
|
||||
font-weight: 600
|
||||
}
|
||||
.qtip:after {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-style: solid;
|
||||
content: '';
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: all .3s ease-in-out
|
||||
}
|
||||
.qtip:hover:before,
|
||||
.qtip:hover:after {
|
||||
visibility: visible;
|
||||
opacity: 1
|
||||
}
|
||||
/*top*/
|
||||
.qtip.tip-top:before {
|
||||
top: 0;
|
||||
left: 50%;
|
||||
transform: translate(-50%, calc(-100% - 8px));
|
||||
box-sizing: border-box;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.qtip.tip-top:after {
|
||||
border-width: 8px 8px 0 8px;
|
||||
border-color: rgba(10, 20, 30, 0.85) transparent transparent transparent;
|
||||
top: -8px;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
}
|
||||
/*bottom*/
|
||||
.qtip.tip-bottom:before {
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
transform: translate(-50%, calc(100% + 8px));
|
||||
box-sizing: border-box;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.qtip.tip-bottom:after {
|
||||
border-width: 0 8px 8px 8px;
|
||||
border-color: transparent transparent rgba(10, 20, 30, 0.85) transparent;
|
||||
bottom: -8px;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
}
|
||||
/*left*/
|
||||
.qtip.tip-left:before {
|
||||
left: 0;
|
||||
top: 50%;
|
||||
transform: translate(calc(-100% - 8px), -50%);
|
||||
box-sizing: border-box;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.qtip.tip-left:after {
|
||||
border-width: 8px 0 8px 8px;
|
||||
border-color: transparent transparent transparent rgba(10, 20, 30, 0.85);
|
||||
left: -8px;
|
||||
top: 50%;
|
||||
transform: translate(0, -50%);
|
||||
}
|
||||
/*right*/
|
||||
.qtip.tip-right:before {
|
||||
right: 0;
|
||||
top: 50%;
|
||||
transform: translate(calc(100% + 8px), -50%);
|
||||
box-sizing: border-box;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.qtip.tip-right:after {
|
||||
border-width: 8px 8px 8px 0;
|
||||
border-color: transparent rgba(10, 20, 30, 0.85) transparent transparent;
|
||||
right: -8px;
|
||||
top: 50%;
|
||||
transform: translate(0, -50%);
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
import './index.scss'
|
||||
import angular = require('angular')
|
||||
import uiRouter from '@uirouter/angularjs'
|
||||
import router from './config/routes.config'
|
||||
import components from './components'
|
||||
import views from './views'
|
||||
import filters from './filters'
|
||||
|
||||
angular
|
||||
.module('app', [
|
||||
uiRouter,
|
||||
components,
|
||||
views,
|
||||
filters
|
||||
])
|
||||
.config(router)
|
||||
|
||||
angular.bootstrap(document, ['app'])
|
||||
|
||||
if (module.hot) {
|
||||
module.hot.accept()
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
class Log {
|
||||
info(info) {
|
||||
alert(info)
|
||||
}
|
||||
}
|
||||
|
||||
export default Log
|
||||
Vendored
-2
@@ -1,2 +0,0 @@
|
||||
declare const _default: string;
|
||||
export default _default;
|
||||
@@ -1,7 +0,0 @@
|
||||
import angular = require('angular')
|
||||
import TodoList from './todo-list'
|
||||
|
||||
export default angular
|
||||
.module('wallets', [])
|
||||
.component('todolist', TodoList)
|
||||
.name
|
||||
Vendored
-13
@@ -1,13 +0,0 @@
|
||||
export default class TodoListCtrl {
|
||||
private bip32;
|
||||
static $inject: string[];
|
||||
todos: any[];
|
||||
id: number;
|
||||
todo: string;
|
||||
todoTypes: string[];
|
||||
visibleType: string;
|
||||
constructor(bip32: any);
|
||||
handleSubmit(e: any): void;
|
||||
toggleTodo(curTodo: any): void;
|
||||
toggleType(type: string): void;
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
export default class TodoListCtrl {
|
||||
static $inject = ['bip32']
|
||||
|
||||
todos = []
|
||||
id = 0
|
||||
todo: string
|
||||
todoTypes = ['All', 'Todo', 'Done']
|
||||
visibleType = 'All'
|
||||
|
||||
constructor(private bip32) {
|
||||
|
||||
}
|
||||
|
||||
handleSubmit(e): void {
|
||||
if (e.keyCode !== 13) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
toggleType(type: string): void {
|
||||
this.visibleType = type
|
||||
}
|
||||
}
|
||||
Vendored
-7
@@ -1,7 +0,0 @@
|
||||
import ctrl from './controller';
|
||||
import './index.scss';
|
||||
declare const _default: {
|
||||
template: string;
|
||||
controller: typeof ctrl;
|
||||
};
|
||||
export default _default;
|
||||
@@ -1,9 +0,0 @@
|
||||
<div class="todo-list">
|
||||
<ul class="todos-type">
|
||||
<li ng-repeat="type in $ctrl.todoTypes" ng-click="$ctrl.toggleType(type)" ng-class="{active:type===$ctrl.visibleType}">{{ type }}</li>
|
||||
</ul>
|
||||
<input type="text" class="input" ng-model="$ctrl.todo" ng-keyup="$ctrl.handleSubmit($event)" />
|
||||
<ul class="todos">
|
||||
<li ng-repeat="todo in $ctrl.todos | todosVisible:$ctrl.visibleType" ng-click="$ctrl.toggleTodo(todo)" ng-style="{textDecoration: todo.complete ? 'line-through' : 'none'}">{{ todo.text }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -1,38 +0,0 @@
|
||||
.todo-list {
|
||||
.input {
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
width: 200px;
|
||||
margin: 20px auto;
|
||||
padding: 5px 8px;
|
||||
background-color: #fff;
|
||||
border: 1px solid #d9d9d9;
|
||||
border-radius: 4px;
|
||||
transition: all .3s;
|
||||
}
|
||||
@at-root {
|
||||
.todos-type {
|
||||
display: table;
|
||||
margin: 0 auto;
|
||||
li {
|
||||
display: table-cell;
|
||||
padding: 3px 8px;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
color: #108ee9;
|
||||
}
|
||||
&.active {
|
||||
color: #108ee9;
|
||||
}
|
||||
}
|
||||
}
|
||||
.todos {
|
||||
width: 200px;
|
||||
margin: 0 auto;
|
||||
li {
|
||||
line-height: 1.8;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
import ctrl from './controller'
|
||||
const html = require('./index.html').default
|
||||
import './index.scss'
|
||||
|
||||
export default {
|
||||
template: html,
|
||||
controller: ctrl
|
||||
}
|
||||
Vendored
-6
@@ -1,6 +0,0 @@
|
||||
declare const _default: {
|
||||
name: string;
|
||||
url: string;
|
||||
component: string;
|
||||
};
|
||||
export default _default;
|
||||
@@ -1,5 +0,0 @@
|
||||
export default {
|
||||
name: 'todolist',
|
||||
url: '/todolist',
|
||||
component: 'todolist'
|
||||
}
|
||||
@@ -137,7 +137,7 @@ const angularPage = {
|
||||
|
||||
const FrontblockLib = {
|
||||
mode: 'production',
|
||||
entry: path.resolve(__dirname, 'lib/backendsrc/FrontblockLib.js'),
|
||||
entry: path.resolve(__dirname, 'lib/FrontblockLib.js'),
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'static'),
|
||||
filename: 'FrontblockLib.js',
|
||||
@@ -180,6 +180,6 @@ const angularPage = {
|
||||
|
||||
|
||||
module.exports = [
|
||||
Object.assign({}, angularPage),
|
||||
//Object.assign({}, angularPage),
|
||||
Object.assign({}, FrontblockLib),
|
||||
];
|
||||
+1
-1
@@ -8,6 +8,6 @@
|
||||
"outDir": "./lib",
|
||||
"strict": true
|
||||
},
|
||||
"include": ["backendsrc", "src"],
|
||||
"include": ["src/backend"],
|
||||
"exclude": ["node_modules", "**/__tests__/*"],
|
||||
}
|
||||
Reference in New Issue
Block a user