This commit is contained in:
Eugene Pankov 2016-12-23 10:06:53 +01:00
commit 98fea7b102
69 changed files with 3066 additions and 0 deletions

23
.gitignore vendored Normal file
View file

@ -0,0 +1,23 @@
app/node_modules
app/src/daemonInstaller.generated.js
app/assets/webpack
app/elements-native.node
node_modules
typings
build/files.wxs
native/windows/build
native/mac/build
native/linux/build
native/build
dist
driver/build
driver/obj
*.xcworkspacedata
*.xcuserstate
*.wixpdb
coverage
.nyc_output

108
.gitlab-ci.yml Normal file
View file

@ -0,0 +1,108 @@
cache:
untracked: true
key: "$CI_BUILD_REF_NAME"
paths:
- app/node_modules
- node_modules
- typings
stages:
- Build
- Test
- Package
- Upload
Build:
stage: Build
script:
- npm prune
- npm install
- cd app; npm prune && npm install; cd ..
- ./node_modules/.bin/typings install
tags:
- Linux
artifacts:
paths:
- node_modules
- typings
- app
Test:
stage: Test
dependencies:
- Build
script:
- apt-get install -y xvfb libxtst6 libxss1 libgconf2-4 libnss3 libasound2
- xvfb-run -a make coverage
tags:
- Linux
Windows package:
stage: Package
dependencies:
- Build
script:
- call npm install
- call npm install webpack # regenerate the .cmd launcher
- cd app
- call npm install
- cd ..
- call ./node_modules/.bin/webpack.cmd --progress
- call make package-windows
- call copy dist\Elements-Electron.exe Elements-Windows-%CI_BUILD_REF_NAME%.exe
artifacts:
name: Elements-Windows-%CI_BUILD_REF_NAME%
paths:
- Elements-Windows-%CI_BUILD_REF_NAME%.exe
tags:
- Windows
macOS package:
stage: Package
dependencies:
- Build
script:
- npm install
- rm -rf node_modules/electron-macos-sign || true
- cp -r node_modules/electron-osx-sign node_modules/electron-macos-sign
- cd app; npm install; cd ..
- ./node_modules/.bin/webpack --progress
- security unlock-keychain -p rjvg login.keychain
- make package-mac
- cp dist/Elements-Electron.pkg ./Elements-macOS-$CI_BUILD_REF_NAME.pkg
artifacts:
name: Elements-macOS-$CI_BUILD_REF_NAME
paths:
- Elements-macOS-$CI_BUILD_REF_NAME.pkg
tags:
- macOS
Linux package:
stage: Package
dependencies:
- Build
script:
- npm install
- cd app; npm install; cd ..
- ./node_modules/.bin/webpack --progress
- make build-linux
- cp dist/ELEMENTS*.AppImage ./Elements-Linux-$CI_BUILD_REF_NAME.AppImage
artifacts:
name: Elements-Linux-$CI_BUILD_REF_NAME
paths:
- Elements-Linux-$CI_BUILD_REF_NAME.AppImage
tags:
- Linux
Upload packages:
stage: Upload
dependencies:
- Windows package
- macOS package
- Linux package
script:
- scp Elements-Windows-$CI_BUILD_REF_NAME.exe root@cloud.elements.tv:/mnt/elements/www/clients/
- scp Elements-macOS-$CI_BUILD_REF_NAME.pkg root@cloud.elements.tv:/mnt/elements/www/clients/
- scp Elements-Linux-$CI_BUILD_REF_NAME.AppImage root@cloud.elements.tv:/mnt/elements/www/clients/
tags:
- Local

97
Makefile Normal file
View file

@ -0,0 +1,97 @@
MAC_WS="/tmp/elements-build"
MAC_OUTPUT="./dist/Elements-Electron.pkg"
FULL_VERSION=$(shell python -c 'import subprocess; v = subprocess.check_output("git describe --tags --long", shell=True).strip()[1:]; print(v.split("-0-g")[0])')
SHORT_VERSION=$(shell python -c 'import subprocess; v = subprocess.check_output("git describe --tags --long", shell=True).strip()[1:].split("-")[0]; print(v)')
all: run
run:
DEV=1 ./node_modules/.bin/electron ./app
lint:
tslint -c tslint.json app/src/*.ts app/src/**/*.ts
build:
DEV=1 ./node_modules/.bin/webpack --progress
watch:
DEV=1 ./node_modules/.bin/webpack --progress -w
build-native-windows:
echo :: Building native extensions
rm -r ./native/windows/build || true
cd native/windows && node-gyp rebuild --target=1.4.12 --arch=x64 --dist-url=https://atom.io/download/atom-shell
mkdir native/build || true
cp ./native/windows/build/Release/elements-native.node ./app/
build-native-mac:
echo :: Building native extensions
rm -r ./native/mac/build || true
cd native/mac && node-gyp rebuild --target=1.4.12 --arch=x64 --dist-url=https://atom.io/download/atom-shell
mkdir native/build || true
cp ./native/mac/build/Release/elements-native.node ./app/
build-native-linux:
echo :: Building native extensions
rm -r ./native/linux/build || true
cd native/linux && node-gyp rebuild --target=1.4.12 --arch=x64 --dist-url=https://atom.io/download/atom-shell
mkdir native/build || true
cp ./native/linux/build/Release/elements-native.node ./app/
build-windows: build-native-windows
echo :: Building application
./node_modules/.bin/build --dir --win --em.version=$(FULL_VERSION)
cp ./app/assets/img/disk.ico dist/win-unpacked/
build-mac: build-native-mac
echo :: Building application
./node_modules/.bin/build --dir --mac --em.version=$(FULL_VERSION)
build-linux: build-native-linux
echo :: Building application
./node_modules/.bin/build --linux --em.version=$(FULL_VERSION)
package-windows-app:
echo :: Building app MSI $(SHORT_VERSION)
heat dir dist/win-unpacked/ -cg Files -gg -scom -sreg -sfrag -srd -dr INSTALLDIR -var var.SourceDir -out build/files.wxs
candle -dSourceDir=dist\\win-unpacked -dProductVersion=$(SHORT_VERSION) -arch x64 -o dist/ build/files.wxs build/windows/elements.wxs
light -o dist/elements-app.msi dist/files.wixobj dist/elements.wixobj
build/windows/signtool.exe sign /f "build\\certificates\\Code Signing.p12" dist/elements-app.msi
package-windows-bundle:
echo :: Building installer
candle -dVersion=$(SHORT_VERSION) -ext WixBalExtension -arch x64 -o dist/build.wixobj build/windows/build.wxs
light -ext WixBalExtension -o bundle.exe dist/build.wixobj
insignia -ib bundle.exe -o engine.exe
build/windows/signtool.exe sign /f "build\\certificates\\Code Signing.p12" engine.exe
insignia -ab engine.exe bundle.exe -o dist/Elements-Electron.exe
build/windows/signtool.exe sign /f "build\\certificates\\Code Signing.p12" dist/Elements-Electron.exe
rm engine.exe bundle.exe || true
package-windows: build-windows package-windows-app package-windows-bundle
package-mac: driver-mac build-mac
rm -rf $(MAC_WS) || true
mkdir -p $(MAC_WS)
mkdir -p $(MAC_WS)/app/Applications
mkdir -p $(MAC_WS)/driver/Library/Extensions
cp -Rv dist/mac/ELEMENTS.app $(MAC_WS)/app/Applications/
cp -Rv dist/ElementsDriver.kext $(MAC_WS)/driver/Library/Extensions
pkgbuild --root $(MAC_WS)/app \
--component-plist ./build/mac/Elements.component.plist \
--version $(SHORT_VERSION) \
--scripts ./build/mac \
$(MAC_WS)/Elements.pkg
pkgbuild --root $(MAC_WS)/driver \
--component-plist ./build/mac/ElementsDriver.component.plist \
--scripts ./build/mac \
$(MAC_WS)/ElementsDriver.pkg
cp ./build/mac/AFPTuner.pkg $(MAC_WS)/
productbuild --distribution "./build/mac/Distribution.xml" \
--package-path $(MAC_WS) \
--version $(SHORT_VERSION) \
--sign "Developer ID Installer: Syslink GmbH (V4JSMC46SY)" \
$(MAC_OUTPUT)
.PHONY: run native build coverage

22
README.md Normal file
View file

