DEV: Move stuff to the regular plugin structure
This commit is contained in:
parent
528d7adc4a
commit
2bba7f62b2
|
@ -1,20 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module DockerManager
|
||||
class ApplicationController < ActionController::Base
|
||||
helper DockerManager::ApplicationHelper
|
||||
|
||||
include CurrentUser
|
||||
|
||||
protect_from_forgery
|
||||
|
||||
def handle_unverified_request
|
||||
unless is_api?
|
||||
super
|
||||
clear_current_user
|
||||
render plain: "['BAD CSRF']", status: 403
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,20 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title><%= I18n.t("docker_manager.title") %></title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="manager-client/config/environment" content="%7B%22modulePrefix%22%3A%22manager-client%22%2C%22environment%22%3A%22development%22%2C%22rootURL%22%3A%22/%22%2C%22locationType%22%3A%22hash%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%7D%7D%2C%22APP%22%3A%7B%22name%22%3A%22manager-client%22%2C%22version%22%3A%220.0.0+cfc32897%22%7D%2C%22exportApplicationGlobal%22%3Atrue%7D" />
|
||||
<meta id="preloaded-data" data-preload="<%= { rootUrl: discourse_root_url, longPollingBaseUrl: long_polling_base_url, logoUrl: image_path('images/docker-manager.png') }.to_json %>">
|
||||
|
||||
<script src="<%= script_asset_path('docker-manager-vendor') %>"></script>
|
||||
<script src="<%= script_asset_path('docker-manager-app') %>"></script>
|
||||
|
||||
<%= stylesheet_link_tag "docker-manager-app" %>
|
||||
<%= stylesheet_link_tag "docker-manager-vendor" %>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,10 @@
|
|||
export default {
|
||||
resource: "admin",
|
||||
|
||||
map() {
|
||||
this.route("docker-manager", { resetNamespace: true }, function () {
|
||||
this.route("processes");
|
||||
this.route("upgrade", { path: "/upgrade/:id" });
|
||||
});
|
||||
},
|
||||
};
|
|
@ -21,10 +21,6 @@ body {
|
|||
padding: 0;
|
||||
}
|
||||
|
||||
.back-site {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
header {
|
||||
img.logo {
|
||||
width: 150px;
|
||||
|
@ -85,10 +81,6 @@ table#repos {
|
|||
}
|
||||
}
|
||||
|
||||
h3.loading {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.new-version {
|
||||
h4 {
|
||||
margin: 0 0 10px 0;
|
|
@ -1,13 +1,16 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
DockerManager::Engine.routes.draw do
|
||||
get "admin/docker", to: redirect("/admin/upgrade"), constraints: AdminConstraint.new
|
||||
get "admin/upgrade" => "admin#index", constraints: AdminConstraint.new
|
||||
get "admin/docker/repos" => "admin#repos", constraints: AdminConstraint.new
|
||||
get "admin/docker/latest" => "admin#latest", constraints: AdminConstraint.new
|
||||
get "admin/docker/progress" => "admin#progress", constraints: AdminConstraint.new
|
||||
get "admin/docker/ps" => "admin#ps", constraints: AdminConstraint.new
|
||||
post "admin/docker/upgrade" => "admin#upgrade", constraints: AdminConstraint.new
|
||||
delete "admin/docker/upgrade" => "admin#reset_upgrade", constraints: AdminConstraint.new
|
||||
get 'admin/docker/csrf' => 'admin#csrf', constraints: AdminConstraint.new
|
||||
scope "/admin", constraints: AdminConstraint.new do
|
||||
get "/docker", to: redirect("/admin/upgrade")
|
||||
get "/upgrade" => "admin#index"
|
||||
get "/docker/repos" => "admin#repos"
|
||||
get "/docker/latest" => "admin#latest"
|
||||
get "/docker/progress" => "admin#progress"
|
||||
get "/docker/ps" => "admin#ps"
|
||||
get "/docker/csrf" => "admin#csrf"
|
||||
|
||||
post "/docker/upgrade" => "admin#upgrade"
|
||||
delete "/docker/upgrade" => "admin#reset_upgrade"
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
# EditorConfig helps developers define and maintain consistent
|
||||
# coding styles between different editors and IDEs
|
||||
# editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.hbs]
|
||||
insert_final_newline = false
|
||||
|
||||
[*.{diff,md}]
|
||||
trim_trailing_whitespace = false
|
|
@ -1,9 +0,0 @@
|
|||
{
|
||||
/**
|
||||
Ember CLI sends analytics information by default. The data is completely
|
||||
anonymous, but there are times when you might want to disable this behavior.
|
||||
|
||||
Setting `disableAnalytics` to true will prevent any data from being sent.
|
||||
*/
|
||||
"disableAnalytics": false
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
# unconventional js
|
||||
/blueprints/*/files/
|
||||
/vendor/
|
||||
|
||||
# compiled output
|
||||
/dist/
|
||||
/tmp/
|
||||
|
||||
# dependencies
|
||||
/bower_components/
|
||||
/node_modules/
|
||||
|
||||
# misc
|
||||
/coverage/
|
||||
!.*
|
||||
|
||||
# ember-try
|
||||
/.node_modules.ember-try/
|
||||
/bower.json.ember-try
|
||||
/package.json.ember-try
|
|
@ -1,57 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
parser: 'babel-eslint',
|
||||
parserOptions: {
|
||||
ecmaVersion: 2018,
|
||||
sourceType: 'module',
|
||||
ecmaFeatures: {
|
||||
legacyDecorators: true
|
||||
}
|
||||
},
|
||||
plugins: [
|
||||
'ember'
|
||||
],
|
||||
globals: {
|
||||
Em: false,
|
||||
MessageBus: false
|
||||
},
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'plugin:ember/recommended'
|
||||
],
|
||||
env: {
|
||||
browser: true
|
||||
},
|
||||
rules: {},
|
||||
overrides: [
|
||||
// node files
|
||||
{
|
||||
files: [
|
||||
'.eslintrc.js',
|
||||
'.template-lintrc.js',
|
||||
'ember-cli-build.js',
|
||||
'testem.js',
|
||||
'blueprints/*/index.js',
|
||||
'config/**/*.js',
|
||||
'lib/*/index.js',
|
||||
'server/**/*.js'
|
||||
],
|
||||
parserOptions: {
|
||||
sourceType: 'script'
|
||||
},
|
||||
env: {
|
||||
browser: false,
|
||||
node: true
|
||||
},
|
||||
plugins: ['node'],
|
||||
extends: ['plugin:node/recommended'],
|
||||
rules: {
|
||||
// this can be removed once the following is fixed
|
||||
// https://github.com/mysticatea/eslint-plugin-node/issues/77
|
||||
'node/no-unpublished-require': 'off'
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
|
@ -1,17 +0,0 @@
|
|||
# See https://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# compiled output
|
||||
/dist
|
||||
/tmp
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/bower_components
|
||||
|
||||
# misc
|
||||
/.sass-cache
|
||||
/connect.lock
|
||||
/coverage/*
|
||||
/libpeerconnection.log
|
||||
npm-debug.log*
|
||||
testem.log
|
|
@ -1,32 +0,0 @@
|
|||
{
|
||||
"predef": [
|
||||
"document",
|
||||
"window",
|
||||
"-Promise"
|
||||
],
|
||||
"browser": true,
|
||||
"boss": true,
|
||||
"curly": true,
|
||||
"debug": false,
|
||||
"devel": true,
|
||||
"eqeqeq": true,
|
||||
"evil": true,
|
||||
"forin": false,
|
||||
"immed": false,
|
||||
"laxbreak": false,
|
||||
"newcap": true,
|
||||
"noarg": true,
|
||||
"noempty": false,
|
||||
"nonew": false,
|
||||
"nomen": false,
|
||||
"onevar": false,
|
||||
"plusplus": false,
|
||||
"regexp": false,
|
||||
"undef": true,
|
||||
"sub": true,
|
||||
"strict": false,
|
||||
"white": false,
|
||||
"eqnull": true,
|
||||
"esversion": 6,
|
||||
"unused": true
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
extends: 'octane'
|
||||
};
|
|
@ -1,25 +0,0 @@
|
|||
---
|
||||
language: node_js
|
||||
node_js:
|
||||
- "4"
|
||||
|
||||
sudo: false
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.npm
|
||||
- $HOME/.cache # includes bowers cache
|
||||
|
||||
before_install:
|
||||
- npm config set spin false
|
||||
- npm install -g bower
|
||||
- bower --version
|
||||
- npm install phantomjs-prebuilt
|
||||
- node_modules/phantomjs-prebuilt/bin/phantomjs --version
|
||||
|
||||
install:
|
||||
- npm install
|
||||
- bower install
|
||||
|
||||
script:
|
||||
- npm test
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"ignore_dirs": ["tmp", "dist"]
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
# manager-client
|
||||
|
||||
This README outlines the details of collaborating on this Ember application.
|
||||
A short introduction of this app could easily go here.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
You will need the following things properly installed on your computer.
|
||||
|
||||
* [Git](https://git-scm.com/)
|
||||
* [Node.js](https://nodejs.org/) (with NPM)
|
||||
* [Yarn](https://yarnpkg.com)
|
||||
* [Ember CLI](https://ember-cli.com/)
|
||||
* [PhantomJS](http://phantomjs.org/)
|
||||
|
||||
## Installation
|
||||
|
||||
* `git clone <repository-url>` this repository
|
||||
* `cd manager-client`
|
||||
* `yarn install`
|
||||
|
||||
## Running / Development
|
||||
|
||||
* `./dev_server` (in root directory of this plugin)
|
||||
* Visit your app at [http://localhost:4200](http://localhost:4200).
|
||||
|
||||
### Code Generators
|
||||
|
||||
Make use of the many generators for code, try `ember help generate` for more details
|
||||
|
||||
### Running Tests
|
||||
|
||||
* `ember test`
|
||||
* `ember test --server`
|
||||
|
||||
### Building
|
||||
|
||||
* `ember build` (development)
|
||||
* `ember build --environment production` (production)
|
||||
|
||||
## Further Reading / Useful Links
|
||||
|
||||
* [ember.js](http://emberjs.com/)
|
||||
* [ember-cli](https://ember-cli.com/)
|
||||
* Development Browser Extensions
|
||||
* [ember inspector for chrome](https://chrome.google.com/webstore/detail/ember-inspector/bmdblncegkenkacieihfhpjfppoconhi)
|
||||
* [ember inspector for firefox](https://addons.mozilla.org/en-US/firefox/addon/ember-inspector/)
|
|
@ -1,15 +0,0 @@
|
|||
import Ember from "ember";
|
||||
import Application from "@ember/application";
|
||||
import Resolver from "./resolver";
|
||||
import loadInitializers from "ember-load-initializers";
|
||||
import config from "./config/environment";
|
||||
|
||||
Ember.MODEL_FACTORY_INJECTIONS = true;
|
||||
|
||||
export default class App extends Application {
|
||||
modulePrefix = config.modulePrefix;
|
||||
podModulePrefix = config.podModulePrefix;
|
||||
Resolver = Resolver;
|
||||
}
|
||||
|
||||
loadInitializers(App, config.modulePrefix);
|
|
@ -1,30 +0,0 @@
|
|||
/* eslint-disable */
|
||||
import jQuery from "jquery";
|
||||
|
||||
function init() {
|
||||
const data = JSON.parse(
|
||||
document.getElementById("preloaded-data").dataset.preload
|
||||
);
|
||||
jQuery.extend(Discourse, data);
|
||||
}
|
||||
|
||||
const Discourse = {
|
||||
getAppURL(url) {
|
||||
if (!this.hasOwnProperty("rootUrl")) {
|
||||
init();
|
||||
}
|
||||
if (!url) return url;
|
||||
|
||||
// if it's a non relative URL, return it.
|
||||
if (url !== "/" && !/^\/[^/]/.test(url)) return url;
|
||||
|
||||
if (url.indexOf(this.rootUrl) !== -1) return url;
|
||||
if (url[0] !== "/") url = "/" + url;
|
||||
|
||||
return this.rootUrl + url;
|
||||
},
|
||||
};
|
||||
|
||||
export default Discourse;
|
||||
|
||||
/* eslint-enable */
|
|
@ -1,27 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>DockerManager</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta id="preloaded-data" data-preload="{"rootUrl":"/","longPollingBaseUrl":"/"}">
|
||||
|
||||
{{content-for 'head'}}
|
||||
|
||||
<link rel="stylesheet" href="assets/vendor.css">
|
||||
<link rel="stylesheet" href="assets/manager-client.css">
|
||||
|
||||
{{content-for 'head-footer'}}
|
||||
|
||||
</head>
|
||||
<body>
|
||||
{{content-for 'body'}}
|
||||
|
||||
<script src="assets/vendor.js"></script>
|
||||
<script src="assets/manager-client.js"></script>
|
||||
|
||||
{{content-for 'body-footer'}}
|
||||
</body>
|
||||
</html>
|
|
@ -1,17 +0,0 @@
|
|||
import Discourse from "manager-client/discourse";
|
||||
import jQuery from "jquery";
|
||||
|
||||
export default {
|
||||
name: "findCsrfToken",
|
||||
|
||||
initialize() {
|
||||
return jQuery.ajax(Discourse.getAppURL("/session/csrf")).then((result) => {
|
||||
const token = result.csrf;
|
||||
jQuery.ajaxPrefilter((options, originalOptions, xhr) => {
|
||||
if (!options.crossDomain) {
|
||||
xhr.setRequestHeader("X-CSRF-Token", token);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
|
@ -1,23 +0,0 @@
|
|||
import Discourse from "manager-client/discourse";
|
||||
import jQuery from "jquery";
|
||||
|
||||
export default {
|
||||
name: "message-bus",
|
||||
|
||||
initialize() {
|
||||
MessageBus.baseUrl = Discourse.longPollingBaseUrl.replace(/\/$/, "") + "/";
|
||||
|
||||
if (MessageBus.baseUrl !== "/") {
|
||||
MessageBus.ajax = function (opts) {
|
||||
opts.headers = opts.headers || {};
|
||||
const meta = document.querySelector("meta[name=shared_session_key]");
|
||||
if (meta) {
|
||||
opts.headers["X-Shared-Session-Key"] = meta.content;
|
||||
}
|
||||
return jQuery.ajax(opts);
|
||||
};
|
||||
} else {
|
||||
MessageBus.baseUrl = Discourse.getAppURL("/");
|
||||
}
|
||||
},
|
||||
};
|
|
@ -1,3 +0,0 @@
|
|||
import Resolver from 'ember-resolver';
|
||||
|
||||
export default Resolver;
|
|
@ -1,12 +0,0 @@
|
|||
import EmberRouter from '@ember/routing/router';
|
||||
import config from 'manager-client/config/environment';
|
||||
|
||||
export default class Router extends EmberRouter {
|
||||
location = config.locationType;
|
||||
rootURL = config.rootURL;
|
||||
}
|
||||
|
||||
Router.map(function() {
|
||||
this.route("processes");
|
||||
this.route("upgrade", { path: "/upgrade/:id" });
|
||||
});
|
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"schemaVersion": "1.0.0",
|
||||
"packages": [
|
||||
{
|
||||
"name": "ember-cli",
|
||||
"version": "3.22.0",
|
||||
"blueprints": [
|
||||
{
|
||||
"name": "app",
|
||||
"outputRepo": "https://github.com/ember-cli/ember-new-output",
|
||||
"codemodsSource": "ember-app-codemods-manifest@1",
|
||||
"isBaseBlueprint": true,
|
||||
"options": [
|
||||
"--yarn"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
/* eslint-disable */
|
||||
/* jshint node: true */
|
||||
|
||||
module.exports = function (environment) {
|
||||
var ENV = {
|
||||
modulePrefix: "manager-client",
|
||||
environment: environment,
|
||||
rootURL: "/",
|
||||
locationType: "hash",
|
||||
EmberENV: {
|
||||
FEATURES: {
|
||||
// Here you can enable experimental features on an ember canary build
|
||||
// e.g. EMBER_NATIVE_DECORATOR_SUPPORT: true
|
||||
},
|
||||
EXTEND_PROTOTYPES: {
|
||||
// Prevent Ember Data from overriding Date.parse.
|
||||
Date: false,
|
||||
},
|
||||
},
|
||||
|
||||
APP: {
|
||||
// Here you can pass flags/options to your application instance
|
||||
// when it is created
|
||||
},
|
||||
};
|
||||
|
||||
if (environment === "development") {
|
||||
// ENV.APP.LOG_RESOLVER = true;
|
||||
// ENV.APP.LOG_ACTIVE_GENERATION = true;
|
||||
// ENV.APP.LOG_TRANSITIONS = true;
|
||||
// ENV.APP.LOG_TRANSITIONS_INTERNAL = true;
|
||||
// ENV.APP.LOG_VIEW_LOOKUPS = true;
|
||||
}
|
||||
|
||||
if (environment === "test") {
|
||||
// Testem prefers this...
|
||||
ENV.locationType = "none";
|
||||
|
||||
// keep test console output quieter
|
||||
ENV.APP.LOG_ACTIVE_GENERATION = false;
|
||||
ENV.APP.LOG_VIEW_LOOKUPS = false;
|
||||
|
||||
ENV.APP.rootElement = "#ember-testing";
|
||||
ENV.APP.autoboot = false;
|
||||
}
|
||||
|
||||
if (environment === "production") {
|
||||
}
|
||||
|
||||
return ENV;
|
||||
};
|
||||
|
||||
/* eslint-enable */
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"application-template-wrapper": false,
|
||||
"default-async-observers": true,
|
||||
"jquery-integration": true,
|
||||
"template-only-glimmer-components": true
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
const browsers = [
|
||||
'last 1 Chrome versions',
|
||||
'last 1 Firefox versions',
|
||||
'last 1 Safari versions'
|
||||
];
|
||||
|
||||
module.exports = {
|
||||
browsers
|
||||
};
|
|
@ -1,4 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
ember serve --proxy "http://localhost:${1:-3000}"
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
/* eslint-disable */
|
||||
/*jshint node:true*/
|
||||
/* global require, module */
|
||||
var EmberApp = require("ember-cli/lib/broccoli/ember-app");
|
||||
|
||||
module.exports = function (defaults) {
|
||||
var app = new EmberApp(defaults, {
|
||||
// Add options here
|
||||
fingerprint: {
|
||||
enabled: false,
|
||||
},
|
||||
});
|
||||
|
||||
// Use `app.import` to add additional libraries to the generated
|
||||
// output files.
|
||||
//
|
||||
// If you need to use different assets in different
|
||||
// environments, specify an object as the first parameter. That
|
||||
// object's keys should be the environment name and the values
|
||||
// should be the asset to use in that environment.
|
||||
//
|
||||
// If the library that you are including contains AMD or ES6
|
||||
// modules that you would like to import into your application
|
||||
// please specify an object with the list of modules as keys
|
||||
// along with the exports of each module as its value.
|
||||
app.import("node_modules/bootbox/dist/bootbox.min.js");
|
||||
app.import("node_modules/bootstrap/js/dist/util.js");
|
||||
app.import("node_modules/bootstrap/js/dist/modal.js");
|
||||
app.import("vendor/message-bus.js");
|
||||
|
||||
return app.toTree();
|
||||
};
|
||||
|
||||
/* eslint-enable */
|
|
@ -1,67 +0,0 @@
|
|||
{
|
||||
"name": "manager-client",
|
||||
"version": "0.0.0",
|
||||
"description": "Small description for manager-client goes here",
|
||||
"license": "MIT",
|
||||
"author": "",
|
||||
"directories": {
|
||||
"doc": "doc",
|
||||
"test": "tests"
|
||||
},
|
||||
"repository": "",
|
||||
"scripts": {
|
||||
"build": "ember build --environment=production",
|
||||
"lint": "npm-run-all --aggregate-output --continue-on-error --parallel lint:*",
|
||||
"start": "ember server",
|
||||
"test": "npm-run-all lint:* test:*",
|
||||
"test:ember": "ember test"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ember/jquery": "1.1.0",
|
||||
"@ember/optional-features": "^2.0.0",
|
||||
"@glimmer/component": "^1.0.2",
|
||||
"@glimmer/tracking": "^1.0.2",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"broccoli-asset-rev": "^3.0.0",
|
||||
"ember-auto-import": "^1.6.0",
|
||||
"ember-cli": "~3.22.0",
|
||||
"ember-cli-app-version": "^4.0.0",
|
||||
"ember-cli-babel": "^7.22.1",
|
||||
"ember-cli-dependency-checker": "^3.2.0",
|
||||
"ember-cli-htmlbars": "^5.3.1",
|
||||
"ember-cli-inject-live-reload": "^2.0.2",
|
||||
"ember-cli-moment-shim": "3.7.1",
|
||||
"ember-cli-sass": "8.0.1",
|
||||
"ember-cli-sri": "^2.1.1",
|
||||
"ember-cli-terser": "^4.0.0",
|
||||
"ember-data": "~3.22.0",
|
||||
"ember-export-application-global": "^2.0.1",
|
||||
"ember-fetch": "^8.0.2",
|
||||
"ember-load-initializers": "^2.1.1",
|
||||
"ember-maybe-import-regenerator": "^0.1.6",
|
||||
"ember-moment": "7.8.0",
|
||||
"ember-qunit": "^4.6.0",
|
||||
"ember-resolver": "^8.0.2",
|
||||
"ember-source": "~3.22.0",
|
||||
"ember-template-lint": "^2.14.0",
|
||||
"ember-welcome-page": "^4.0.0",
|
||||
"eslint": "^7.11.0",
|
||||
"eslint-plugin-ember": "^9.3.0",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"loader.js": "^4.7.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"qunit-dom": "^1.5.0",
|
||||
"sass": "^1.23"
|
||||
},
|
||||
"engines": {
|
||||
"node": "10.* || >= 12"
|
||||
},
|
||||
"ember": {
|
||||
"edition": "octane"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"bootbox": "^5.3",
|
||||
"bootstrap": "^4.4"
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE cross-domain-policy SYSTEM "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">
|
||||
<cross-domain-policy>
|
||||
<!-- Read this: www.adobe.com/devnet/articles/crossdomain_policy_file_spec.html -->
|
||||
|
||||
<!-- Most restrictive policy: -->
|
||||
<site-control permitted-cross-domain-policies="none"/>
|
||||
|
||||
<!-- Least restrictive policy: -->
|
||||
<!--
|
||||
<site-control permitted-cross-domain-policies="all"/>
|
||||
<allow-access-from domain="*" to-ports="*" secure="false"/>
|
||||
<allow-http-request-headers-from domain="*" headers="*" secure="false"/>
|
||||
-->
|
||||
</cross-domain-policy>
|
|
@ -1,3 +0,0 @@
|
|||
# http://www.robotstxt.org
|
||||
User-agent: *
|
||||
Disallow:
|
|
@ -1,28 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
test_page: 'tests/index.html?hidepassed',
|
||||
disable_watching: true,
|
||||
launch_in_ci: [
|
||||
'PhantomJS'
|
||||
],
|
||||
launch_in_dev: [
|
||||
'PhantomJS',
|
||||
'Chrome'
|
||||
],
|
||||
browser_start_timeout: 120,
|
||||
browser_args: {
|
||||
Chrome: {
|
||||
ci: [
|
||||
// --no-sandbox is needed when running Chrome inside a container
|
||||
process.env.CI ? '--no-sandbox' : null,
|
||||
'--headless',
|
||||
'--disable-dev-shm-usage',
|
||||
'--disable-software-rasterizer',
|
||||
'--mute-audio',
|
||||
'--remote-debugging-port=0',
|
||||
'--window-size=1440,900'
|
||||
].filter(Boolean)
|
||||
}
|
||||
}
|
||||
};
|
|
@ -1,52 +0,0 @@
|
|||
{
|
||||
"predef": [
|
||||
"document",
|
||||
"window",
|
||||
"location",
|
||||
"setTimeout",
|
||||
"$",
|
||||
"-Promise",
|
||||
"define",
|
||||
"console",
|
||||
"visit",
|
||||
"exists",
|
||||
"fillIn",
|
||||
"click",
|
||||
"keyEvent",
|
||||
"triggerEvent",
|
||||
"find",
|
||||
"findWithAssert",
|
||||
"wait",
|
||||
"DS",
|
||||
"andThen",
|
||||
"currentURL",
|
||||
"currentPath",
|
||||
"currentRouteName"
|
||||
],
|
||||
"node": false,
|
||||
"browser": false,
|
||||
"boss": true,
|
||||
"curly": true,
|
||||
"debug": false,
|
||||
"devel": false,
|
||||
"eqeqeq": true,
|
||||
"evil": true,
|
||||
"forin": false,
|
||||
"immed": false,
|
||||
"laxbreak": false,
|
||||
"newcap": true,
|
||||
"noarg": true,
|
||||
"noempty": false,
|
||||
"nonew": false,
|
||||
"nomen": false,
|
||||
"onevar": false,
|
||||
"plusplus": false,
|
||||
"regexp": false,
|
||||
"undef": true,
|
||||
"sub": true,
|
||||
"strict": false,
|
||||
"white": false,
|
||||
"eqnull": true,
|
||||
"esversion": 6,
|
||||
"unused": true
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
import { run } from "@ember/runloop";
|
||||
|
||||
export default function destroyApp(application) {
|
||||
run(application, "destroy");
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
import { module } from "qunit";
|
||||
import startApp from "../helpers/start-app";
|
||||
import destroyApp from "../helpers/destroy-app";
|
||||
import { Promise } from "rsvp";
|
||||
|
||||
export default function(name, options = {}) {
|
||||
module(name, {
|
||||
beforeEach() {
|
||||
this.application = startApp();
|
||||
|
||||
if (options.beforeEach) {
|
||||
return options.beforeEach.apply(this, arguments);
|
||||
}
|
||||
},
|
||||
|
||||
afterEach() {
|
||||
let afterEach =
|
||||
options.afterEach && options.afterEach.apply(this, arguments);
|
||||
return Promise.resolve(afterEach).then(() =>
|
||||
destroyApp(this.application)
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
import Resolver from "../../resolver";
|
||||
import config from "../../config/environment";
|
||||
|
||||
const resolver = Resolver.create();
|
||||
|
||||
resolver.namespace = {
|
||||
modulePrefix: config.modulePrefix,
|
||||
podModulePrefix: config.podModulePrefix
|
||||
};
|
||||
|
||||
export default resolver;
|
|
@ -1,18 +0,0 @@
|
|||
import Application from "../../app";
|
||||
import config from "../../config/environment";
|
||||
import { run } from "@ember/runloop";
|
||||
|
||||
export default function startApp(attrs) {
|
||||
let application;
|
||||
|
||||
// use defaults, but you can override
|
||||
let attributes = Object.assign({}, config.APP, attrs);
|
||||
|
||||
run(() => {
|
||||
application = Application.create(attributes);
|
||||
application.setupForTesting();
|
||||
application.injectTestHelpers();
|
||||
});
|
||||
|
||||
return application;
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>Manager Client Tests</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta id="preloaded-data" data-preload="{"rootUrl":"/","longPollingBaseUrl":"/"}">
|
||||
|
||||
{{content-for "head"}}
|
||||
{{content-for "test-head"}}
|
||||
|
||||
<link rel="stylesheet" href="{{rootURL}}assets/vendor.css">
|
||||
<link rel="stylesheet" href="{{rootURL}}assets/manager-client.css">
|
||||
<link rel="stylesheet" href="{{rootURL}}assets/test-support.css">
|
||||
|
||||
{{content-for "head-footer"}}
|
||||
{{content-for "test-head-footer"}}
|
||||
</head>
|
||||
<body>
|
||||
{{content-for "body"}}
|
||||
{{content-for "test-body"}}
|
||||
|
||||
<script src="/testem.js" integrity=""></script>
|
||||
<script src="{{rootURL}}assets/vendor.js"></script>
|
||||
<script src="{{rootURL}}assets/test-support.js"></script>
|
||||
<script src="{{rootURL}}assets/manager-client.js"></script>
|
||||
<script src="{{rootURL}}assets/tests.js"></script>
|
||||
|
||||
{{content-for "body-footer"}}
|
||||
{{content-for "test-body-footer"}}
|
||||
</body>
|
||||
</html>
|
|
@ -1,8 +0,0 @@
|
|||
import Application from 'manager-client/app';
|
||||
import config from 'manager-client/config/environment';
|
||||
import { setApplication } from '@ember/test-helpers';
|
||||
import { start } from 'ember-qunit';
|
||||
|
||||
setApplication(Application.create(config.APP));
|
||||
|
||||
start();
|
|
@ -1,515 +0,0 @@
|
|||
/*jshint bitwise: false*/
|
||||
(function(global, document, undefined) {
|
||||
'use strict';
|
||||
var previousMessageBus = global.MessageBus;
|
||||
|
||||
// http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
|
||||
var callbacks, clientId, failCount, shouldLongPoll, queue, responseCallbacks, uniqueId, baseUrl;
|
||||
var me, started, stopped, longPoller, pollTimeout, paused, later, jQuery, interval, chunkedBackoff;
|
||||
var delayPollTimeout;
|
||||
|
||||
var ajaxInProgress = false;
|
||||
|
||||
uniqueId = function() {
|
||||
return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||
var r, v;
|
||||
r = Math.random() * 16 | 0;
|
||||
v = c === 'x' ? r : (r & 0x3 | 0x8);
|
||||
return v.toString(16);
|
||||
});
|
||||
};
|
||||
|
||||
clientId = uniqueId();
|
||||
responseCallbacks = {};
|
||||
callbacks = [];
|
||||
queue = [];
|
||||
interval = null;
|
||||
failCount = 0;
|
||||
baseUrl = "/";
|
||||
paused = false;
|
||||
later = [];
|
||||
chunkedBackoff = 0;
|
||||
jQuery = global.jQuery;
|
||||
var hiddenProperty;
|
||||
|
||||
(function(){
|
||||
var prefixes = ["","webkit","ms","moz"];
|
||||
for(var i=0; i<prefixes.length; i++) {
|
||||
var prefix = prefixes[i];
|
||||
var check = prefix + (prefix === "" ? "hidden" : "Hidden");
|
||||
if(document[check] !== undefined ){
|
||||
hiddenProperty = check;
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
var isHidden = function() {
|
||||
if (hiddenProperty !== undefined){
|
||||
return document[hiddenProperty];
|
||||
} else {
|
||||
return !document.hasFocus;
|
||||
}
|
||||
};
|
||||
|
||||
var hasLocalStorage = (function() {
|
||||
try {
|
||||
localStorage.setItem("mbTestLocalStorage", Date.now());
|
||||
localStorage.removeItem("mbTestLocalStorage");
|
||||
return true;
|
||||
} catch(e) {
|
||||
return false;
|
||||
}
|
||||
})();
|
||||
|
||||
var updateLastAjax = function() {
|
||||
if (hasLocalStorage) {
|
||||
localStorage.setItem("__mbLastAjax", Date.now());
|
||||
}
|
||||
}
|
||||
|
||||
var hiddenTabShouldWait = function() {
|
||||
if (hasLocalStorage && isHidden()) {
|
||||
var lastAjaxCall = parseInt(localStorage.getItem("__mbLastAjax"), 10);
|
||||
var deltaAjax = Date.now() - lastAjaxCall;
|
||||
|
||||
return deltaAjax >= 0 && deltaAjax < me.minHiddenPollInterval;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
var hasonprogress = (new XMLHttpRequest()).onprogress === null;
|
||||
var allowChunked = function(){
|
||||
return me.enableChunkedEncoding && hasonprogress;
|
||||
};
|
||||
|
||||
shouldLongPoll = function() {
|
||||
return me.alwaysLongPoll || !isHidden();
|
||||
};
|
||||
|
||||
var totalAjaxFailures = 0;
|
||||
var totalAjaxCalls = 0;
|
||||
var lastAjax;
|
||||
|
||||
var processMessages = function(messages) {
|
||||
var gotData = false;
|
||||
if (!messages) return false; // server unexpectedly closed connection
|
||||
|
||||
for (var i=0; i<messages.length; i++) {
|
||||
var message = messages[i];
|
||||
gotData = true;
|
||||
for (var j=0; j<callbacks.length; j++) {
|
||||
var callback = callbacks[j];
|
||||
if (callback.channel === message.channel) {
|
||||
callback.last_id = message.message_id;
|
||||
try {
|
||||
callback.func(message.data, message.global_id, message.message_id);
|
||||
}
|
||||
catch(e){
|
||||
if(console.log) {
|
||||
console.log("MESSAGE BUS FAIL: callback " + callback.channel + " caused exception " + e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (message.channel === "/__status") {
|
||||
if (message.data[callback.channel] !== undefined) {
|
||||
callback.last_id = message.data[callback.channel];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return gotData;
|
||||
};
|
||||
|
||||
var reqSuccess = function(messages) {
|
||||
failCount = 0;
|
||||
if (paused) {
|
||||
if (messages) {
|
||||
for (var i=0; i<messages.length; i++) {
|
||||
later.push(messages[i]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return processMessages(messages);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
longPoller = function(poll, data) {
|
||||
|
||||
if (ajaxInProgress) {
|
||||
// never allow concurrent ajax reqs
|
||||
return;
|
||||
}
|
||||
|
||||
var gotData = false;
|
||||
var aborted = false;
|
||||
lastAjax = new Date();
|
||||
totalAjaxCalls += 1;
|
||||
data.__seq = totalAjaxCalls;
|
||||
|
||||
var longPoll = shouldLongPoll() && me.enableLongPolling;
|
||||
var chunked = longPoll && allowChunked();
|
||||
if (chunkedBackoff > 0) {
|
||||
chunkedBackoff--;
|
||||
chunked = false;
|
||||
}
|
||||
|
||||
var headers = {
|
||||
'X-SILENCE-LOGGER': 'true'
|
||||
};
|
||||
for (var name in me.headers){
|
||||
headers[name] = me.headers[name];
|
||||
}
|
||||
|
||||
if (!chunked){
|
||||
headers["Dont-Chunk"] = 'true';
|
||||
}
|
||||
|
||||
var dataType = chunked ? "text" : "json";
|
||||
|
||||
var handle_progress = function(payload, position) {
|
||||
|
||||
var separator = "\r\n|\r\n";
|
||||
var endChunk = payload.indexOf(separator, position);
|
||||
|
||||
if (endChunk === -1) {
|
||||
return position;
|
||||
}
|
||||
|
||||
var chunk = payload.substring(position, endChunk);
|
||||
chunk = chunk.replace(/\r\n\|\|\r\n/g, separator);
|
||||
|
||||
try {
|
||||
reqSuccess(JSON.parse(chunk));
|
||||
} catch(e) {
|
||||
if (console.log) {
|
||||
console.log("FAILED TO PARSE CHUNKED REPLY");
|
||||
console.log(data);
|
||||
}
|
||||
}
|
||||
|
||||
return handle_progress(payload, endChunk + separator.length);
|
||||
}
|
||||
|
||||
var disableChunked = function(){
|
||||
if (me.longPoll) {
|
||||
me.longPoll.abort();
|
||||
chunkedBackoff = 30;
|
||||
}
|
||||
};
|
||||
|
||||
var setOnProgressListener = function(xhr) {
|
||||
var position = 0;
|
||||
// if it takes longer than 3000 ms to get first chunk, we have some proxy
|
||||
// this is messing with us, so just backoff from using chunked for now
|
||||
var chunkedTimeout = setTimeout(disableChunked,3000);
|
||||
xhr.onprogress = function () {
|
||||
clearTimeout(chunkedTimeout);
|
||||
if(xhr.getResponseHeader('Content-Type') === 'application/json; charset=utf-8') {
|
||||
// not chunked we are sending json back
|
||||
chunked = false;
|
||||
return;
|
||||
}
|
||||
position = handle_progress(xhr.responseText, position);
|
||||
}
|
||||
};
|
||||
if (!me.ajax){
|
||||
throw new Error("Either jQuery or the ajax adapter must be loaded");
|
||||
}
|
||||
|
||||
updateLastAjax();
|
||||
|
||||
ajaxInProgress = true;
|
||||
var req = me.ajax({
|
||||
url: me.baseUrl + "message-bus/" + me.clientId + "/poll" + (!longPoll ? "?dlp=t" : ""),
|
||||
data: data,
|
||||
cache: false,
|
||||
async: true,
|
||||
dataType: dataType,
|
||||
type: 'POST',
|
||||
headers: headers,
|
||||
messageBus: {
|
||||
chunked: chunked,
|
||||
onProgressListener: function(xhr) {
|
||||
var position = 0;
|
||||
// if it takes longer than 3000 ms to get first chunk, we have some proxy
|
||||
// this is messing with us, so just backoff from using chunked for now
|
||||
var chunkedTimeout = setTimeout(disableChunked,3000);
|
||||
return xhr.onprogress = function () {
|
||||
clearTimeout(chunkedTimeout);
|
||||
if(xhr.getResponseHeader('Content-Type') === 'application/json; charset=utf-8') {
|
||||
chunked = false; // not chunked, we are sending json back
|
||||
} else {
|
||||
position = handle_progress(xhr.responseText, position);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
xhr: function() {
|
||||
var xhr = jQuery.ajaxSettings.xhr();
|
||||
if (!chunked) {
|
||||
return xhr;
|
||||
}
|
||||
this.messageBus.onProgressListener(xhr);
|
||||
return xhr;
|
||||
},
|
||||
success: function(messages) {
|
||||
if (!chunked) {
|
||||
// we may have requested text so jQuery will not parse
|
||||
if (typeof(messages) === "string") {
|
||||
messages = JSON.parse(messages);
|
||||
}
|
||||
gotData = reqSuccess(messages);
|
||||
}
|
||||
},
|
||||
error: function(xhr, textStatus, err) {
|
||||
if(textStatus === "abort") {
|
||||
aborted = true;
|
||||
} else {
|
||||
failCount += 1;
|
||||
totalAjaxFailures += 1;
|
||||
}
|
||||
},
|
||||
complete: function() {
|
||||
|
||||
ajaxInProgress = false;
|
||||
|
||||
var interval;
|
||||
try {
|
||||
if (gotData || aborted) {
|
||||
interval = me.minPollInterval;
|
||||
} else {
|
||||
interval = me.callbackInterval;
|
||||
if (failCount > 2) {
|
||||
interval = interval * failCount;
|
||||
} else if (!shouldLongPoll()) {
|
||||
interval = me.backgroundCallbackInterval;
|
||||
}
|
||||
if (interval > me.maxPollInterval) {
|
||||
interval = me.maxPollInterval;
|
||||
}
|
||||
|
||||
interval -= (new Date() - lastAjax);
|
||||
|
||||
if (interval < 100) {
|
||||
interval = 100;
|
||||
}
|
||||
}
|
||||
} catch(e) {
|
||||
if(console.log && e.message) {
|
||||
console.log("MESSAGE BUS FAIL: " + e.message);
|
||||
}
|
||||
}
|
||||
|
||||
if (pollTimeout) {
|
||||
clearTimeout(pollTimeout);
|
||||
pollTimeout = null;
|
||||
}
|
||||
|
||||
if (started) {
|
||||
pollTimeout = setTimeout(function(){
|
||||
pollTimeout = null;
|
||||
poll();
|
||||
}, interval);
|
||||
}
|
||||
|
||||
me.longPoll = null;
|
||||
}
|
||||
});
|
||||
|
||||
return req;
|
||||
};
|
||||
|
||||
me = {
|
||||
/* shared between all tabs */
|
||||
minHiddenPollInterval: 1500,
|
||||
enableChunkedEncoding: true,
|
||||
enableLongPolling: true,
|
||||
callbackInterval: 15000,
|
||||
backgroundCallbackInterval: 60000,
|
||||
minPollInterval: 100,
|
||||
maxPollInterval: 3 * 60 * 1000,
|
||||
callbacks: callbacks,
|
||||
clientId: clientId,
|
||||
alwaysLongPoll: false,
|
||||
baseUrl: baseUrl,
|
||||
headers: {},
|
||||
ajax: (jQuery && jQuery.ajax),
|
||||
noConflict: function(){
|
||||
global.MessageBus = global.MessageBus.previousMessageBus;
|
||||
return this;
|
||||
},
|
||||
diagnostics: function(){
|
||||
console.log("Stopped: " + stopped + " Started: " + started);
|
||||
console.log("Current callbacks");
|
||||
console.log(callbacks);
|
||||
console.log("Total ajax calls: " + totalAjaxCalls + " Recent failure count: " + failCount + " Total failures: " + totalAjaxFailures);
|
||||
console.log("Last ajax call: " + (new Date() - lastAjax) / 1000 + " seconds ago") ;
|
||||
},
|
||||
|
||||
pause: function() {
|
||||
paused = true;
|
||||
},
|
||||
|
||||
resume: function() {
|
||||
paused = false;
|
||||
processMessages(later);
|
||||
later = [];
|
||||
},
|
||||
|
||||
stop: function() {
|
||||
stopped = true;
|
||||
started = false;
|
||||
if (delayPollTimeout) {
|
||||
clearTimeout(delayPollTimeout);
|
||||
delayPollTimeout = null;
|
||||
}
|
||||
if (me.longPoll) {
|
||||
me.longPoll.abort();
|
||||
}
|
||||
},
|
||||
|
||||
// Start polling
|
||||
start: function() {
|
||||
var poll;
|
||||
|
||||
if (started) return;
|
||||
started = true;
|
||||
stopped = false;
|
||||
|
||||
poll = function() {
|
||||
var data;
|
||||
|
||||
if(stopped) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (callbacks.length === 0 || hiddenTabShouldWait()) {
|
||||
if(!delayPollTimeout) {
|
||||
delayPollTimeout = setTimeout(function() {
|
||||
delayPollTimeout = null;
|
||||
poll();
|
||||
}, parseInt(500 + Math.random() * 500));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
data = {};
|
||||
for (var i=0;i<callbacks.length;i++) {
|
||||
data[callbacks[i].channel] = callbacks[i].last_id;
|
||||
}
|
||||
|
||||
// could possibly already be started
|
||||
// notice the delay timeout above
|
||||
if (!me.longPoll) {
|
||||
me.longPoll = longPoller(poll, data);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// monitor visibility, issue a new long poll when the page shows
|
||||
if(document.addEventListener && 'hidden' in document){
|
||||
me.visibilityEvent = global.document.addEventListener('visibilitychange', function(){
|
||||
if(!document.hidden && !me.longPoll && pollTimeout){
|
||||
|
||||
clearTimeout(pollTimeout);
|
||||
clearTimeout(delayPollTimeout);
|
||||
|
||||
delayPollTimeout = null;
|
||||
pollTimeout = null;
|
||||
poll();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
poll();
|
||||
},
|
||||
|
||||
"status": function() {
|
||||
if (paused) {
|
||||
return "paused";
|
||||
} else if (started) {
|
||||
return "started";
|
||||
} else if (stopped) {
|
||||
return "stopped";
|
||||
} else {
|
||||
throw "Cannot determine current status";
|
||||
}
|
||||
},
|
||||
|
||||
// Subscribe to a channel
|
||||
// if lastId is 0 or larger, it will recieve messages AFTER that id
|
||||
// if lastId is negative it will perform lookbehind
|
||||
// -1 will subscribe to all new messages
|
||||
// -2 will recieve last message + all new messages
|
||||
// -3 will recieve last 2 messages + all new messages
|
||||
subscribe: function(channel, func, lastId) {
|
||||
|
||||
if(!started && !stopped){
|
||||
me.start();
|
||||
}
|
||||
|
||||
if (typeof(lastId) !== "number") {
|
||||
lastId = -1;
|
||||
}
|
||||
|
||||
if (typeof(channel) !== "string") {
|
||||
throw "Channel name must be a string!";
|
||||
}
|
||||
|
||||
callbacks.push({
|
||||
channel: channel,
|
||||
func: func,
|
||||
last_id: lastId
|
||||
});
|
||||
if (me.longPoll) {
|
||||
me.longPoll.abort();
|
||||
}
|
||||
|
||||
return func;
|
||||
},
|
||||
|
||||
// Unsubscribe from a channel
|
||||
unsubscribe: function(channel, func) {
|
||||
// TODO allow for globbing in the middle of a channel name
|
||||
// like /something/*/something
|
||||
// at the moment we only support globbing /something/*
|
||||
var glob;
|
||||
if (channel.indexOf("*", channel.length - 1) !== -1) {
|
||||
channel = channel.substr(0, channel.length - 1);
|
||||
glob = true;
|
||||
}
|
||||
|
||||
var removed = false;
|
||||
|
||||
for (var i=callbacks.length-1; i>=0; i--) {
|
||||
|
||||
var callback = callbacks[i];
|
||||
var keep;
|
||||
|
||||
if (glob) {
|
||||
keep = callback.channel.substr(0, channel.length) !== channel;
|
||||
} else {
|
||||
keep = callback.channel !== channel;
|
||||
}
|
||||
|
||||
if(!keep && func && callback.func !== func){
|
||||
keep = true;
|
||||
}
|
||||
|
||||
if (!keep) {
|
||||
callbacks.splice(i,1);
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (removed && me.longPoll) {
|
||||
me.longPoll.abort();
|
||||
}
|
||||
|
||||
return removed;
|
||||
}
|
||||
};
|
||||
global.MessageBus = me;
|
||||
})(window, document);
|
11369
manager-client/yarn.lock
11369
manager-client/yarn.lock
File diff suppressed because it is too large
Load Diff
|
@ -18,11 +18,6 @@ module ::DockerManager
|
|||
end
|
||||
end
|
||||
|
||||
assets = Rails.configuration.assets
|
||||
|
||||
assets.precompile += ['docker-manager-app.js', 'docker-manager-app.css', 'docker-manager-vendor.js', 'docker-manager-vendor.css', 'images/docker-manager.png']
|
||||
assets.skip_minification += ['docker-manager-app.js', 'docker-manager-vendor.js']
|
||||
|
||||
after_initialize do
|
||||
Discourse::Application.routes.append do
|
||||
mount ::DockerManager::Engine, at: "/"
|
||||
|
|
Loading…
Reference in New Issue