<|start_filename|>static/js/main.js<|end_filename|>
var app = angular.module('rsm', [
    'smart-table', 'toggle-switch', 'angularMoment', 'mgcrea.ngStrap.alert']);

app.directive('csSelect', function () {
  return {
    require: '^stTable',
    template: '<input type="checkbox"/>',
    scope: {
      row: '=csSelect'
    },
    link: function (scope, element, attr, ctrl) {

      element.bind('change', function () {
        scope.$apply(function () {
          ctrl.select(scope.row, 'multiple');
        });
      });

      scope.$watch('row.isSelected', function (newValue) {
        if (newValue === true) {
          element.parent().addClass('st-selected');
          element.find('input').prop('checked', true);
        } else {
          element.parent().removeClass('st-selected');
          element.find('input').prop('checked', false);
        }
      });
    }
  };
});

app.directive('stSelectAll', function () {
  return {
    require: '^stTable',
    restrict: 'E',
    template: '<input type="checkbox" ng-model="isAllSelected" />',
    scope: {
      all: '='
    },
    link: function (scope, element, attr, ctrl) {

      scope.$watch('isAllSelected', function () {
        ctrl.getFilteredCollection().forEach(function(val) {
          val.isSelected = scope.isAllSelected;
        });
      });

      scope.$watch(ctrl.getFilteredCollection(), function(newVal, oldVal) {
        if (oldVal) {
          oldVal.forEach(function (val) {
            val.isSelected = false;
          });
        }

        scope.isAllSelected = false;
      });
    }
  };
});

app.controller('MainCtrl', [
    '$scope', '$window', '$interval', '$http', '$alert',
  function($scope, $window, $interval, $http, $alert) {

    $scope.internalCollection = [];

    var error_cb = function() {
      $alert({
        title: 'Server error: ',
        content: 'An server error occured...',
        type: 'danger',
        container: '#alerts-container',
        duration: 3
      });
    };

    $scope.selectedDelete = function() {
      var bulk_json = {};
      angular.forEach($scope.internalCollection, function(item) {
        if (item.isSelected) {
          bulk_json[item.uuid] = true;
        }
      });
      if (bulk_json) {
        $http.post('../bulk_delete', bulk_json)
          .success(function(resp) {
            if (!resp.success) {
              error_cb();
              return;
            }
            // delete requires a full reload
            $window.location.reload();
          })
        .error(error_cb);
      }
    };

    $scope.selectedUpdateData = function(data) {
      var bulk_json = {};
      angular.forEach($scope.internalCollection, function(item) {
        if (item.isSelected) {
          bulk_json[item.uuid] = data || '';
        }
      });
      if (bulk_json) {
        $http.post('../bulk_update_data', bulk_json)
          .success(function(resp) {
            if (!resp.success) {
              error_cb();
              return;
            }
            $scope.updateCollection();
          })
        .error(error_cb);
      }
    };

    $scope.updateCollection = function() {
      $http({
        url: '../uuids',
        method: 'GET'
      }).success(function(resp) {
        if (!resp.success) {
          error_cb();
          return;
        }
        var db = resp.db;
        angular.forEach($scope.internalCollection, function(item) {
          if (!db[item.uuid]) {
            // reload the whole page if item have been removed on the server
            $window.location.reload();
          }
          angular.extend(item, db[item.uuid]);
          delete db[item.uuid];
        });
        angular.forEach(db, function(item, uuid) {
          var idx = $scope.internalCollection.push(item) - 1;
          $scope.$watch(
            'internalCollection[' + idx +'].active',
            function(newValue, oldValue) {
              if (newValue != oldValue) {
                $http.post(
                    '../uuid/' + uuid,
                    angular.extend({}, item, {active: newValue}))
                  .success(function(resp) {
                    angular.extend(item, resp);
                  })
                  .error(error_cb);
              }
            }
          );
        });

      }).error(error_cb);
    };

    $interval($scope.updateCollection, 10000);
  }
]);


<|start_filename|>gulpfile.js<|end_filename|>
var gulp = require('gulp');
var del = require('del');
var runSequence = require('run-sequence');
var jshint = require('gulp-jshint');
var usemin = require('gulp-usemin');
var uglify = require('gulp-uglify');
var minifyCss = require('gulp-minify-css');
var rev = require('gulp-rev');

gulp.task('del', function(cb) {
  del('rsm/static/**', cb);
});

gulp.task('lint', function() {
  gulp.src(['static/js/*.js'])
    .pipe(jshint('.jshintrc'))
      .pipe(jshint.reporter('jshint-stylish'));
});

gulp.task('usemin', function() {
  gulp.src('static/index.html')
    .pipe(usemin({
      assetsDir: 'static',
      css: [minifyCss(),rev()],
      js: [uglify(), rev()]
      //js: [uglify({mangle: false}), rev()]
    }))
    .pipe(gulp.dest('rsm/static'));
});

gulp.task('bootstrap-fonts', function() {
  gulp.src('static/vendor/bootstrap/dist/fonts/*')
    .pipe(gulp.dest('rsm/static/fonts'));
});

gulp.task('img', function() {
  gulp.src('static/img/*')
    .pipe(gulp.dest('rsm/static/img'));
});

gulp.task('default', function() {
  runSequence('del', ['usemin', 'img', 'bootstrap-fonts', 'lint']);
});


<|start_filename|>Dockerfile<|end_filename|>
FROM debian:stretch

MAINTAINER <NAME> <<EMAIL>>

ENV DEBIAN_FRONTEND noninteractive

RUN apt-get update && apt-get install -yq --no-install-recommends \
    curl openssh-server python python-pip python-setuptools python-wheel gcc python-dev linux-libc-dev \
  && rm -rf /var/lib/apt/lists/*

# https://github.com/giampaolo/psutil/issues/824
# Once psutils supports wheels on Linux, install will be:
#RUN apt-get update && apt-get install -yq --no-install-recommends \
#    curl openssh-server python \
#  && rm -rf /var/lib/apt/lists/*
#RUN curl https://bootstrap.pypa.io/get-pip.py | python

RUN pip install dumb-init reverse-ssh-manager

RUN adduser --system --shell /bin/sh rsm --uid 1000

RUN mkdir -p /var/run/sshd
ADD docker /rsm

# sshd, reverse-ssh-manager
EXPOSE 22 80

ENTRYPOINT ["/usr/local/bin/dumb-init", "--"]

ENV HOST_KEY /etc/ssh/ssh_host_rsa_key
ENV AUTHORIZED_KEYS_FILE /etc/ssh/authorized_keys

CMD ["bash", "-c", "/usr/sbin/sshd -f /rsm/sshd_config -h $HOST_KEY -o AuthorizedKeysFile=$AUTHORIZED_KEYS_FILE && exec reverse-ssh-manager /rsm/prod.cfg"]


<|start_filename|>static/css/main.css<|end_filename|>
#alerts-container {
  position: absolute;
  top: 20px;
  left: 20px;
  right: 20px;
}

.contenteditable {
  height: 20px;
}


<|start_filename|>static/js/fix-angular-smart-table.js<|end_filename|>
window.ng = angular;