@ -0,0 +1,22 @@
[![build status](http://ci.elements.tv/root/elements-benchmark/badges/master/build.svg)](http://ci.elements.tv/root/elements-benchmark/commits/master)
This repository hosts the ELEMENTS Benchmark
Build requirements:
* Windows: NodeJS, Windows SDK, WiX on $PATH, Cygwin with ``make`` on $PATH
* Mac: NodeJS, Xcode
* Linux: NodeJS
Preparing:
* ``npm install``
* ``typings install``
* ``webpack``
Building:
* Windows: ``make package-windows`` → ``dist/Elements-Electron.exe``
* Mac: ``make package-mac`` → ``dist/Elements-Electron.pkg``
* Linux: ``make package-linux`` → ``dist/Elements-Electron.AppImage``

58
app/assets/bootstrap/bootstrap.less vendored Normal file
View file

@ -0,0 +1,58 @@
// Core variables and mixins
@import "../../../node_modules/bootstrap/less/variables.less";
@import "variables.less";
@import "../../../node_modules/bootstrap/less/mixins.less";
//@import "mixin-overrides.less";
// Reset and dependencies
@import "../../../node_modules/bootstrap/less/normalize.less";
@import "../../../node_modules/bootstrap/less/print.less";
@import "../../../node_modules/bootstrap/less/glyphicons.less";
// Core CSS
@import "../../../node_modules/bootstrap/less/scaffolding.less";
@import "../../../node_modules/bootstrap/less/type.less";
@import "../../../node_modules/bootstrap/less/code.less";
@import "../../../node_modules/bootstrap/less/grid.less";
@import "../../../node_modules/bootstrap/less/tables.less";
@import "../../../node_modules/bootstrap/less/forms.less";
@import "../../../node_modules/bootstrap/less/buttons.less";
// Components
@import "../../../node_modules/bootstrap/less/component-animations.less";
@import "../../../node_modules/bootstrap/less/dropdowns.less";
@import "../../../node_modules/bootstrap/less/button-groups.less";
@import "../../../node_modules/bootstrap/less/input-groups.less";
@import "../../../node_modules/bootstrap/less/navs.less";
@import "../../../node_modules/bootstrap/less/navbar.less";
@import "../../../node_modules/bootstrap/less/breadcrumbs.less";
@import "../../../node_modules/bootstrap/less/pagination.less";
@import "../../../node_modules/bootstrap/less/pager.less";
@import "../../../node_modules/bootstrap/less/labels.less";
@import "../../../node_modules/bootstrap/less/badges.less";
@import "../../../node_modules/bootstrap/less/jumbotron.less";
@import "../../../node_modules/bootstrap/less/thumbnails.less";
@import "../../../node_modules/bootstrap/less/alerts.less";
@import "../../../node_modules/bootstrap/less/progress-bars.less";
@import "../../../node_modules/bootstrap/less/media.less";
@import "../../../node_modules/bootstrap/less/list-group.less";
@import "../../../node_modules/bootstrap/less/panels.less";
@import "../../../node_modules/bootstrap/less/responsive-embed.less";
@import "../../../node_modules/bootstrap/less/wells.less";
@import "../../../node_modules/bootstrap/less/close.less";
// Components w/ JavaScript
@import "../../../node_modules/bootstrap/less/modals.less";
@import "../../../node_modules/bootstrap/less/tooltip.less";
@import "../../../node_modules/bootstrap/less/popovers.less";
@import "../../../node_modules/bootstrap/less/carousel.less";
// Utility classes
@import "../../../node_modules/bootstrap/less/utilities.less";
@import "../../../node_modules/bootstrap/less/responsive-utilities.less";
@import "overrides.less";
body {
background: transparent;
}

View file

@ -0,0 +1,4 @@
// Core variables and mixins
@import "../../../node_modules/bootstrap/less/variables.less";
@import "variables.less";
@import "../../../node_modules/bootstrap/less/mixins.less";

View file

@ -0,0 +1,541 @@
@import (less, reference) "../../../node_modules/font-awesome/css/font-awesome.css";
.glyphicon:extend(.fa all) {
&.glyphicon-chevron-right:extend(.fa-chevron-right all) {};
&.glyphicon-chevron-left:extend(.fa-chevron-left all) {};
&.glyphicon-chevron-up:extend(.fa-chevron-up all) {};
&.glyphicon-chevron-down:extend(.fa-chevron-down all) {};
}
h4 {
margin-bottom: 5px;
}
a {
color: #EFEAB1;
transition: opacity 0.125s, background 0.125s, color0.125s ;
&:hover {
color: #FFF79A;
}
}
.block-element {
display: block;
}
textarea {
resize: vertical;
}
.btn {
border: none !important;
box-shadow: 0 1px 1px rgba(0,0,0,.125);
&:active {
outline: 5px auto @brand-info;
}
&:active,
&.active {
.box-shadow(@control-shadow-active);
}
-webkit-transition: all 0.125s ease-out;
-moz-transition: all 0.125s ease-out;
-ms-transition: all 0.125s ease-out;
-o-transition: all 0.125s ease-out;
transition: all 0.125s ease-out;
&[disabled] {
cursor: default !important;
}
}
.btn-ink {
background: transparent !important;
box-shadow: none;
&.btn-danger {
color: #FF4832;
}
&.btn-xs {
padding-top: 0;
padding-bottom: 0;
}
}
.btn-toolbar {
margin: 0;
.btn, .btn-group, [uib-dropdown] {
float: none;
}
> .btn-group > * {
float: left;
}
> .btn, > .btn-group, > [uib-dropdown] {
margin: 0 5px 5px 0px;
vertical-align: top;
> .btn {
margin: 0;
}
}
}
@media (max-width: @screen-xs-max) {
.btn-toolbar-collapsible {
.btn {
font-size: 0;
.fa::before, .caret {
font-size: @font-size-base;
}
}
}
}
[uib-dropdown] {
position: relative;
}
[uib-dropdown-menu], .dropdown-menu {
.box-shadow(@control-dropdown-shadow);
top: 25px;
> li > * {
display: block;
padding: 5px 20px;
clear: both;
font-weight: normal;
line-height: @line-height-base;
color: @dropdown-link-color;
white-space: nowrap;
&[disabled] {
color: #888;
cursor: not-allowed;
}
}
> li.disabled a {
color: #666;
&:hover {
color: #666;
}
}
}
[uib-dropdown-menu] > .active > * {
&,
&:hover,
&:focus {
color: @dropdown-link-active-color;
text-decoration: none;
outline: 0;
background-color: @dropdown-link-active-bg;
}
}
.form-control {
border: none;
&[checkbox] {
border: none;
background: transparent;
display: inline-block;
margin: @padding-base-vertical 0 0;
}
border-radius: 0;
.box-shadow(~"0 1px 1px rgba(0, 0, 0, 0.51)");
&:focus {
.box-shadow(~"0 1px 1px rgba(0, 0, 0, 0.51)");
}
.transition(0.25s background);
&::-webkit-input-placeholder {
font-style: italic;
}
}
.input-group {
.box-shadow(~"0 1px 1px rgba(0, 0, 0, 0.51)");
.form-control {
.box-shadow(none);
}
}
.input-group-addon {
border: none;
padding: 6px 8px;
}
@media (min-width: @screen-sm-min) {
.control-label {
font-size: 12px;
padding-top: 10px;
font-weight: normal;
}
}
.form-group .control-label {
font-size: 12px;
padding-top: 10px;
font-weight: bold;
color: #777;
}
label.form-control-static {
font-size: inherit;
}
.input-group {
width: 100%;
*:focus + .input-group-addon,
*:focus + .input-group-btn {
//border-bottom: 1px solid @brand-primary;
}
.input-group-addon, .input-group-btn {
border: none;
&.input-sm {
border-radius: 0;
}
a {
margin: 0 !important;
}
text-decoration: none !important;
}
}
.label {
font-size: 76%;
position: relative;
padding: 5px 4px 4px;
}
.list-group {
.box-shadow(@control-shadow);
}
.list-group-item {
border: none;
border-top: 1px solid @list-group-line-border;
cursor: default;
&:first-child {
border-top: none;
}
&.active {
color: #f7e61d;
border-right: 2px solid #f7e61d;
}
}
.list-group-item.combi {
padding: 0;
clear: both;
tr& {
a.main, .btn {
display: table-cell !important;
}
}
& > .main {
display: block;
h4 {
margin-top: 4px;
}
pre {
background: transparent;
margin: 0;
}
video-thumbnail, asset-thumbnail {
margin-right: 15px;
}
}
& > a.main {
cursor: pointer;
color: inherit;
}
& > a.main, & > a.btn, & > button, & > [uib-dropdown] > button {
&:hover,
&:focus {
text-decoration: none;
color: @list-group-link-hover-color;
background-color: @list-group-hover-bg;
}
}
& > a.btn, & > button, & > [uib-dropdown] > button {
background-color: @list-group-bg;
position: relative; // more z-index
z-index: 2;
display: block;
float: right;
border: none;
margin: 0;
box-shadow: none;
}
& > .drag-handle {
float: left;
cursor: move;
}
&.single > .main {
height: 40px;
line-height: 39px;
padding: 0 15px;
[checkbox] {
display: inline;
}
.label-lg {
top: 7px;
}
}
&.double > .main {
height: 68px;
line-height: 25px;
padding: 10px 15px;
}
&.single {
a.btn, button, .drag-handle {
padding: 10px 12px;
}
}
&.double {
a.btn, button, .drag-handle {
padding: 24px;
}
}
}
.form-control-focus(@color: @input-border-focus) {
@color-rgba: rgba(red(@color), green(@color), blue(@color), .3);
}
.modal {
background-color: rgba(0,0,0,.5);
position: fixed !important;
.modal-dialog {
margin: 0 auto;
top: 50px;
.modal-content {
background-color: @body-bg;
.modal-body {
max-height: 80vh;
overflow-y: auto;
padding: 25px 15px;
-webkit-app-region: no-drag;
}
.modal-footer {
border-top: 1px solid #222;
padding: 0;
-webkit-app-region: no-drag;
.btn.btn-default {
background: @input-bg;
border: none !important;
cursor: pointer;
box-shadow: none !important;
padding: 10px;
&:hover {
background: rgba(0,0,0,.25);
}
&:active {
background: rgba(0,0,0,.5);
}
}
}
}
}
}
.modal-backdrop {
background: rgba(0,0,0,.25);
}
.navbar-fixed-top {
border-width: 0 0 2px;
height: 52px;
}
.navbar-form {
box-shadow: none !important;
border: none !important;
}
.nav-tabs-justified,
.nav-tabs {
border-bottom: 1px solid @nav-tabs-border-color;
> li {
> a {
border: 1px solid transparent;
border-radius: 0;
color: @text-color;
&:hover {
background-color: @nav-tabs-active-link-hover-bg;
border-bottom: 1px solid @nav-tabs-border-color;
}
}
// Active state, and its :hover to override normal :hover
&.active > a {
&,
&:hover,
&:focus {
border-radius: 0;
border: 1px solid transparent;
border-bottom: 1px solid @nav-tabs-active-link-hover-border-color;
}
}
}
}
.nav-justified {
> li {
display: table-cell;
width: 1%;
> a {
margin-bottom: 0;
}
}
}
.popover-content {
//padding: 0;
}
.progress {
margin-bottom: 0;
}
table {
background: transparent;
td {
vertical-align: top;
}
.table-condensed {
display: block;
}
}
.table {
background: @table-bg;
.box-shadow(@control-shadow);
&.no-margin {
margin-bottom: 0;
}
> thead,
> tbody,
> tfoot {
> tr {
background-color: transparent;
> th,
> td {
border-top: 1px solid @table-line-border-color;
}
&:first-child {
th, td {
border-top: none;
}
}
}
}
> thead > tr > th {
border-bottom: 2px solid @table-line-border-color;
}
}
.table-bordered {
> thead,
> tbody,
> tfoot {
> tr {
> th,
> td {
border: 1px solid @table-line-border-color;
}
}
}
}
.help-block {
color: darken(@text-color, 10%);
}
.label {
margin-right: 5px;
}
.datepicker-dropdown {
&.datepicker-orient-top:before {
display: none !important;
}
&.datepicker-orient-top:after {
border-bottom: 7px solid @dropdown-bg !important;
}
&.datepicker-orient-bottom:after {
border-top: 7px solid @dropdown-bg !important;
}
table tr td.day:hover {
background: #555 !important;
}
table tr td.active {
background: @brand-primary !important;
color: #222 !important;
text-shadow: none !important;
}
}

View file

@ -0,0 +1,141 @@
@brand-primary: #f7e61d;
@brand-success: #5cb85c;
@brand-info: #5bc0de;
@brand-warning: #f0ad4e;
@brand-danger: #FF1C01;
// New
@brand-primary: #f7e61d;
@brand-success: #42B500;
@brand-info: #01BAEF;
@brand-warning: #DB8A00;
@brand-danger: #EF2F00;
@control-shadow: 0 1px 1px rgba(0,0,0,.25);
@control-shadow-active: 0 1px 1px rgba(0,0,0,.25) inset, @control-shadow;
@control-dropdown-shadow: 0 0 50px rgba(0,0,0,.5), @control-shadow;
@form-accent: #DBCA00;
@form-accent-bright: @brand-primary;
@body-bg: #1D272D;
@text-color: #aaa;
@font-family-sans-serif: "Source Sans Pro", "PT Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
@icon-font-path: "../fonts/";
@component-active-color: rgba(0,0,0,.15);
@component-active-color: darken(@component-active-bg, 30%);
@table-bg: #444;
@table-bg-accent: rgba(255,255,255,.15);
@table-bg-hover: #666;
@table-border-color: #2e2e2e;
@table-line-border-color: #4f4f4f;
@btn-default-color: @text-color;
@btn-default-bg: #243D49;
@btn-default-border: transparent;
@btn-primary-color: @component-active-color;
@btn-primary-border: #584E00;
@btn-danger-border: rgba(0,0,0,.5);
@btn-danger-color: white;
@btn-danger-bg: #FF4630;
@btn-danger-border: transparent;//@brand-danger;
@btn-link-disabled-color: darken(@text-color, 20%);
@input-bg: #11181C;
@input-bg-disabled: #2a2f31;
@input-color: #bbb;
@input-border: #3a3a3a;
@input-group-addon-border-color: @input-bg;
@input-color-placeholder: #777;
@input-group-addon-bg: @input-bg;
@dropdown-bg: rgba(64,64,64,.95); //@body-bg;
@dropdown-link-color: @text-color;
@dropdown-link-hover-color: #ddd;
@dropdown-link-hover-bg: #444;
@dropdown-link-disabled-color: darken(@text-color, 5%);
@navbar-default-bg: #23272A;
@navbar-default-border: #111;
@nav-tabs-border-color: #666;
@nav-tabs-link-hover-border-color: transparent;
@nav-tabs-active-link-hover-bg: rgba(255,255,255,.1);
@nav-tabs-active-link-hover-color: @brand-primary;
@nav-tabs-active-link-border-color: @brand-primary;
@nav-tabs-active-link-hover-border-color: @brand-primary;
@pagination-color: @btn-default-color;
@pagination-bg: @btn-default-bg;
@pagination-border: @btn-default-border;
@pagination-hover-color: @btn-default-color;
@pagination-hover-bg: lighten(@btn-default-bg, 5%);
@pagination-hover-border: @btn-default-border;
@pagination-active-color: @brand-primary;
@pagination-active-bg: darken(@btn-default-bg, 5%);
@pagination-active-border: @btn-default-border;
@pagination-disabled-color: @btn-link-disabled-color;
@pagination-disabled-bg: darken(@btn-default-bg, 5%);
@pagination-disabled-border: @btn-default-border;
//@state-success-bg: #234116; //#dff0d8;
//@state-info-bg: #0C3A50; //#d9edf7;
//@state-danger-bg: #9E3B3B;///#f2dede;
@popover-bg: rgba(64,64,64,.95);
@popover-arrow-color: #444;
@progress-bg: #555;
@list-group-bg: rgba(255,255,255,.1);
@list-group-disabled-bg: #333;
@list-group-border: transparent;
@list-group-line-border: rgba(255,255,255,.1);
@list-group-hover-bg: rgba(255,255,255,.2);
@list-group-link-color: @text-color;
@list-group-link-heading-color: @text-color;
@list-group-active-bg: rgba(255,255,255,.3);
@list-group-active-border: transparent;
@panel-bg: @table-bg;
@panel-inner-border: @table-border-color;
@panel-footer-bg: #666;
@panel-default-text: #ddd;
@panel-default-border: @table-border-color;
@panel-default-heading-bg: #666;
@well-bg: #222;
@badge-bg: #333;
@badge-active-bg: #333;
@code-bg: #222;
@pre-bg: #222;
@pre-color: #bbb;
@blockquote-border-color: #444;
@page-header-border-color: #444;
@alert-bg: #2A2A2A;
@state-success-text: @brand-success;
@state-success-bg: @alert-bg;
@state-success-border: @state-success-text;
@state-info-text: @brand-info;
@state-info-bg: @alert-bg;
@state-info-border: @state-info-text;
@state-warning-text: #F27208;
@state-warning-bg: @alert-bg;
@state-warning-border: @state-warning-text;
@state-danger-text: @brand-danger;
@state-danger-bg: @alert-bg;
@state-danger-border: @state-danger-text;
@border-radius-base: 1px;
@border-radius-large: 3px;
@border-radius-small: 1px;

BIN
app/assets/img/disk.icns Normal file

Binary file not shown.

BIN
app/assets/img/disk.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
app/assets/img/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 KiB

BIN
app/assets/img/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

107
app/assets/img/logo.svg Normal file
View file

@ -0,0 +1,107 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
xml:space="preserve"
width="536.82501"
height="126.525"
viewBox="0 0 536.82501 126.525"
sodipodi:docname="elements_wortmarke+bildmarke_gelb+weiß_rz.svg"
inkscape:export-filename="/home/eugene/Downloads/logo.png"
inkscape:export-xdpi="42.677204"
inkscape:export-ydpi="42.677204"><metadata
id="metadata8"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs6" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1845"
inkscape:window-height="1025"
id="namedview4"
showgrid="false"
inkscape:zoom="1.1586643"
inkscape:cx="143.54613"
inkscape:cy="-3.8338411"
inkscape:window-x="75"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="g10" /><g
id="g10"
inkscape:groupmode="layer"
inkscape:label="ink_ext_XXXXXX"
transform="matrix(1.25,0,0,-1.25,0,126.525)"><g
id="g12"
transform="scale(0.1,0.1)"><path
d="m 202.457,809.793 404.891,0 0,202.457 -404.891,0 0,-202.457 z"
style="fill:#fff200;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path14"
inkscape:connector-curvature="0" /><path
d="m 0,607.375 202.445,0 0,202.457 -202.445,0 0,-202.457 z"
style="fill:#fff200;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path16"
inkscape:connector-curvature="0" /><path
d="m 202.457,404.918 404.891,0 0,202.457 -404.891,0 0,-202.457 z"
style="fill:#fff200;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path18"
inkscape:connector-curvature="0" /><path
d="m 0,202.461 202.445,0 0,202.457 -202.445,0 0,-202.457 z"
style="fill:#fff200;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path20"
inkscape:connector-curvature="0" /><path
d="m 202.457,0 404.891,0 0,202.461 -404.891,0 0,-202.461 z"
style="fill:#fff200;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path22"
inkscape:connector-curvature="0" /><path
d="m 1072.96,482.414 -148.108,0 0,48.219 148.108,0 0,-48.219 z m 39.27,-234.23 -302.441,0 0,516.679 302.441,0 0,-48.218 -247.32,0 0,-420.243 247.32,0 0,-48.218"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path24"
inkscape:connector-curvature="0" /><path
d="m 1518.04,248.184 -187.4,0 0,48.218 187.4,0 0,-48.218 z m -247.34,0 -55.1,0 0,516.679 55.1,0 0,-516.679"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path26"
inkscape:connector-curvature="0" /><path
d="m 1875.61,482.414 -148.12,0 0,48.219 148.12,0 0,-48.219 z m 39.27,-234.23 -302.43,0 0,516.679 302.43,0 0,-48.218 -247.33,0 0,-420.243 247.33,0 0,-48.218"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path28"
inkscape:connector-curvature="0" /><path
d="m 2515.65,248.184 -55.12,0 0,333.425 55.12,0 0,-333.425 z m -432.66,0 -55.1,0 0,333.425 55.1,0 0,-333.425"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path30"
inkscape:connector-curvature="0" /><path
d="m 2899.41,482.414 -148.12,0 0,48.219 148.12,0 0,-48.219 z m 39.28,-234.23 -302.44,0 0,516.679 302.44,0 0,-48.218 -247.34,0 0,-420.243 247.34,0 0,-48.218"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path32"
inkscape:connector-curvature="0" /><path
d="m 3438.17,419.605 -55.11,0 0,345.258 55.11,0 0,-345.258 z m -334.12,-171.421 -55.12,0 0,344.457 55.12,0 0,-344.457 z m 336.1,19.675 -44.09,-28.949 -352.46,505.524 44.79,28.933 351.76,-505.508"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path34"
inkscape:connector-curvature="0" /><path
d="m 3732.38,248.184 -55.1,0 0,408.523 55.1,0 0,-408.523 z m 160.52,468.461 -376.14,0 0,48.218 376.14,0 0,-48.218"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path36"
inkscape:connector-curvature="0" /><path
d="m 4243.6,638.805 c -18.61,62.683 -73.02,92.308 -126.76,92.308 -56.49,0 -108.85,-33.754 -108.85,-95.761 0,-37.891 23.43,-75.786 73.02,-86.801 l 16.54,-4.141 -13.1,-48.91 -15.16,3.453 c -75.77,17.902 -115.04,76.461 -115.04,135.02 0,95.757 80.6,144.683 162.59,144.683 73.71,0 148.81,-39.273 171.54,-122.64 L 4243.6,638.805 Z M 4122.34,234.406 c -75.78,0 -153.63,38.571 -181.18,124.696 l 46.84,19.285 c 19.99,-66.137 75.79,-95.762 132.27,-95.762 63.39,0 121.26,37.203 121.26,104.027 0,46.856 -28.24,81.297 -83.37,92.313 l -13.77,2.758 13.08,48.91 19.99,-4.129 c 76.46,-15.848 117.12,-69.586 117.12,-137.777 0,-85.438 -68.9,-154.321 -172.24,-154.321"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path38"
inkscape:connector-curvature="0" /><path
d="m 2528.61,742.93 -44.08,35.597 -211.89,-224.117 -212.58,224.731 -44.08,-35.598 249.15,-263.246 7.51,-7.883 7.51,7.883 248.46,262.633"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
id="path40"
inkscape:connector-curvature="0" /></g></g></svg>

After

Width:  |  Height:  |  Size: 6 KiB

BIN
app/assets/img/shortcut.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 B

BIN
app/assets/img/user.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View file

@ -0,0 +1,23 @@
app > toaster-container > #toast-container {
width: 100% !important;
left: 0 !important;
right: 0 !important;
top: 50px !important;
.toast {
box-shadow: none !important;
text-shadow: none !important;
opacity: 1 !important;
border-radius: 0 !important;
width: 100% !important;
padding: 10px !important;
.toaster-icon {
display: none !important;
}
.toast-title {
font-weight: normal !important;
}
}
}

13
app/index.pug Normal file
View file

@ -0,0 +1,13 @@
doctype html
html
head
meta(charset='UTF-8')
title ELEMENTS Benchmark
base(href='index.html')
script.
console.timeStamp('index')
window.nodeRequire = require
script(src='./preload.js')
script(src='./bundle.js', defer)
body(style='background-image: radial-gradient(circle, #2b3840 0%, #1D272D 100%); min-height: 100vh')
app

130
app/main.js Normal file
View file

@ -0,0 +1,130 @@
const Config = require('electron-config')
const electron = require('electron')
const platform = require('os').platform()
require('electron-debug')({enabled: true, showDevTools: process.argv.indexOf('--debug') != -1})
let app = electron.app
let windowConfig = new Config({name: 'window'})
setupWindowManagement = () => {
let windowCloseable
app.window.on('close', (e) => {
windowConfig.set('windowBoundaries', app.window.getBounds())
if (!windowCloseable) {
app.window.hide()
e.preventDefault()
}
})
app.window.on('closed', () => {
app.window = null
})
electron.ipcMain.on('window-closeable', (event, flag) => {
windowCloseable = flag
})
electron.ipcMain.on('window-focus', () => {
app.window.show()
app.window.focus()
})
app.on('before-quit', () => windowCloseable = true)
}
setupMenu = () => {
var template = [{
label: "Application",
submenu: [
{ type: "separator" },
{ label: "Quit", accelerator: "CmdOrCtrl+Q", click: () => {
app.window.webContents.send('host:quit-request')
}}
]}, {
label: "Edit",
submenu: [
{ label: "Undo", accelerator: "CmdOrCtrl+Z", selector: "undo:" },
{ label: "Redo", accelerator: "Shift+CmdOrCtrl+Z", selector: "redo:" },
{ type: "separator" },
{ label: "Cut", accelerator: "CmdOrCtrl+X", selector: "cut:" },
{ label: "Copy", accelerator: "CmdOrCtrl+C", selector: "copy:" },
{ label: "Paste", accelerator: "CmdOrCtrl+V", selector: "paste:" },
{ label: "Select All", accelerator: "CmdOrCtrl+A", selector: "selectAll:" }
]
}]
electron.Menu.setApplicationMenu(electron.Menu.buildFromTemplate(template))
}
start = () => {
let t0 = Date.now()
let secondInstance = app.makeSingleInstance((argv) => {
app.window.focus()
})
if (secondInstance) {
app.quit()
return
}
let options = {
width: 800,
height: 400,
icon: `${app.getAppPath()}/assets/img/icon.png`,
title: 'ELEMENTS Benchmark',
minWidth: 800,
minHeight: 400,
'web-preferences': {'web-security': false},
//- background to avoid the flash of unstyled window
backgroundColor: '#1D272D',
}
Object.assign(options, windowConfig.get('windowBoundaries'))
if (platform == 'darwin') {
options.titleBarStyle = 'hidden'
} else {
options.frame = false
}
app.commandLine.appendSwitch('--disable-http-cache')
app.window = new electron.BrowserWindow(options)
app.window.loadURL(`file://${app.getAppPath()}/assets/webpack/index.html`, {extraHeaders: "pragma: no-cache\n"})
if (platform != 'darwin') {
app.window.setMenu(null)
}
app.window.show()
app.window.focus()
setupWindowManagement()
setupMenu()
console.info(`Host startup: ${Date.now() - t0}ms`)
t0 = Date.now()
electron.ipcMain.on('app:ready', () => {
console.info(`App startup: ${Date.now() - t0}ms`)
})
}
app.on('ready', start)
app.on('activate', () => {
if (!app.window)
start()
else {
app.window.show()
app.window.focus()
}
})
process.on('uncaughtException', function(err) {
console.log(err)
app.window.webContents.send('uncaughtException', err)
})

14
app/package.json Normal file
View file

@ -0,0 +1,14 @@
{
"name": "term",
"version": "1.0.0",
"main": "main.js",
"dependencies": {
"child-process-promise": "^2.1.3",
"devtron": "^1.4.0",
"electron-config": "^0.2.1",
"electron-debug": "^1.0.1",
"electron-is-dev": "^0.1.2",
"path": "^0.12.7",
"pty.js": "https://github.com/Tyriar/pty.js/tarball/c75c2dcb6dcad83b0cb3ef2ae42d0448fb912642"
}
}

15
app/src/app.d.ts vendored Normal file
View file

@ -0,0 +1,15 @@
declare var nodeRequire: any
interface IPromise {}
declare interface Window {
require: any
process: any
__dirname: any
__platform: any
}
declare var window: Window
declare interface Console {
timeStamp(...args: any[])
}

60
app/src/app.module.ts Normal file
View file

@ -0,0 +1,60 @@
import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { HttpModule } from '@angular/http'
import { FormsModule } from '@angular/forms'
import { ToasterModule } from 'angular2-toaster'
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'
import { PerfectScrollbarModule } from 'angular2-perfect-scrollbar'
import { PerfectScrollbarConfigInterface } from 'angular2-perfect-scrollbar'
const PERFECT_SCROLLBAR_CONFIG: PerfectScrollbarConfigInterface = {
suppressScrollX: true
}
import { ConfigService } from 'services/config'
import { ElectronService } from 'services/electron'
import { HostAppService } from 'services/hostApp'
import { LogService } from 'services/log'
import { ModalService } from 'services/modal'
import { NotifyService } from 'services/notify'
import { QuitterService } from 'services/quitter'
import { LocalStorageService } from 'angular2-localstorage/LocalStorageEmitter'
import { AppComponent } from 'components/app'
import { CheckboxComponent } from 'components/checkbox'
import { SettingsModalComponent } from 'components/settingsModal'
@NgModule({
imports: [
BrowserModule,
HttpModule,
FormsModule,
ToasterModule,
NgbModule.forRoot(),
PerfectScrollbarModule.forRoot(PERFECT_SCROLLBAR_CONFIG),
],
providers: [
ConfigService,
ElectronService,
HostAppService,
LogService,
ModalService,
NotifyService,
QuitterService,
LocalStorageService,
],
entryComponents: [
SettingsModalComponent,
],
declarations: [
AppComponent,
CheckboxComponent,
SettingsModalComponent,
],
bootstrap: [
AppComponent
]
})
export class AppModule {}

132
app/src/components/app.less Normal file
View file

@ -0,0 +1,132 @@
@import "~bootstrap/less/variables.less";
@import "~bootstrap/variables.less";
:host {
display: flex;
width: 100vw;
height: 100vh;
flex-direction: column;
overflow: hidden;
-webkit-user-select: none;
-webkit-font-smoothing: antialiased;
background: @body-bg;
}
.navbar {
flex: none;
border-left: none;
border-right: none;
border-top: none;
-webkit-app-region: drag;
margin: 0;
background: @navbar-default-bg;
:host.platform-darwin & {
background: fade(@navbar-default-bg, 50%);
}
.navbar-btn-big {
margin: 0;
padding: 15px 20px 15px;
background-color: #333;
text-align: left;
background: transparent;
box-shadow: none;
&.btn-profile {
padding: 7px 14px 7px;
display: flex;
flex-direction: row;
max-width: 150px;
:host.platform-darwin & {
max-width: 120px;
}
>img {
flex: none;
float: left;
margin: 2px 10px 4px 0;
width: 30px;
height: 30px;
:host.platform-darwin & {
margin-right: 0;
}
}
>div {
flex: auto;
:host.platform-darwin & {
display: none;
}
.username {
}
.settings {
font-size: 10px;
}
}
}
&.btn-close {
font-size: 38px;
padding: 1px 13px 2px;
line-height: 47px;
:host.platform-darwin & {
display: none;
}
}
}
button.navbar-btn-big:hover {
background-color: #222;
}
button.navbar-btn-big:active {
background-color: #111;
}
.navbar-brand {
padding: 11px 15px;
width: 150px;
:host.platform-darwin & {
display: block;
margin: auto;
float: none;
}
img {
height: 28px;
}
}
}
[scrollable] {
width: 100vw;
flex: auto;
display: flex;
.nano {
flex: auto;
height: auto;
}
}
footer {
display: block;
flex: none;
height: 1px;
}
perfect-scrollbar {
flex: auto;
min-height: 0;
}

View file

@ -0,0 +1,19 @@
div.navbar.navbar-default.draggable
button.btn.btn-default.navbar-btn.navbar-btn-big.btn-close.pull-right((click)='hide()', title='Hide')
| &times;
button.btn.btn-default.navbar-btn.navbar-btn-big.pull-right((click)='showSettings()', title='Settings')
i.fa.fa-cog
div.navbar-brand
img.logo(src=require("img/logo.svg"))
perfect-scrollbar
div.container
div#term(style='width: 300px; height: 300px;')
footer
toaster-container([toasterconfig]="toasterconfig")
template(ngbModalContainer)
div.window-resizer.window-resizer-tl

87
app/src/components/app.ts Normal file
View file

@ -0,0 +1,87 @@
import { Component, ElementRef } from '@angular/core'
import { ModalService } from 'services/modal'
import { ElectronService } from 'services/electron'
import { HostAppService } from 'services/hostApp'
import { LogService } from 'services/log'
import { QuitterService } from 'services/quitter'
import { ToasterConfig } from 'angular2-toaster'
import { SettingsModalComponent } from 'components/settingsModal'
import 'angular2-toaster/lib/toaster.css'
import 'global.less'
const hterm = require('hterm-commonjs')
var pty = require('pty.js');
@Component({
selector: 'app',
template: require('./app.pug'),
styles: [require('./app.less')],
})
export class AppComponent {
constructor(
private hostApp: HostAppService,
private modal: ModalService,
private electron: ElectronService,
element: ElementRef,
log: LogService,
_quitter: QuitterService,
) {
console.timeStamp('AppComponent ctor')
let logger = log.create('main')
logger.info('ELEMENTS client', electron.app.getVersion())
this.toasterConfig = new ToasterConfig({
mouseoverTimerStop: true,
preventDuplicates: true,
timeout: 4000,
})
}
toasterConfig: ToasterConfig
ngOnInit () {
let io
hterm.hterm.defaultStorage = new hterm.lib.Storage.Memory()
let t = new hterm.hterm.Terminal()
t.onTerminalReady = function() {
t.installKeyboard()
io = t.io.push();
//#t.decorate(element.nativeElement);
var cmd = pty.spawn('bash', [], {
name: 'xterm-color',
cols: 80,
rows: 30,
cwd: process.env.HOME,
env: process.env
});
cmd.on('data', function(data) {
io.writeUTF8(data);
});
io.onVTKeystroke = function(str) {
cmd.write(str)
};
io.sendString = function(str) {
cmd.write(str)
};
io.onTerminalResize = function(columns, rows) {
cmd.resize(columns, rows)
};
};
console.log(document.querySelector('#term'))
t.decorate(document.querySelector('#term'));
}
ngOnDestroy () {
}
showSettings() {
this.modal.open(SettingsModalComponent)
}
}

View file

@ -0,0 +1,53 @@
:host {
cursor: pointer;
&:focus {
background: rgba(255,255,255,.05);
border-radius: 5px;
}
&:active {
background: rgba(255,255,255,.1);
border-radius: 3px;
}
&[disabled] {
opacity: 0.5;
}
display: inline-flex;
flex-direction: row;
align-items: center;
.icon {
position: relative;
flex: none;
width: 14px;
height: 14px;
i {
position: absolute;
left: 0;
top: 1px;
transition: 0.25s opacity;
display: block;
font-size: 14px;
}
i.on {
color: yellow;
}
i.on, &.active i.off {
opacity: 0;
}
i.off, &.active i.on {
opacity: 1;
}
}
.name {
flex: auto;
}
}

View file

@ -0,0 +1,4 @@
.icon((click)='click()', tabindex='0', [class.active]='model', (keyup.space)='click()')
i.fa.fa-square-o.off
i.fa.fa-check-square.on
.text((click)='click()') {{text}}

View file

@ -0,0 +1,25 @@
import { NgZone, Component, Input, Output, EventEmitter } from '@angular/core'
@Component({
selector: 'checkbox',
template: require('./checkbox.pug'),
styles: [require('./checkbox.less')]
})
export class CheckboxComponent {
public click() {
NgZone.assertInAngularZone()
if (this.disabled) {
return
}
this.model = !this.model
this.modelChange.emit(this.model)
}
@Input() model: boolean
@Output() modelChange = new EventEmitter()
@Input() disabled: boolean
@Input() text: string
}

View file

@ -0,0 +1,69 @@
:host {
>.modal-body {
padding: 0 0 20px !important;
}
.form-group {
margin-left: 15px;
}
.version-info {
text-align: center;
font-size: 12px;
color: #aaa;
cursor: pointer;
padding: 10px 0;
-webkit-user-select: text;
transition: .25s all;
&:hover {
color: white;
}
}
.status-line {
display: flex;
padding: 5px 10px;
&.clickable {
&:hover {
background: rgba(0,0,0,.5);
cursor: pointer;
}
}
.icon {
flex: none;
padding: 7px 10px 0 0px;
img {
width: 32px;
height: 32px;
border-radius: 16px;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.5);
}
i {
width: 32px;
text-align: center;
}
}
.main {
flex: auto;
flex-direction: column;
display: flex;
.title {
flex: none;
font-size: 12px;
}
.value {
flex: auto;
font-size: 16px;
color: #ddd;
}
}
}
}

