DEV: Move stuff to the regular plugin structure

This commit is contained in:
Jarek Radosz 2023-01-15 20:15:23 +01:00
parent 528d7adc4a
commit 2bba7f62b2
73 changed files with 22 additions and 12700 deletions

View File

@ -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

View File

@ -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>

View File

@ -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" });
});
},
};

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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'
}
}
]
};

View File

@ -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

View File

@ -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
}

View File

@ -1,5 +0,0 @@
'use strict';
module.exports = {
extends: 'octane'
};

View File

@ -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

View File

@ -1,3 +0,0 @@
{
"ignore_dirs": ["tmp", "dist"]
}

View File

@ -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/)

View File

@ -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);

View File

@ -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 */

View File

@ -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="{&quot;rootUrl&quot;:&quot;/&quot;,&quot;longPollingBaseUrl&quot;:&quot;/&quot;}">
{{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>

View File

@ -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);
}
});
});
},
};

View File

@ -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("/");
}
},
};

View File

@ -1,3 +0,0 @@
import Resolver from 'ember-resolver';
export default Resolver;

View File

@ -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" });
});

View File

@ -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"
]
}
]
}
]
}

View File

@ -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 */

View File

@ -1,6 +0,0 @@
{
"application-template-wrapper": false,
"default-async-observers": true,
"jquery-integration": true,
"template-only-glimmer-components": true
}

View File

@ -1,11 +0,0 @@
'use strict';
const browsers = [
'last 1 Chrome versions',
'last 1 Firefox versions',
'last 1 Safari versions'
];
module.exports = {
browsers
};

View File

@ -1,4 +0,0 @@
#!/bin/bash
ember serve --proxy "http://localhost:${1:-3000}"

View File

@ -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 */

View File

@ -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"
}
}

View File

@ -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>

View File

@ -1,3 +0,0 @@
# http://www.robotstxt.org
User-agent: *
Disallow:

View File

@ -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)
}
}
};

View File

@ -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
}

View File

@ -1,5 +0,0 @@
import { run } from "@ember/runloop";
export default function destroyApp(application) {
run(application, "destroy");
}

View File

@ -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)
);
}
});
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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="{&quot;rootUrl&quot;:&quot;/&quot;,&quot;longPollingBaseUrl&quot;:&quot;/&quot;}">
{{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>

View File

@ -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();

View File

View File

@ -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);

File diff suppressed because it is too large Load Diff

View File

@ -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: "/"