View file

@ -0,0 +1,112 @@
div.modal-body
ngb-tabset(type='tabs nav-justified')
ngb-tab
template(ngbTabTitle)
i.fa.fa-cog
| General
template(ngbTabContent)
.status-line.clickable(*ngIf='connectionHost', (click)='openWeb()')
.icon
i.fa.fa-rss.fa-2x.fa-live
.main
.title Server
.value {{connectionHost}}
.status-line(*ngIf='!connectionHost')
.icon
i.fa.fa-rss.fa-2x
.main
.title Server
.value Not connected
.status-line(*ngIf='!userInfo?.user')
.icon
img(src=require("img/user.png"))
.main
.title Login
.value Not logged in
.status-line(*ngIf='userInfo?.user')
.icon
img([src]='userInfo.user.avatar || "../../assets/img/user.png"')
.main
.title Login
.value {{ userInfo.user.full_name || userInfo.user.username }}
br
div.form-group
checkbox(text='Remember connected workspaces', '[(model)]'='config.store.rememberWorkspaces')
ngb-tab
template(ngbTabTitle)
i.fa.fa-wrench
| Advanced
template(ngbTabContent)
div.form-group(*ngIf='isWindows || isLinux')
div.input-group
input.form-control(type='text', placeholder='SNFS projects folder', '[(ngModel)]'='config.store.snfsPath')
div.input-group-btn
button.btn.btn-default((click)='selectSNFSPath()')
i.fa.fa-folder-open
div.form-group(*ngIf='isWindows')
label First drive letter to use
select.form-control('[(ngModel)]'='config.store.firstDrive')
option(*ngFor='let x of drives', value='{{x}}') {{x}}:
div.form-group(*ngIf='isMac')
label Extra NFS options
input.form-control(type='text', '[(ngModel)]'='config.store.extraNFSOptions')
div.form-group(*ngIf='isMac')
label Extra AFP options
input.form-control(type='text', '[(ngModel)]'='config.store.extraAFPOptions')
div.form-group(*ngIf='isMac')
label Extra SMB options
input.form-control(type='text', '[(ngModel)]'='config.store.extraSMBOptions')
div.form-group(*ngIf='isLinux')
label Extra NFS options
input.form-control(type='text', '[(ngModel)]'='config.store.extraLinuxNFSOptions')
div.form-group(*ngIf='isLinux')
label Extra SMB options
input.form-control(type='text', '[(ngModel)]'='config.store.extraLinuxSMBOptions')
ngb-tab(*ngIf="apiServer.authorizedKeysStore.length > 0")
template(ngbTabTitle)
i.fa.fa-plug
| Apps
template(ngbTabContent)
.list-group
.list-group-item(*ngFor="let key of apiServer.authorizedKeysStore")
button.btn.btn-default((click)='apiServer.deauthorizeKey(key)')
i.fa.fa-times
span Disconnect this app
div {{key.name}}
ngb-tab
template(ngbTabTitle)
i.fa.fa-info-circle
| About
template(ngbTabContent)
.form-group
h1 ELEMENTS Client
div syslink GmbH © {{year}}
.form-group
label Version
div {{version}}
.form-group
button.btn.btn-default((click)='copyDiagnostics()') Copy diagnostic info
div.modal-footer
div.btn-group.btn-group-justified
a.btn.btn-default((click)='logout()', *ngIf='elementsClient.userInfo')
i.fa.fa-fw.fa-arrow-left
br
| Log out
a.btn.btn-default((click)='quit()')
i.fa.fa-fw.fa-power-off
br
| Quit
a.btn.btn-default((click)='close()')
i.fa.fa-fw.fa-check
br
| Done

View file

@ -0,0 +1,44 @@
import { Component } from '@angular/core'
import { ElectronService } from 'services/electron'
import { HostAppService, PLATFORM_WINDOWS, PLATFORM_LINUX, PLATFORM_MAC } from 'services/hostApp'
import { ConfigService } from 'services/config'
import { QuitterService } from 'services/quitter'
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'
import * as os from 'os'
@Component({
selector: 'settings-modal',
template: require('./settingsModal.pug'),
styles: [require('./settingsModal.less')],
})
export class SettingsModalComponent {
constructor(
private modalInstance: NgbActiveModal,
private hostApp: HostAppService,
private electron: ElectronService,
private quitter: QuitterService,
public config: ConfigService,
) {
this.isWindows = hostApp.platform == PLATFORM_WINDOWS
this.isMac = hostApp.platform == PLATFORM_MAC
this.isLinux = hostApp.platform == PLATFORM_LINUX
this.version = electron.app.getVersion()
this.year = new Date().getFullYear()
}
isWindows: boolean
isMac: boolean
isLinux: boolean
year: number
version: string
ngOnDestroy() {
this.config.save()
}
close() {
this.modalInstance.close()
}
}

6
app/src/entry.preload.ts Normal file
View file

@ -0,0 +1,6 @@
import 'source-sans-pro'
import 'font-awesome/css/font-awesome.css'
import '../assets/toaster-custom.less'
import '../assets/bootstrap/bootstrap.less'

25
app/src/entry.ts Normal file
View file

@ -0,0 +1,25 @@
console.timeStamp('entry point')
import 'core-js'
import 'zone.js/dist/zone.js'
import 'core-js/es7/reflect'
import 'jquery'
// Always land on the start view
location.hash = ''
import { AppModule } from 'app.module'
import { enableProdMode } from '@angular/core'
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'
if (nodeRequire('electron-is-dev')) {
console.warn('Running in debug mode')
} else {
enableProdMode()
}
console.timeStamp('angular bootstrap started')
platformBrowserDynamic().bootstrapModule(AppModule)
process.emitWarning = function () { console.log(arguments) }

176
app/src/global.less Normal file
View file

@ -0,0 +1,176 @@
@import "~bootstrap/include.less";
html.platform-win32 {
body.focused {
//border: 1px solid #9c9c00 !important;
}
}
body {
border: 1px solid #131313;
transition: 0.5s border;
overflow: hidden;
min-height: 100vh;
}
.no-drag, a, button, checkbox, .form-control, #toast-container {
-webkit-app-region: no-drag;
outline: 0 !important;
* {
outline: 0 !important;
-webkit-app-region: no-drag;
}
}
.form-control {
-webkit-user-select: initial;
}
.window-resizer {
-webkit-app-region: no-drag;
position: fixed;
width: 10px;
height: 10px;
}
.window-resizer-tl {
left: 0;
top: 0;
}
.no-wrap {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.word-wrap {
word-wrap: break-word;
word-break: break-all;
}
#toast-container.toast-top-full-width {
width: 100%;
top: 50px;
> div {
width: 100%;
border-radius: 0;
box-shadow: 0 0 2px rgba(0,0,0,.75);
opacity: 1;
filter: none;
}
}
.avatar {
margin: 20px;
width: 100px;
height: 100px;
border-radius: 50px;
box-shadow: 0 1px 1px rgba(0,0,0,.5);
}
.fa-live {
color: #7aff00;
.list-group-item &.fa-2x {
top: 10px;
position: relative;
}
}
.otp-input {
height: 50px;
input {
height: 50px;
font-size: 41px;
font-family: monospace;
text-align: center;
}
.btn {
height: 50px;
width: 50px;
}
}
ngb-modal-backdrop {
// ngbmodalwindow has its own, properly animated backdrop
background: transparent !important;
}
ngb-modal-window.fade.in {
&.out {
opacity: 0;
.modal-dialog {
transform: translate(0, -25%);
}
}
}
ngb-tabset {
>ul.nav-tabs.nav-justified {
border-bottom: none;
margin-bottom: 10px;
background: rgba(0,0,0,.25);
.nav-item .nav-link {
background: transparent;
border: none;
&.active {
background: rgba(0,0,0,.5);
border-bottom: 1px solid #777;
}
i {
display: block;
text-align: center;
font-size: 18px;
margin: 0 0 5px;
}
}
}
>.tab-content {
padding: 10px;
}
}
.btn {
i + * {
margin-left: 5px;
}
}
.list-group-item {
margin: none;
> .btn {
float: right;
margin: -7px -11px 0 0;
background: transparent;
box-shadow: none;
&:hover {
background: rgba(0,0,0,.25);
}
}
}
.ps-container.ps-in-scrolling>.ps-scrollbar-y-rail,
.ps-container:hover>.ps-scrollbar-y-rail:hover {
background: rgba(0,0,0,.5) !important;
}

View file

@ -0,0 +1,88 @@
import { Injectable } from '@angular/core'
import { HostAppService, PLATFORM_MAC, PLATFORM_WINDOWS } from 'services/hostApp'
const Config = nodeRequire('electron-config')
const exec = nodeRequire('child-process-promise').exec
import * as fs from 'fs'
@Injectable()
export class ConfigService {
constructor(
private hostApp: HostAppService,
) {
this.config = new Config({name: 'config'})
this.load()
}
private config: any
private store: any
migrate() {
if (!this.has('migrated')) {
if (this.hostApp.platform == PLATFORM_WINDOWS) {
let configPath = `${this.hostApp.getPath('documents')}\\.elements.conf`
let config = null
try {
config = JSON.parse(fs.readFileSync(configPath, 'utf-8'))
console.log('Migrating configuration:', config)
this.set('host', config.Hostname)
this.set('username', config.Username)
this.set('firstDrive', config.FirstDrive)
} catch (err) {
console.error('Could not migrate the config:', err)
}
this.set('migrated', 1)
this.save()
return Promise.resolve()
}
if (this.hostApp.platform == PLATFORM_MAC) {
return Promise.all([
exec('defaults read ~/Library/Preferences/com.syslink.Elements.plist connection_host').then((result) => {
this.set('host', result.stdout.trim())
}),
exec('defaults read ~/Library/Preferences/com.syslink.Elements.plist connection_username').then((result) => {
this.set('username', result.stdout.trim())
}),
]).then(() => {
this.set('migrated', 1)
this.save()
}).catch((err) => {
console.error('Could not migrate the config:', err)
this.set('migrated', 1)
this.save()
})
}
}
return Promise.resolve()
}
set(key: string, value: any) {
this.save()
this.config.set(key, value)
this.load()
}
get(key: string): any {
this.save()
return this.config.get(key)
}
has(key: string): boolean {
this.save()
return this.config.has(key)
}
delete(key: string) {
this.save()
this.config.delete(key)
this.load()
}
load() {
this.store = this.config.store
}
save() {
this.config.store = this.store
}
}

View file

@ -0,0 +1,39 @@
import { Injectable } from '@angular/core'
@Injectable()
export class ElectronService {
constructor() {
if (process.env.TEST_ENV) {
this.initTest()
} else {
this.init()
}
}
init() {
this.electron = require('electron')
this.remoteElectron = this.remoteRequire('electron')
this.app = this.remoteElectron.app
this.dialog = this.remoteElectron.dialog
this.shell = this.electron.shell
this.clipboard = this.electron.clipboard
this.ipcRenderer = this.electron.ipcRenderer
}
initTest() {
;
}
remoteRequire(name: string): any {
return this.electron.remote.require(name)
}
app: any
ipcRenderer: any
shell: any
dialog: any
clipboard: any
private electron: any
private remoteElectron: any
}

View file

@ -0,0 +1,69 @@
import { Injectable, NgZone, EventEmitter } from '@angular/core'
import { ElectronService } from 'services/electron'
import { Logger, LogService } from 'services/log'
export const PLATFORM_WINDOWS = 'win32'
export const PLATFORM_MAC = 'darwin'
export const PLATFORM_LINUX = 'linux'
@Injectable()
export class HostAppService {
constructor(
private zone: NgZone,
private electron: ElectronService,
log: LogService,
) {
this.platform = require('os').platform()
this.logger = log.create('hostApp')
electron.ipcRenderer.on('host:quit-request', () => this.zone.run(() => this.quitRequested.emit()))
electron.ipcRenderer.on('uncaughtException', function(err) {
console.error('Unhandled exception:', err)
})
this.ready.subscribe(() => {
electron.ipcRenderer.send('app:ready')
})
}
platform: string;
quitRequested = new EventEmitter<any>()
ready = new EventEmitter<any>()
private logger: Logger;
getWindow() {
return this.electron.app.window
}
getShell() {
return this.electron.shell
}
getAppPath() {
return this.electron.app.getAppPath()
}
getPath(type: string) {
return this.electron.app.getPath(type)
}
openDevTools() {
this.electron.app.webContents.openDevTools()
}
setWindowCloseable(flag: boolean) {
this.electron.ipcRenderer.send('window-closeable', flag)
}
focusWindow() {
this.electron.ipcRenderer.send('window-focus')
}
quit() {
this.logger.info('Quitting')
this.electron.app.quit()
}
}

25
app/src/services/log.ts Normal file
View file

@ -0,0 +1,25 @@
import { Injectable } from '@angular/core'
export class Logger {
constructor(
private name: string,
) {}
log(level: string, ...args: any[]) {
args.splice(0, 0, this.name + ':')
console[level](...args)
}
debug(...args: any[]) { this.log('debug', ...args) }
info(...args: any[]) { this.log('info', ...args) }
warn(...args: any[]) { this.log('warn', ...args) }
error(...args: any[]) { this.log('error', ...args) }
}
@Injectable()
export class LogService {
create (name: string): Logger {
return new Logger(name)
}
}

29
app/src/services/modal.ts Normal file
View file

@ -0,0 +1,29 @@
import { Injectable, NgZone } from '@angular/core';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
@Injectable()
export class ModalService {
constructor(
private zone: NgZone,
private ngbModal: NgbModal,
) {}
open(content: any, config?: any) {
config = config || {}
config.windowClass = 'out'
let modal = this.ngbModal.open(content, config)
let fx = (<any>modal)._removeModalElements.bind(modal);
(<any>modal)._removeModalElements = () => {
(<any>modal)._windowCmptRef.instance.windowClass = 'out'
setTimeout(() => fx(), 500)
}
setTimeout(() => {
(<any>modal)._windowCmptRef.instance.windowClass = ''
}, 1)
return modal
}
}

View file

@ -0,0 +1,48 @@
import { Injectable } from '@angular/core'
import { ToasterService } from 'angular2-toaster'
import { LogService } from 'services/log'
@Injectable()
export class NotifyService {
constructor(
private toaster: ToasterService,
private log: LogService,
) {}
pop(options) {
this.toaster.pop(options)
}
info(title: string, body: string = null) {
return this.pop({
type: 'info',
title, body,
timeout: 4000,
})
}
success(title: string, body: string = null) {
return this.pop({
type: 'success',
title, body,
timeout: 4000,
})
}
warning(title: string, body: string = null) {
return this.pop({
type: 'warning',
title, body,
timeout: 4000,
})
}
error(title: string, body: string = null) {
return this.pop({
type: 'error',
title, body,
timeout: 4000,
})
}
}

View file

@ -0,0 +1,21 @@
import { Injectable } from '@angular/core'
import { HostAppService } from 'services/hostApp'
import { ElectronService } from 'services/electron'
@Injectable()
export class QuitterService {
constructor(
private electron: ElectronService,
private hostApp: HostAppService,
) {
hostApp.quitRequested.subscribe(() => {
this.quit()
})
}
quit() {
this.hostApp.setWindowCloseable(true)
this.hostApp.quit()
}
}

62
build/config.gypi Normal file
View file

@ -0,0 +1,62 @@
# Do not edit. File was generated by node-gyp's "configure" step
{
"target_defaults": {
"cflags": [],
"default_configuration": "Release",
"defines": [],
"include_dirs": [],
"libraries": []
},
"variables": {
"asan": 0,
"debug_devtools": "node",
"force_dynamic_crt": 0,
"host_arch": "x64",
"icu_data_file": "icudt57l.dat",
"icu_data_in": "..\\..\\deps/icu-small\\source/data/in\\icudt57l.dat",
"icu_endianness": "l",
"icu_gyp_path": "tools/icu/icu-generic.gyp",
"icu_locales": "en,root",
"icu_path": "deps/icu-small",
"icu_small": "true",
"icu_ver_major": "57",
"node_byteorder": "little",
"node_enable_d8": "false",
"node_enable_v8_vtunejit": "false",
"node_install_npm": "true",
"node_module_version": 48,
"node_no_browser_globals": "false",
"node_prefix": "/usr/local",
"node_release_urlbase": "https://nodejs.org/download/release/",
"node_shared": "false",
"node_shared_cares": "false",
"node_shared_http_parser": "false",
"node_shared_libuv": "false",
"node_shared_openssl": "false",
"node_shared_zlib": "false",
"node_tag": "",
"node_use_bundled_v8": "true",
"node_use_dtrace": "false",
"node_use_etw": "true",
"node_use_lttng": "false",
"node_use_openssl": "true",
"node_use_perfctr": "true",
"node_use_v8_platform": "true",
"openssl_fips": "",
"openssl_no_asm": 0,
"shlib_suffix": "so.48",
"target_arch": "x64",
"v8_enable_gdbjit": 0,
"v8_enable_i18n_support": 1,
"v8_inspector": "true",
"v8_no_strict_aliasing": 1,
"v8_optimized_debug": 0,
"v8_random_seed": 0,
"v8_use_snapshot": "true",
"want_separate_host_toolset": 0,
"nodedir": "C:\\cygwin64\\home\\Avid\\.node-gyp\\iojs-1.3.5",
"copy_dev_lib": "true",
"standalone_static_library": 1,
"target": "1.3.5"
}
}

BIN
build/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 KiB

BIN
build/icons/1024x1024.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 KiB

BIN
build/icons/128x128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

BIN
build/icons/16x16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 749 B

BIN
build/icons/256x256.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
build/icons/32x32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
build/icons/512x512.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

BIN
build/icons/64x64.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

BIN
build/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View file

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<installer-gui-script minSpecVersion="1">
<title>ELEMENTS Client</title>
<options customize="never" require-scripts="true" rootVolumeOnly="true" />
<choices-outline>
<line choice="default">
<line choice="com.syslink.elements.driver" />
<line choice="com.syslink.Elements" />
<line choice="com.syslink.afptuner" />
</line>
</choices-outline>
<choice id="default"/>
<choice id="com.syslink.elements.driver">
<pkg-ref id="com.syslink.elements.driver"/>
</choice>
<pkg-ref id="com.syslink.elements.driver" version="1" auth="root">ElementsDriver.pkg</pkg-ref>
<choice id="com.syslink.Elements">
<pkg-ref id="com.syslink.Elements"/>
</choice>
<pkg-ref id="com.syslink.Elements" version="1" auth="root">Elements.pkg</pkg-ref>
<pkg-ref id="com.syslink.Elements">
<must-close>
<app id="com.syslink.Elements"/>
</must-close>
</pkg-ref>
<choice id="com.syslink.afptuner" title="AvidSharedStorageAccess">
<pkg-ref id="com.syslink.afptuner"/>
</choice>
<pkg-ref id="com.syslink.afptuner" version="1" auth="root">AFPTuner.pkg</pkg-ref>
</installer-gui-script>

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
<dict>
<key>BundleHasStrictIdentifier</key>
<true/>
<key>BundleIsRelocatable</key>
<false/>
<key>BundleIsVersionChecked</key>
<false/>
<key>BundleOverwriteAction</key>
<string>upgrade</string>
<key>BundlePostInstallScriptPath</key>
<string>Elements.postinst.sh</string>
<key>RootRelativeBundlePath</key>
<string>Applications/ELEMENTS.app</string>
</dict>
</array>
</plist>

44
build/mac/Elements.postinst.sh Executable file
View file

@ -0,0 +1,44 @@
#!/bin/bash
set -e
cat > /Library/LaunchDaemons/com.elements.VolumesFix.plist << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>KeepAlive</key>
<false/>
<key>Label</key>
<string>com.elements.VolumesFix</string>
<key>ProgramArguments</key>
<array>
<string>/bin/bash</string>
<string>-c</string>
<string>sleep 3; chmod 777 /Volumes</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>StandardErrorPath</key>
<string>/dev/null</string>
<key>StandardOutPath</key>
<string>/dev/null</string>
<key>UserName</key>
<string>root</string>
</dict>
</plist>
EOF
chmod 600 /Library/LaunchDaemons/com.elements.VolumesFix.plist
cat > /etc/nsmb.conf << EOF
[default]
minauth=none
streams=yes
soft=yes
notify_off=yes
port445=no_netbios
signing_required=false
EOF
launchctl load -w /Library/LaunchDaemons/com.elements.VolumesFix.plist
launchctl start com.elements.VolumesFix

50
build/mac/Info.plist Normal file
View file

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en_US</string>
<key>CFBundleExecutable</key>
<string>ELEMENTS</string>
<key>CFBundleIdentifier</key>
<string>com.syslink.elements</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>${VERSION}</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>Elements Client</string>
<key>CFBundleURLSchemes</key>
<array>
<string>elements-client</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>619</string>
<key>LSMinimumSystemVersion</key>
<string>10.8.0</string>
<key>LSUIElement</key>
<false/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2016 Syslink GmbH. All rights reserved.</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>AtomApplication</string>
</dict>
</plist>

BIN
build/mac/codesign Executable file

Binary file not shown.

BIN
build/mac/icon.icns Normal file

Binary file not shown.

34
build/windows/build.wxs Normal file
View file

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<Wix RequiredVersion="3.6.2830.0" xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:bal="http://schemas.microsoft.com/wix/BalExtension">
<Bundle Name="ELEMENTS" Version="$(var.Version)" Manufacturer="ELEMENTS.tv" UpgradeCode="508475fc-0e76-4cd1-8e98-6953023ba518"
HelpUrl="http://elements.tv"
Copyright="Copyright © 2016 ELEMENTS" IconSourceFile="build/icon.ico"
AboutUrl="http://elements.tv">
<BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.HyperlinkLicense">
<bal:WixStandardBootstrapperApplication
LicenseUrl=""
LogoFile="build\logo.png"
ThemeFile="build\windows\wix-theme.xml"
/>
</BootstrapperApplicationRef>
<Chain>
<MsiPackage
Id="ClientMSI"
Compressed="yes"
ForcePerMachine="yes"
SourceFile="dist\elements-app.msi"
Vital="yes">
</MsiPackage>
<MsiPackage
Id="DriverMSI"
Compressed="yes"
ForcePerMachine="yes"
SourceFile="build/windows/ElementsDriver_x64.msi"
Vital="yes">
</MsiPackage>
</Chain>
</Bundle>
</Wix>

View file

@ -0,0 +1,84 @@
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" UpgradeCode="37484543-5276-2386-5427-275941245342"
Name="ELEMENTS" Version="$(var.ProductVersion)" Manufacturer="ELEMENTS.tv" Language="1033">
<Package InstallerVersion="200"
Compressed="yes"
Comments="Windows Installer Package"
Platform="x64"
InstallScope="perMachine"
InstallPrivileges="elevated" />
<MajorUpgrade AllowDowngrades="yes" Schedule="afterInstallValidate" />
<Media Id="1" Cabinet="product.cab" EmbedCab="yes"/>
<Feature Id="DefaultFeature" Level="1">
<ComponentRef Id="RegistryEntries" />
<ComponentRef Id="AppDir"/>
<ComponentRef Id="AvidSharedStorageAccess"/>
<ComponentRef Id="ApplicationShortcutDesktop"/>
<ComponentGroupRef Id="Files" />
</Feature>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="DesktopFolder" Name="Desktop">
<Component Id="ApplicationShortcutDesktop" Guid="*">
<Shortcut Id="ApplicationDesktopShortcut"
Name="ELEMENTS"
Description="ELEMENTS client app"
Target="[INSTALLDIR]\\Elements.exe"
WorkingDirectory="INSTALLDIR"/>
<RemoveFolder Id="DesktopFolder" On="uninstall"/>
<RegistryValue
Root="HKCU"
Key="Software\ELEMENTS"
Name="installed"
Type="integer"
Value="1"
KeyPath="yes"/>
</Component>
</Directory>
<Directory Id="ProgramFiles64Folder">
<Directory Id="ElementsDir" Name="ELEMENTS">
<Directory Id="INSTALLDIR" Name="ELEMENTS Client">
<Component Id="AppDir" Guid="284957a6-a462-4e34-babd-c17800f11054" Win64="yes">
<CreateFolder />
<!--RemoveFile Id="RemoveFilesFromAppDirectory" Name="*.*" On="uninstall" /-->
<!--RemoveFolder Id="AppDir" On="uninstall"/-->
</Component>
</Directory>
</Directory>
</Directory>
<Component Id="RegistryEntries" Guid="572998d8-719e-4124-8fe6-6d4f8b855d7b">
<RegistryKey Root="HKLM"
Key="system\currentcontrolset\services\AvidFs"
Action="create">
<RegistryValue Type="string" Name="Description" Value="AIFMRX" />
<RegistryValue Type="string" Name="DisplayName" Value="AIFMRX" />
<RegistryValue Type="integer" Name="ErrorControl" Value="1" />
<RegistryValue Type="string" Name="Group" Value="Network" />
<RegistryValue Type="string" Name="ImagePath" Value="System32\DRIVERS\aifmrx.sys" />
<RegistryValue Type="integer" Name="Start" Value="1" />
<RegistryValue Type="integer" Name="Type" Value="2" />
</RegistryKey>
<RegistryKey Root="HKLM"
Key="system\currentcontrolset\services\AifMRx\NetworkProvider"
Action="create">
<RegistryValue Type="string" Name="DeviceName" Value="\Device\AvidFs" />
<RegistryValue Type="string" Name="Name" Value="Interface Network" />
<RegistryValue Type="string" Name="ProviderPath" Value="System32\aifmrxnp.dll" />
</RegistryKey>
<RegistryKey Root="HKLM"
Key="system\CurrentControlSet\services\LanmanWorkstation\Parameters"
Action="create">
<RegistryValue Type="integer" Name="DisableLargeMtu" Value="0" KeyPath="yes" />
<RegistryValue Type="integer" Name="DisableBandwidthThrottling" Value="1" />
<RegistryValue Type="integer" Name="EnableWsd" Value="0" />
</RegistryKey>
</Component>
<Directory Id="System64Folder" Name="SystemFolder">
<Component Id="AvidSharedStorageAccess" Guid="972c67f2-ee17-4b20-8939-b92cfa13fcf6" NeverOverwrite="yes" Win64="yes" Permanent="yes">
<File Id="AvidSharedStorageAccess.dll" Source="build\windows\AvidSharedStorageAccess.dll" KeyPath="yes"/>
</Component>
</Directory>
</Directory>
</Product>
</Wix>

BIN
build/windows/signtool.exe Normal file

Binary file not shown.

View file

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. -->
<Theme xmlns="http://wixtoolset.org/schemas/thmutil/2010">
<Window Width="300" Height="360" HexStyle="100a0000" FontId="0">#(loc.Caption)</Window>
<Font Id="0" Height="-12" Weight="500" Foreground="000000" Background="FFFFFF">Segoe UI</Font>
<Font Id="1" Height="-24" Weight="500" Foreground="000000">Segoe UI</Font>
<Font Id="2" Height="-22" Weight="500" Foreground="666666">Segoe UI</Font>
<Font Id="3" Height="-12" Weight="500" Foreground="000000" Background="FFFFFF">Segoe UI</Font>
<Font Id="4" Height="-12" Weight="500" Foreground="ff0000" Background="FFFFFF" Underline="yes">Segoe UI</Font>
<Image X="30" Y="30" Width="256" Height="60" ImageFile="logo.png" Visible="yes"/>
<Page Name="Help">
<Text X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.HelpHeader)</Text>
<Text X="11" Y="112" Width="-11" Height="-35" FontId="3" DisablePrefix="yes">#(loc.HelpText)</Text>
<Button Name="HelpCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.HelpCloseButton)</Button>
</Page>
<Page Name="Install">
<!--Hypertext Name="EulaHyperlink" X="11" Y="121" Width="-11" Height="51" TabStop="yes" FontId="3" HideWhenDisabled="yes">#(loc.InstallLicenseLinkText)</Hypertext>
<Checkbox Name="EulaAcceptCheckbox" X="-11" Y="-41" Width="260" Height="17" TabStop="yes" FontId="3" HideWhenDisabled="yes">#(loc.InstallAcceptCheckbox)</Checkbox-->
<Button Name="InstallButton" X="90" Y="-120" Width="120" Height="50" TabStop="yes" FontId="0">#(loc.InstallInstallButton)</Button>
<Button Name="WelcomeCancelButton" X="110" Y="-80" Width="80" Height="23" TabStop="yes" FontId="0">#(loc.InstallCloseButton)</Button>
</Page>
<Page Name="Options">
<Text X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.OptionsHeader)</Text>
<Text X="11" Y="121" Width="-11" Height="17" FontId="3" DisablePrefix="yes">#(loc.OptionsLocationLabel)</Text>
<Editbox Name="FolderEditbox" X="11" Y="143" Width="-91" Height="21" TabStop="yes" FontId="3" FileSystemAutoComplete="yes" />
<Button Name="BrowseButton" X="-11" Y="142" Width="75" Height="23" TabStop="yes" FontId="3">#(loc.OptionsBrowseButton)</Button>
<Button Name="OptionsOkButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.OptionsOkButton)</Button>
<Button Name="OptionsCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.OptionsCancelButton)</Button>
</Page>
<Page Name="FilesInUse">
<Text X="11" Y="80" Width="-11" Height="30" FontId="2" DisablePrefix="yes">#(loc.FilesInUseHeader)</Text>
<Text X="11" Y="121" Width="-11" Height="34" FontId="3" DisablePrefix="yes">#(loc.FilesInUseLabel)</Text>
<Text Name="FilesInUseText" X="11" Y="150" Width="-11" Height="-86" FontId="3" DisablePrefix="yes" HexStyle="0x0000C000"></Text>
<Button Name="FilesInUseCloseRadioButton" X="11" Y="-60" Width="-11" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes" HexStyle="0x000009">#(loc.FilesInUseCloseRadioButton)</Button>
<Button Name="FilesInUseDontCloseRadioButton" X="11" Y="-40" Width="-11" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes" HexStyle="0x000009">#(loc.FilesInUseDontCloseRadioButton)</Button>
<Button Name="FilesInUseOkButton" X="-91" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.FilesInUseOkButton)</Button>
<Button Name="FilesInUseCancelButton" X="-11" Y="-11" Width="75" Height="23" TabStop="yes" FontId="0">#(loc.FilesInUseCancelButton)</Button>
</Page>
<Page Name="Progress">
<Text X="30" Y="120" Width="-30" Height="30" FontId="2" DisablePrefix="yes">#(loc.ProgressHeader)</Text>
<Text X="30" Y="150" Width="70" Height="17" FontId="3" DisablePrefix="yes">#(loc.ProgressLabel)</Text>
<Text Name="OverallProgressPackageText" X="30" Y="200" Width="-30" Height="17" FontId="3" DisablePrefix="yes">#(loc.OverallProgressPackageText)</Text>
<Progressbar Name="OverallCalculatedProgressbar" X="30" Y="220" Width="-30" Height="20" />
<Button Name="ProgressCancelButton" X="110" Y="-40" Width="80" Height="23" TabStop="yes" FontId="0">#(loc.ProgressCancelButton)</Button>
</Page>
<Page Name="Modify">
<Text X="30" Y="110" Width="-30" Height="30" FontId="2" DisablePrefix="yes">#(loc.ModifyHeader)</Text>
<Button Name="UninstallButton" X="90" Y="-100" Width="120" Height="50" TabStop="yes" FontId="0">#(loc.ModifyUninstallButton)</Button>
<Button Name="RepairButton" X="110" Y="-60" Width="80" Height="23" TabStop="yes" FontId="0">#(loc.ModifyRepairButton)</Button>
<Button Name="ModifyCancelButton" X="110" Y="-30" Width="80" Height="23" TabStop="yes" FontId="0">#(loc.ModifyCloseButton)</Button>
</Page>
<Page Name="Success">
<Text Name="SuccessHeader" X="30" Y="110" Width="-30" Height="30" FontId="2" HideWhenDisabled="yes" DisablePrefix="yes">Success</Text>
<Text Name="SuccessInstallHeader" X="30" Y="110" Width="-30" Height="30" FontId="2" HideWhenDisabled="yes" DisablePrefix="yes">Installed successfully</Text>
<Text Name="SuccessRepairHeader" X="30" Y="110" Width="-30" Height="30" FontId="2" HideWhenDisabled="yes" DisablePrefix="yes">Repaired successfully</Text>
<Text Name="SuccessUninstallHeader" X="30" Y="110" Width="-30" Height="30" FontId="2" HideWhenDisabled="yes" DisablePrefix="yes">Uninstalled successfully</Text>
<Button Name="LaunchButton" X="90" Y="-100" Width="120" Height="50" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.SuccessLaunchButton)</Button>
<Button Name="SuccessCancelButton" X="110" Y="-60" Width="80" Height="23" TabStop="yes" FontId="0">#(loc.SuccessCloseButton)</Button>
</Page>
<Page Name="Failure">
<Text Name="FailureHeader" X="30" Y="110" Width="-30" Height="30" FontId="2" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.FailureHeader)</Text>
<Text Name="FailureInstallHeader" X="30" Y="110" Width="-30" Height="30" FontId="2" HideWhenDisabled="yes" DisablePrefix="yes">Setup failed</Text>
<Text Name="FailureUninstallHeader" X="30" Y="110" Width="-30" Height="30" FontId="2" HideWhenDisabled="yes" DisablePrefix="yes">Uninstall failed</Text>
<Text Name="FailureRepairHeader" X="30" Y="110" Width="-30" Height="30" FontId="2" HideWhenDisabled="yes" DisablePrefix="yes">Repair failed</Text>
<Hypertext Name="FailureLogFileLink" X="30" Y="145" Width="-30" Height="50" FontId="3" TabStop="yes" HideWhenDisabled="yes">#(loc.FailureHyperlinkLogText)</Hypertext>
<Hypertext Name="FailureMessageText" X="30" Y="195" Width="-30" Height="50" FontId="3" TabStop="yes" HideWhenDisabled="yes" />
<Text Name="FailureRestartText" X="-30" Y="255" Width="400" Height="34" FontId="3" HideWhenDisabled="yes" DisablePrefix="yes">#(loc.FailureRestartText)</Text>
<Button Name="FailureRestartButton" X="90" Y="-100" Width="120" Height="50" TabStop="yes" FontId="0" HideWhenDisabled="yes">#(loc.FailureRestartButton)</Button>
<Button Name="FailureCloseButton" X="110" Y="-60" Width="80" Height="23" TabStop="yes" FontId="0">#(loc.FailureCloseButton)</Button>
</Page>
</Theme>

76
package.json Normal file
View file

@ -0,0 +1,76 @@
{
"name": "term",
"devDependencies": {
"apply-loader": "^0.1.0",
"awesome-typescript-loader": "2.2.4",
"css-loader": "0.26.1",
"electron": "^1.4.13",
"electron-builder": "10.6.1",
"electron-osx-sign": "electron-userland/electron-osx-sign#f092181a1bffa2b3248a23ee28447a47e14a8f04",
"electron-rebuild": "1.4.0",
"file-loader": "^0.9.0",
"font-awesome": "4.7.0",
"html-loader": "^0.4.4",
"less": "^2.7.1",
"less-loader": "^2.2.3",
"node-gyp": "^3.4.0",
"pug-html-loader": "^1.0.9",
"pug-loader": "^2.3.0",
"pug-static-loader": "0.0.1",
"raw-loader": "^0.5.1",
"style-loader": "^0.13.1",
"to-string-loader": "^1.1.5",
"tslint": "4.0.2",
"typescript": "2.1.1",
"typings": "2.0.0",
"url-loader": "^0.5.7",
"val-loader": "^0.5.0",
"webpack": "2.2.0-rc.0"
},
"build": {
"appId": "com.elements.benchmark",
"productName": "ELEMENTS Benchmark",
"compression": "normal",
"win": {
"target": "zip",
"icon": "./app/assets/img/shortcut.ico"
},
"mac": {
"category": "public.app-category.video",
"icon": "./build/mac/icon.icns",
"identity": "Syslink GmbH"
},
"linux": {
"category": "Network",
"target": "AppImage",
"icon": "./app/assets/img/icon.png"
}
},
"scripts": {
"pack": "build --dir",
"postinstall": "install-app-deps",
"dist": "build"
},
"dependencies": {
"@angular/common": "2.3.1",
"@angular/compiler": "2.3.1",
"@angular/core": "2.3.1",
"@angular/forms": "2.3.1",
"@angular/http": "2.3.1",
"@angular/platform-browser": "2.3.1",
"@angular/platform-browser-dynamic": "2.3.1",
"@angular/platform-server": "2.3.1",
"@angular/router": "3.3.1",
"@ng-bootstrap/ng-bootstrap": "^1.0.0-alpha.15",
"angular2-localstorage": "github:AilisObrian/angular2-localstorage",
"angular2-perfect-scrollbar": "^1.1.0",
"angular2-toaster": "^1.1.0",
"bootstrap": "^3.3.7",
"core-js": "^2.4.1",
"jquery": "^3.1.1",
"rxjs": "5.0.0-rc.4",
"source-sans-pro": "^2.0.10",
"hterm-commonjs": "^1.0.0",
"zone.js": "0.7.2"
}
}

26
tsconfig.json Normal file
View file

@ -0,0 +1,26 @@
{
"compilerOptions": {
"baseUrl": "./app/src",
"module": "commonjs",
"target": "es5",
"declaration": false,
"noImplicitAny": false,
"removeComments": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"sourceMap": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
},
"compileOnSave": false,
"exclude": [
"node_modules"
],
"files": [
"app/src/app.d.ts",
"app/src/entry.ts",
"typings/index.d.ts",
"node_modules/rxjs/Rx.d.ts"
]
}

22
tslint.json Normal file
View file

@ -0,0 +1,22 @@
{
"rules": {
"indent": [true, "spaces"],
"quotemark": [true, "single"],
"semicolon": false,
"no-inferrable-types": [true, "ignore-params"],
"curly": true,
"no-duplicate-key": true,
"no-duplicate-variable": true,
"no-empty": true,
"no-eval": true,
"no-invalid-this": true,
"no-shadowed-variable": true,
"no-unreachable": true,
"no-unused-expression": true,
"no-unused-new": true,
"no-unused-variable": true,
"no-use-before-declare": true,
"no-var-keyword": true,
"new-parens": true
}
}

8
typings.json Normal file
View file

@ -0,0 +1,8 @@
{
"globalDependencies": {
"core-js": "registry:dt/core-js#0.0.0+20160914114559",
"electron": "registry:dt/electron#1.3.3+20161012142539",
"jquery": "registry:dt/jquery#1.10.0+20160929162922",
"node": "registry:dt/node#6.0.0+20161014191813"
}
}

98
webpack.config.js Normal file
View file

@ -0,0 +1,98 @@
const path = require("path")
const webpack = require("webpack")
module.exports = {
target: 'node',
entry: {
'index.ignore': 'file-loader?name=index.html!val-loader!pug-html-loader!./app/index.pug',
'preload': './app/src/entry.preload.ts',
'bundle': './app/src/entry.ts',
},
devtool: 'source-map',
output: {
path: 'app/assets/webpack',
pathinfo: true,
//publicPath: 'assets/webpack/',
filename: '[name].js'
},
resolve: {
modules: ['app/src/', 'node_modules', 'app/assets/'],
extensions: ['.ts', '.js'],
},
module: {
loaders: [
{
test: /\.ts$/,
loader: 'awesome-typescript-loader'
},
{
test: /\.pug$/,
exclude: [
/index.pug/
],
loaders: [
{
loader: 'apply-loader'
},
{
loader: 'pug-loader'
}
]
},
{ test: /\.css$/, loader: "style-loader!css-loader" },
{
test: /\.less$/,
loader: "style-loader!css-loader!less-loader",
exclude: [/app\/src\/components\//],
},
{
test: /\.less$/,
loader: "to-string-loader!css-loader!less-loader",
include: [/app\/src\/components\//],
},
{
test: /\.(png|svg)$/,
loader: "file-loader",
query: {
name: 'images/[name].[hash:8].[ext]'
}
},
{
test: /\.(ttf|eot|otf|woff|woff2)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: "file-loader",
query: {
name: 'fonts/[name].[hash:8].[ext]'
}
},
]
},
externals: {
'electron': 'require("electron")',
'net': 'require("net")',
'remote': 'require("remote")',
'shell': 'require("shell")',
'ipc': 'require("ipc")',
'fs': 'require("fs")',
'buffer': 'require("buffer")',
'pty.js': 'require("pty.js")',
'system': '{}',
'file': '{}'
},
plugins: [
new webpack.ProvidePlugin({
"window.jQuery": "jquery",
}),
]
}
if (!process.env.DEV) {
module.exports.plugins.push(new webpack.LoaderOptionsPlugin({
minimize: true,
}))
module.exports.plugins.push(new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
mangle: false,
}))
module.exports.devtool = 'source-map'
}