1
0
mirror of https://github.com/ansible/awx.git synced 2024-10-27 17:55:10 +03:00

Update UI build system

* Faster build times
* Smaller bundle sizes
* Adjust paths
* Cleanup npm dependencies
* Remove unneded Grunt tasks
This commit is contained in:
gconsidine 2017-09-07 18:09:14 -04:00
parent b565fd2ec1
commit c57c17546e
No known key found for this signature in database
GPG Key ID: CC78E4D5913BB71D
81 changed files with 1212 additions and 7104 deletions

View File

@ -17,38 +17,4 @@ module.exports = function(grunt) {
grunt.initConfig(configs);
grunt.loadNpmTasks('grunt-newer');
grunt.loadNpmTasks('grunt-angular-gettext');
// writes environment variables for development. current manages:
// browser-sync + websocket proxy
grunt.registerTask('sync', [
'browserSync:http',
'concurrent:watch'
]);
grunt.registerTask('dev', [
'clean:tmp',
'clean:static',
'concurrent:dev',
'concat:css',
'webpack:dev',
'sync'
]);
grunt.registerTask('devNoSync', [
'clean:tmp',
'clean:static',
'concurrent:devNoSync',
'concat:css'
]);
grunt.registerTask('release', [
'clean:tmp',
'clean:static',
'concurrent:prod',
'webpack:prod',
'concat:css',
'cssmin:vendor',
'cssmin:source'
]);
};

View File

@ -0,0 +1,198 @@
const path = require('path');
const webpack = require('webpack');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CLIENT_PATH = path.resolve(__dirname, '../client');
const LIB_PATH = path.join(CLIENT_PATH, 'lib');
const UI_PATH = path.resolve(__dirname, '..');
const ASSETS_PATH = path.join(CLIENT_PATH, 'assets');
const COMPONENTS_PATH = path.join(LIB_PATH, 'components');
const COVERAGE_PATH = path.join(UI_PATH, 'coverage');
const FEATURES_PATH = path.join(CLIENT_PATH, 'features');
const LANGUAGES_PATH = path.join(CLIENT_PATH, 'languages');
const MODELS_PATH = path.join(LIB_PATH, 'models');
const NODE_MODULES_PATH = path.join(UI_PATH, 'node_modules');
const SERVICES_PATH = path.join(LIB_PATH, 'services');
const SOURCE_PATH = path.join(CLIENT_PATH, 'src');
const STATIC_PATH = path.join(UI_PATH, 'static');
const APP_ENTRY = path.join(SOURCE_PATH, 'app.js');
const VENDOR_ENTRY = path.join(SOURCE_PATH, 'vendor.js');
const INDEX_ENTRY = path.join(CLIENT_PATH, 'index.template.html');
const INDEX_OUTPUT = path.join(UI_PATH, 'templates/ui/index.html');
const THEME_ENTRY = path.join(LIB_PATH, 'theme', 'index.less');
const OUTPUT = 'js/[name].[hash].js';
const CHUNKS = ['vendor', 'app'];
const VENDOR = VENDOR_ENTRY;
const APP = [THEME_ENTRY, APP_ENTRY];
let base = {
entry: {
vendor: VENDOR,
app: APP
},
output: {
path: STATIC_PATH,
publicPath: '{{ STATIC_URL }}',
filename: OUTPUT
},
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
use: {
loader: 'css-loader',
options: {
url: false
}
}
})
},
{
test: /\lib\/theme\/index.less$/,
use: ExtractTextPlugin.extract({
use: ['css-loader', 'less-loader']
})
},
{
test: require.resolve('jquery'),
loader: 'expose-loader?$!expose-loader?jQuery!expose-loader?jquery'
},
{
loader: 'script-loader',
test: [
/node_modules\/javascript-detect-element-resize\/jquery.resize\.js$/,
/node_modules\/d3\/d3\.min.js$/
]
},
{
test: /\.js$/,
use: 'imports-loader?define=>false'
},
{
test: /\.html$/,
use: ['ngtemplate-loader', 'html-loader'],
include: [
/lib\/components\//,
/features\//
]
},
{
test: /\.json$/,
loader: 'json-loader',
exclude: /node_modules/
}
]
},
plugins: [
new webpack.ProvidePlugin({
jsyaml: 'js-yaml',
CodeMirror: 'codemirror',
jsonlint: 'codemirror.jsonlint',
_: 'lodash'
}),
new ExtractTextPlugin('css/[name].[hash].css'),
new CleanWebpackPlugin([STATIC_PATH, COVERAGE_PATH], {
root: UI_PATH,
}),
new CopyWebpackPlugin([
{
from: path.join(ASSETS_PATH, 'fontcustom/**/*'),
to: path.join(STATIC_PATH, 'fonts/'),
flatten: true
},
{
from: path.join(NODE_MODULES_PATH, 'components-font-awesome/fonts/*'),
to: path.join(STATIC_PATH, 'fonts/'),
flatten: true
},
{
from: path.join(ASSETS_PATH, 'custom-theme/images.new/*'),
to: path.join(STATIC_PATH, 'images/'),
flatten: true
},
{
from: path.join(LANGUAGES_PATH, '*'),
to: path.join(STATIC_PATH, 'languages'),
flatten: true
},
{
from: ASSETS_PATH,
to: path.join(STATIC_PATH, 'assets')
},
{
from: path.join(NODE_MODULES_PATH, 'angular-scheduler/lib/*.html'),
to: path.join(STATIC_PATH, 'lib'),
context: NODE_MODULES_PATH
},
{
from: path.join(NODE_MODULES_PATH, 'angular-tz-extensions/tz/data/*'),
to: path.join(STATIC_PATH, 'lib/'),
context: NODE_MODULES_PATH
},
{
from: path.join(SOURCE_PATH, '**/*.partial.html'),
to: path.join(STATIC_PATH, 'partials/'),
context: SOURCE_PATH
},
{
from: path.join(SOURCE_PATH, 'partials', '*.html'),
to: STATIC_PATH,
context: SOURCE_PATH
},
{
from: path.join(SOURCE_PATH, '*config.js'),
to: STATIC_PATH,
flatten: true
}
]),
new HtmlWebpackPlugin({
alwaysWriteToDisk: true,
template: INDEX_ENTRY,
filename: INDEX_OUTPUT,
inject: 'head',
chunks: CHUNKS,
chunksSortMode: (moduleA, moduleB) => {
moduleA.files.sort((fileA, fileB) => fileA.includes('js') ? -1 : 1)
moduleB.files.sort((fileA, fileB) => fileA.includes('js') ? -1 : 1)
return moduleA.names[0] === 'vendor' ? -1 : 1
}
})
],
resolve: {
alias: {
'@features': FEATURES_PATH,
'@models': MODELS_PATH,
'@services': SERVICES_PATH,
'@components': COMPONENTS_PATH,
'@modules': NODE_MODULES_PATH,
'@assets': ASSETS_PATH,
'd3$': '@modules/d3/d3.min.js',
'codemirror.jsonlint$': '@modules/codemirror/addon/lint/json-lint.js',
'jquery-resize$': '@modules/javascript-detect-element-resize/jquery.resize.js',
'select2$': '@modules/select2/dist/js/select2.full.min.js',
'js-yaml$': '@modules/js-yaml/dist/js-yaml.min.js',
'lr-infinite-scroll$': '@modules/lr-infinite-scroll/lrInfiniteScroll.js',
'angular-ui-router$': '@modules/angular-ui-router/release/angular-ui-router.js',
'angular-ui-router-state-events$': '@modules/angular-ui-router/release/stateEvents.js',
'ng-toast-provider$': '@modules/ng-toast/src/scripts/provider.js',
'ng-toast-directives$': '@modules/ng-toast/src/scripts/directives.js',
'ng-toast$': '@modules/ng-toast/src/scripts/module.js'
}
}
};
module.exports = base;

View File

@ -0,0 +1,11 @@
const path = require('path');
const _ = require('lodash');
let base = require('./webpack.base');
let development = {
devtool: 'cheap-source-map'
};
module.exports = _.merge(base, development);

View File

@ -0,0 +1,19 @@
const _ = require('lodash');
const webpack = require('webpack');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
let base = require('./webpack.base');
let production = {
plugins: [
new UglifyJSPlugin({
compress: true,
mangle: false
})
]
};
production.plugins = base.plugins.concat(production.plugins)
module.exports = _.merge(base, production);

View File

@ -0,0 +1,21 @@
const path = require('path');
const _ = require('lodash');
const webpack = require('webpack');
const STATIC_URL = '/static/';
let development = require('./webpack.development');
let test = {
plugins: [
new webpack.DefinePlugin({
$basePath: STATIC_URL
})
]
};
test.plugins = development.plugins.concat(test.plugins)
module.exports = _.merge(development, test);

View File

@ -0,0 +1,43 @@
const path = require('path');
const _ = require('lodash');
const webpack = require('webpack');
const HtmlWebpackHarddiskPlugin = require('html-webpack-harddisk-plugin');
const TARGET_PORT = _.get(process.env, 'npm_package_config_django_port', 8043);
const TARGET_HOST = _.get(process.env, 'npm_package_config_django_host', 'https://localhost');
const TARGET = `https://${TARGET_HOST}:${TARGET_PORT}`;
const STATIC_URL = '/static/';
let development = require('./webpack.development');
let watch = {
plugins: [
new HtmlWebpackHarddiskPlugin(),
new webpack.HotModuleReplacementPlugin()
],
devServer: {
contentBase: path.resolve(__dirname, '..', 'static'),
publicPath: STATIC_URL,
clientLogLevel: 'info',
host: '127.0.0.1',
port: 3000,
proxy: {
'/': {
target: TARGET,
secure: false,
ws: false
},
'/websocket': {
target: TARGET,
secure: false,
ws: true
}
}
}
};
watch.plugins = development.plugins.concat(watch.plugins)
module.exports = _.merge(development, watch);

View File

@ -3,6 +3,8 @@ import AddController from './add-credentials.controller';
import EditController from './edit-credentials.controller';
import CredentialsStrings from './credentials.strings'
const addEditTemplate = require('@features/credentials/add-edit-credentials.view.html');
function CredentialsResolve ($q, $stateParams, Me, Credential, CredentialType, Organization) {
let id = $stateParams.credential_id;
@ -69,7 +71,7 @@ function CredentialsConfig ($stateExtenderProvider, legacyProvider, pathProvider
},
views: {
'add@credentials': {
templateUrl: path.getViewPath('credentials/add-edit-credentials'),
templateUrl: addEditTemplate,
controller: AddController,
controllerAs: 'vm'
}
@ -92,7 +94,7 @@ function CredentialsConfig ($stateExtenderProvider, legacyProvider, pathProvider
},
views: {
'edit@credentials': {
templateUrl: path.getViewPath('credentials/add-edit-credentials'),
templateUrl: addEditTemplate,
controller: EditController,
controllerAs: 'vm'
}

View File

@ -5,6 +5,8 @@ import OrganizationList from '../../src/organizations/organizations.list';
import ListController from '../../src/credentials/list/credentials-list.controller';
import { N_ } from '../../src/i18n';
const indexTemplate = require('@features/credentials/index.view.html');
function LegacyCredentialsService (pathService) {
this.list = {
name: 'credentials',
@ -18,7 +20,7 @@ function LegacyCredentialsService (pathService) {
},
views: {
'@': {
templateUrl: pathService.getViewPath('credentials/index')
templateUrl: indexTemplate
},
'list@credentials': {
templateProvider: function(CredentialList, generateList) {

View File

@ -0,0 +1,153 @@
<!DOCTYPE html>
<html lang="en" ng-app="awApp">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="shortcut icon" href="{{ STATIC_URL }}assets/favicon.ico?v={{version}}" />
<title ng-bind="tabTitle"></title>
<script>var $basePath = '{{ STATIC_URL }}'</script>
</head>
<body data-user-agent="{{userAgent}}">
<at-layout>
<bread-crumb></bread-crumb>
<toast></toast>
<div class="container-fluid" id="content-container">
<div class="row">
<div class="col-lg-12" ui-view>
</div>
</div>
<!-- Password Dialog -->
<div id="password-modal" style="display: none;"></div>
<div id="idle-modal" style="display:none" translate>Your session will expire in <span id="remaining_seconds" class="IdleModal-remainingSeconds">60</span> seconds, would you like to continue?</div>
<stream-detail-modal></stream-detail-modal>
<!-- Confirmation Dialog -->
<div id="prompt-modal" class="modal fade">
<div class="modal-dialog">
<div class="Modal-content modal-content">
<div class="Modal-header">
<div class="Modal-title" ng-bind="promptHeader" id="prompt-header"></div>
<div class="Modal-exitHolder">
<button class="close Modal-exit" data-target="#prompt-modal" data-dismiss="modal" aria-hidden="true"><i class="fa fa-times-circle"></i></button>
</div>
</div>
<div class="Modal-body" ng-bind-html="promptBody" id="prompt-body">
</div>
<div class="Modal-footer">
<a href="#" data-target="#prompt-modal" data-dismiss="modal" id="prompt_cancel_btn" class="btn Modal-defaultButton Modal-footerButton" translate>CANCEL</a>
<a href="" ng-class="promptActionBtnClass" ng-click="promptAction()" id="prompt_action_btn" class="btn Modal-footerButton" ng-bind="promptActionText"></a>
</div>
</div>
<!-- modal-content -->
</div>
<!-- modal-dialog -->
</div>
<!-- modal -->
<!-- Alerts/error handling dialogs -->
<div id="alert-modal" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" ng-hide="disableButtons" data-target="#alert-modal" data-dismiss="modal" class="modal" aria-hidden="true"><i class="fa fa-times-circle"></i></button>
<h3 id="alertHeader" ng-bind="alertHeader"></h3>
</div>
<div class="modal-body">
<div id="alert-modal-msg" class="alert" ng-bind-html="alertBody"></div>
</div>
<div class="modal-footer">
<a href="#" ng-hide="disableButtons" data-target="#form-modal" data-dismiss="modal" id="alert_ok_btn" class="btn btn-default" translate>OK</a>
</div>
</div>
<!-- modal-content -->
</div>
<!-- modal-dialog -->
</div>
<!-- modal -->
<div id="alert-modal2" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-target="#alert-modal2" data-dismiss="modal" ng-hide="disableButtons2" aria-hidden="true">&times;</button>
<h3 id="alertHeader2" ng-bind="alertHeader2"></h3>
</div>
<div class="modal-body">
<div id="alert2-modal-msg" class="alert" ng-bind-html="alertBody2"></div>
</div>
<div class="modal-footer">
<a href="#" ng-hide="disableButtons2" data-target="#form-modal2" data-dismiss="modal" id="alert2_ok_btn" class="btn btn-primary">OK</a>
</div>
</div>
<!-- modal-content -->
</div>
<!-- modal-dialog -->
</div>
<!-- modal -->
<div id="login-modal-dialog" style="display: none;"></div>
<div id="help-modal-dialog" style="display: none;"></div>
<div id="prompt-for-days" style="display:none">
<form name="prompt_for_days_form" id="prompt_for_days_form" class="MgmtCards-promptText">
<span translate>Set how many days of data should be retained.</span>
<br>
<input type="integer" id="days_to_keep" name="days_to_keep" ng-model="days_to_keep" ng-required="true" class="form-control Form-textInput" min=0 max=9999 style="margin-top:10px;" integer>
<div class="error" ng-show="prompt_for_days_form.days_to_keep.$dirty && (prompt_for_days_form.days_to_keep.$error.number || prompt_for_days_form.days_to_keep.$error.integer ||
prompt_for_days_form.days_to_keep.$error.required ||
prompt_for_days_form.days_to_keep.$error.min ||
prompt_for_days_form.days_to_keep.$error.max)" translate>Please enter an integer<span ng-show="prompt_for_days_form.days_to_keep.$dirty && prompt_for_days_form.days_to_keep.$error.min"> that is not negative</span><span ng-show="prompt_for_days_form.days_to_keep.$dirty && prompt_for_days_form.days_to_keep.$error.max"> that is lower than 9999</span>.</div>
</form>
</div>
<div id="prompt-for-days-facts" style="display:none">
<form name="prompt_for_days_facts_form" id="prompt_for_days_facts_form" class="MgmtCards-promptText">
<div style="padding-bottom:15px;"><span translate>For facts collected older than the time period specified, save one fact scan (snapshot) per time window (frequency). For example, facts older than 30 days are purged, while one weekly fact scan is kept.</span>
<br>
<br>
<span translate>CAUTION: Setting both numerical variables to "0" will delete all facts.</span>
<br>
<br>
</div>
<div class="form-group">
<label for="description">
<span class="label-text" translate>Select a time period after which to remove old facts</span>
</label>
<div class="row">
<div class="col-xs-6">
<input type="integer" id="keep_amount" name="keep_amount" ng-model="keep_amount" ng-required="true" class="form-control Form-textInput MgmtCards-card--promptElements" min=0 max=9999 integer></input>
</div>
<div class="col-xs-6">
<select id="keep_unit" name="keep_unit" ng-model="keep_unit" ng-options="type.label for type in keep_unit_choices track by type.value" ng-required="true" class="form-control MgmtCards-card--promptElements"></select>
</div>
</div>
<div class="error" ng-show="prompt_for_days_facts_form.keep_amount.$dirty && (prompt_for_days_facts_form.keep_amount.$error.number || prompt_for_days_facts_form.keep_amount.$error.integer ||
prompt_for_days_facts_form.keep_amount.$error.required ||
prompt_for_days_facts_form.keep_amount.$error.min ||
prompt_for_days_facts_form.keep_amount.$error.max)" translate>Please enter an integer<span ng-show="prompt_for_days_facts_form.keep_amount.$dirty && prompt_for_days_facts_form.keep_amount.$error.min"> that is not negative</span><span ng-show="prompt_for_days_facts_form.keep_amount.$dirty && prompt_for_days_facts_form.keep_amount.$error.max"> that is lower than 9999</span>.</div>
</div>
<div class="form-group ">
<label for="description">
<span class="label-text" translate>Select a frequency for snapshot retention</span>
</label>
<div class="row">
<div class="col-xs-6">
<input type="integer" id="granularity_keep_amount" name="granularity_keep_amount" ng-model="granularity_keep_amount" ng-required="true" class="form-control Form-textInput MgmtCards-card--promptElements" min=0 max=9999 integer></input>
</div>
<div class="col-xs-6">
<select id="granularity_keep_unit" name="granularity_keep_unit" ng-model="granularity_keep_unit" ng-options="type.label for type in granularity_keep_unit_choices track by type.value" ng-required="true" class="form-control MgmtCards-card--promptElements"></select>
</div>
</div>
<div class="error" ng-show="prompt_for_days_facts_form.granularity_keep_amount.$dirty && (prompt_for_days_facts_form.granularity_keep_amount.$error.number || prompt_for_days_facts_form.granularity_keep_amount.$error.integer ||
prompt_for_days_facts_form.granularity_keep_amount.$error.required ||
prompt_for_days_facts_form.granularity_keep_amount.$error.min ||
prompt_for_days_facts_form.granularity_keep_amount.$error.max)" translate>Please enter an integer<span ng-show="prompt_for_days_facts_form.granularity_keep_amount.$dirty && prompt_for_days_facts_form.granularity_keep_amount.$error.min"> that is not negative</span><span ng-show="prompt_for_days_facts_form.granularity_keep_amount.$dirty && prompt_for_days_facts_form.granularity_keep_amount.$error.max"> that is lower than 9999</span>.</div>
</div>
</form>
</div>
<div class="overlay"></div>
<div class="spinny"><i class="fa fa-cog fa-spin fa-2x"></i>
<p translate>working...</p>
</div>
</div>
</at-layout>
</body>
</html>

View File

@ -1,9 +1,11 @@
function atActionGroup (pathService) {
const templateUrl = require('@components/action/action-group.partial.html');
function atActionGroup () {
return {
restrict: 'E',
replace: true,
transclude: true,
templateUrl: pathService.getPartialPath('components/action/action-group'),
templateUrl,
scope: {
col: '@',
pos: '@'
@ -11,6 +13,4 @@ function atActionGroup (pathService) {
};
}
atActionGroup.$inject = ['PathService'];
export default atActionGroup;

View File

@ -1,3 +1,5 @@
const templateUrl = require('@components/form/action.partial.html');
function link (scope, element, attrs, controllers) {
let formController = controllers[0];
let actionController = controllers[1];
@ -52,13 +54,13 @@ function atFormActionController ($state, strings) {
atFormActionController.$inject = ['$state', 'ComponentsStrings'];
function atFormAction (pathService) {
function atFormAction () {
return {
restrict: 'E',
transclude: true,
replace: true,
require: ['^^atForm', 'atFormAction'],
templateUrl: pathService.getPartialPath('components/form/action'),
templateUrl,
controller: atFormActionController,
controllerAs: 'vm',
link,
@ -70,6 +72,4 @@ function atFormAction (pathService) {
};
}
atFormAction.$inject = ['PathService'];
export default atFormAction;

View File

@ -1,3 +1,5 @@
const templateUrl = require('@components/form/form.partial.html');
function atFormLink (scope, el, attrs, controllers) {
let formController = controllers[0];
let form = el[0];
@ -195,13 +197,13 @@ function AtFormController (eventService, strings) {
AtFormController.$inject = ['EventService', 'ComponentsStrings'];
function atForm (pathService) {
function atForm () {
return {
restrict: 'E',
replace: true,
transclude: true,
require: ['atForm'],
templateUrl: pathService.getPartialPath('components/form/form'),
templateUrl,
controller: AtFormController,
controllerAs: 'vm',
link: atFormLink,
@ -211,6 +213,4 @@ function atForm (pathService) {
};
}
atForm.$inject = ['PathService'];
export default atForm;

View File

@ -1,39 +1,35 @@
import layout from './layout/layout.directive';
import topNavItem from './layout/top-nav-item.directive';
import sideNav from './layout/side-nav.directive';
import sideNavItem from './layout/side-nav-item.directive';
import actionGroup from './action/action-group.directive';
import divider from './utility/divider.directive';
import form from './form/form.directive';
import formAction from './form/action.directive';
import inputCheckbox from './input/checkbox.directive';
import inputGroup from './input/group.directive';
import inputLabel from './input/label.directive';
import inputLookup from './input/lookup.directive';
import inputMessage from './input/message.directive';
import inputSecret from './input/secret.directive';
import inputSelect from './input/select.directive';
import inputText from './input/text.directive';
import inputTextarea from './input/textarea.directive';
import inputTextareaSecret from './input/textarea-secret.directive';
import modal from './modal/modal.directive';
import panel from './panel/panel.directive';
import panelHeading from './panel/heading.directive';
import panelBody from './panel/body.directive';
import popover from './popover/popover.directive';
import tab from './tabs/tab.directive';
import tabGroup from './tabs/group.directive';
import truncate from './truncate/truncate.directive';
import actionGroup from '@components/action/action-group.directive';
import divider from '@components/utility/divider.directive';
import form from '@components/form/form.directive';
import formAction from '@components/form/action.directive';
import inputCheckbox from '@components/input/checkbox.directive';
import inputGroup from '@components/input/group.directive';
import inputLabel from '@components/input/label.directive';
import inputLookup from '@components/input/lookup.directive';
import inputMessage from '@components/input/message.directive';
import inputSecret from '@components/input/secret.directive';
import inputSelect from '@components/input/select.directive';
import inputText from '@components/input/text.directive';
import inputTextarea from '@components/input/textarea.directive';
import inputTextareaSecret from '@components/input/textarea-secret.directive';
import layout from '@components/layout/layout.directive';
import modal from '@components/modal/modal.directive';
import panel from '@components/panel/panel.directive';
import panelBody from '@components/panel/body.directive';
import panelHeading from '@components/panel/heading.directive';
import popover from '@components/popover/popover.directive';
import sideNav from '@components/layout/side-nav.directive';
import sideNavItem from '@components/layout/side-nav-item.directive';
import tab from '@components/tabs/tab.directive';
import tabGroup from '@components/tabs/group.directive';
import topNavItem from '@components/layout/top-nav-item.directive';
import truncate from '@components/truncate/truncate.directive';
import BaseInputController from './input/base.controller';
import ComponentsStrings from './components.strings';
import BaseInputController from '@components/input/base.controller';
import ComponentsStrings from '@components/components.strings';
angular
.module('at.lib.components', [])
.directive('atLayout', layout)
.directive('atTopNavItem', topNavItem)
.directive('atSideNav', sideNav)
.directive('atSideNavItem', sideNavItem)
.directive('atActionGroup', actionGroup)
.directive('atDivider', divider)
.directive('atForm', form)
@ -48,13 +44,17 @@ angular
.directive('atInputText', inputText)
.directive('atInputTextarea', inputTextarea)
.directive('atInputTextareaSecret', inputTextareaSecret)
.directive('atLayout', layout)
.directive('atModal', modal)
.directive('atPanel', panel)
.directive('atPanelHeading', panelHeading)
.directive('atPanelBody', panelBody)
.directive('atPanelHeading', panelHeading)
.directive('atPopover', popover)
.directive('atSideNav', sideNav)
.directive('atSideNavItem', sideNavItem)
.directive('atTab', tab)
.directive('atTabGroup', tabGroup)
.directive('atTopNavItem', topNavItem)
.directive('atTruncate', truncate)
.service('ComponentsStrings', ComponentsStrings)
.service('BaseInputController', BaseInputController);
.service('BaseInputController', BaseInputController)
.service('ComponentsStrings', ComponentsStrings);

View File

@ -1,3 +1,5 @@
const templateUrl = require('@components/input/checkbox.partial.html');
function atInputCheckboxLink (scope, element, attrs, controllers) {
let formController = controllers[0];
let inputController = controllers[1];
@ -23,13 +25,13 @@ function AtInputCheckboxController (baseInputController) {
AtInputCheckboxController.$inject = ['BaseInputController'];
function atInputCheckbox (pathService) {
function atInputCheckbox () {
return {
restrict: 'E',
transclude: true,
replace: true,
require: ['^^atForm', 'atInputCheckbox'],
templateUrl: pathService.getPartialPath('components/input/checkbox'),
templateUrl,
controller: AtInputCheckboxController,
controllerAs: 'vm',
link: atInputCheckboxLink,
@ -41,6 +43,4 @@ function atInputCheckbox (pathService) {
};
}
atInputCheckbox.$inject = ['PathService'];
export default atInputCheckbox;

View File

@ -1,3 +1,5 @@
const templateUrl = require('@components/input/group.partial.html');
function atInputGroupLink (scope, el, attrs, controllers) {
let groupController = controllers[0];
let formController = controllers[1];
@ -168,13 +170,13 @@ function AtInputGroupController ($scope, $compile) {
AtInputGroupController.$inject = ['$scope', '$compile'];
function atInputGroup (pathService) {
function atInputGroup () {
return {
restrict: 'E',
replace: true,
transclude: true,
require: ['atInputGroup', '^^atForm'],
templateUrl: pathService.getPartialPath('components/input/group'),
templateUrl,
controller: AtInputGroupController,
controllerAs: 'vm',
link: atInputGroupLink,
@ -186,6 +188,4 @@ function atInputGroup (pathService) {
};
}
atInputGroup.$inject = ['PathService'];
export default atInputGroup;

View File

@ -1,11 +1,11 @@
function atInputLabel (pathService) {
const templateUrl = require('@components/input/label.partial.html');
function atInputLabel () {
return {
restrict: 'E',
replace: true,
templateUrl: pathService.getPartialPath('components/input/label')
templateUrl
};
}
atInputLabel.$inject = ['PathService'];
export default atInputLabel;

View File

@ -1,3 +1,5 @@
const templateUrl = require('@components/input/lookup.partial.html');
const DEFAULT_DEBOUNCE = 250;
const DEFAULT_KEY = 'name';
@ -120,13 +122,13 @@ AtInputLookupController.$inject = [
'$stateParams'
];
function atInputLookup (pathService) {
function atInputLookup () {
return {
restrict: 'E',
transclude: true,
replace: true,
require: ['^^atForm', 'atInputLookup'],
templateUrl: pathService.getPartialPath('components/input/lookup'),
templateUrl,
controller: AtInputLookupController,
controllerAs: 'vm',
link: atInputLookupLink,
@ -138,6 +140,4 @@ function atInputLookup (pathService) {
};
}
atInputLookup.$inject = ['PathService'];
export default atInputLookup;

View File

@ -1,11 +1,11 @@
function atInputMessage (pathService) {
const templateUrl = require('@components/input/message.partial.html');
function atInputMessage () {
return {
restrict: 'E',
replace: true,
templateUrl: pathService.getPartialPath('components/input/message'),
templateUrl
};
}
atInputMessage.$inject = ['PathService'];
export default atInputMessage;

View File

@ -1,3 +1,5 @@
const templateUrl = require('@components/input/secret.partial.html');
function atInputSecretLink (scope, element, attrs, controllers) {
let formController = controllers[0];
let inputController = controllers[1];
@ -48,13 +50,13 @@ function AtInputSecretController (baseInputController) {
AtInputSecretController.$inject = ['BaseInputController'];
function atInputSecret (pathService) {
function atInputSecret () {
return {
restrict: 'E',
transclude: true,
replace: true,
require: ['^^atForm', 'atInputSecret'],
templateUrl: pathService.getPartialPath('components/input/secret'),
templateUrl,
controller: AtInputSecretController,
controllerAs: 'vm',
link: atInputSecretLink,
@ -66,6 +68,4 @@ function atInputSecret (pathService) {
};
}
atInputSecret.$inject = ['PathService'];
export default atInputSecret;

View File

@ -1,3 +1,5 @@
const templateUrl = require('@components/input/select.partial.html');
function atInputSelectLink (scope, element, attrs, controllers) {
let formController = controllers[0];
let inputController = controllers[1];
@ -72,13 +74,13 @@ function AtInputSelectController (baseInputController, eventService) {
AtInputSelectController.$inject = ['BaseInputController', 'EventService'];
function atInputSelect (pathService) {
function atInputSelect () {
return {
restrict: 'E',
transclude: true,
replace: true,
require: ['^^at-form', 'atInputSelect'],
templateUrl: pathService.getPartialPath('components/input/select'),
templateUrl,
controller: AtInputSelectController,
controllerAs: 'vm',
link: atInputSelectLink,
@ -90,6 +92,4 @@ function atInputSelect (pathService) {
};
}
atInputSelect.$inject = ['PathService'];
export default atInputSelect;

View File

@ -1,3 +1,5 @@
const templateUrl = require('@components/input/text.partial.html');
function atInputTextLink (scope, element, attrs, controllers) {
let formController = controllers[0];
let inputController = controllers[1];
@ -21,13 +23,13 @@ function AtInputTextController (baseInputController) {
AtInputTextController.$inject = ['BaseInputController'];
function atInputText (pathService) {
function atInputText () {
return {
restrict: 'E',
transclude: true,
replace: true,
require: ['^^atForm', 'atInputText'],
templateUrl: pathService.getPartialPath('components/input/text'),
templateUrl,
controller: AtInputTextController,
controllerAs: 'vm',
link: atInputTextLink,
@ -39,6 +41,4 @@ function atInputText (pathService) {
};
}
atInputText.$inject = ['PathService'];
export default atInputText;

View File

@ -1,3 +1,5 @@
const templateUrl = require('@components/input/textarea-secret.partial.html');
function atInputTextareaSecretLink (scope, element, attrs, controllers) {
let formController = controllers[0];
let inputController = controllers[1];
@ -96,13 +98,13 @@ AtInputTextareaSecretController.$inject = [
'ComponentsStrings'
];
function atInputTextareaSecret (pathService) {
function atInputTextareaSecret () {
return {
restrict: 'E',
transclude: true,
replace: true,
require: ['^^atForm', 'atInputTextareaSecret'],
templateUrl: pathService.getPartialPath('components/input/textarea-secret'),
templateUrl,
controller: AtInputTextareaSecretController,
controllerAs: 'vm',
link: atInputTextareaSecretLink,
@ -114,6 +116,4 @@ function atInputTextareaSecret (pathService) {
};
}
atInputTextareaSecret.$inject = ['PathService'];
export default atInputTextareaSecret;

View File

@ -1,3 +1,5 @@
const templateUrl = require('@components/input/textarea.partial.html');
function atInputTextareaLink (scope, element, attrs, controllers) {
let formController = controllers[0];
let inputController = controllers[1];
@ -21,13 +23,13 @@ function AtInputTextareaController (baseInputController) {
AtInputTextareaController.$inject = ['BaseInputController'];
function atInputTextarea (pathService) {
function atInputTextarea () {
return {
restrict: 'E',
transclude: true,
replace: true,
require: ['^^atForm', 'atInputTextarea'],
templateUrl: pathService.getPartialPath('components/input/textarea'),
templateUrl,
controller: AtInputTextareaController,
controllerAs: 'vm',
link: atInputTextareaLink,
@ -39,6 +41,4 @@ function atInputTextarea (pathService) {
};
}
atInputTextarea.$inject = ['PathService'];
export default atInputTextarea;

View File

@ -1,3 +1,5 @@
const templateUrl = require('@components/layout/layout.partial.html');
function AtLayoutController ($scope, strings) {
let vm = this || {};
@ -34,12 +36,12 @@ function AtLayoutController ($scope, strings) {
AtLayoutController.$inject = ['$scope', 'ComponentsStrings'];
function atLayout (pathService) {
function atLayout () {
return {
restrict: 'E',
replace: true,
transclude: true,
templateUrl: pathService.getPartialPath('components/layout/layout'),
templateUrl,
controller: AtLayoutController,
controllerAs: 'vm',
scope: {
@ -47,6 +49,4 @@ function atLayout (pathService) {
};
}
atLayout.$inject = ['PathService'];
export default atLayout;

View File

@ -1,3 +1,5 @@
const templateUrl = require('@components/layout/side-nav-item.partial.html');
function atSideNavItemLink (scope, element, attrs, ctrl) {
scope.navVm = ctrl[0];
scope.layoutVm = ctrl[1];
@ -29,10 +31,10 @@ function AtSideNavItemController ($state, $scope) {
AtSideNavItemController.$inject = ['$state', '$scope'];
function atSideNavItem (pathService) {
function atSideNavItem () {
return {
restrict: 'E',
templateUrl: pathService.getPartialPath('components/layout/side-nav-item'),
templateUrl,
require: ['^^atSideNav', '^^atLayout'],
controller: AtSideNavItemController,
controllerAs: 'vm',
@ -46,6 +48,4 @@ function atSideNavItem (pathService) {
};
}
atSideNavItem.$inject = ['PathService'];
export default atSideNavItem;

View File

@ -1,3 +1,5 @@
const templateUrl = require('@components/layout/side-nav.partial.html');
function atSideNavLink (scope, element, attrs, ctrl) {
scope.layoutVm = ctrl;
}
@ -12,7 +14,7 @@ function AtSideNavController () {
}
}
function atSideNav (pathService) {
function atSideNav () {
return {
restrict: 'E',
replace: true,
@ -21,12 +23,10 @@ function atSideNav (pathService) {
controllerAs: 'vm',
link: atSideNavLink,
transclude: true,
templateUrl: pathService.getPartialPath('components/layout/side-nav'),
templateUrl,
scope: {
}
};
}
atSideNav.$inject = ['PathService'];
export default atSideNav;

View File

@ -1,3 +1,5 @@
const templateUrl = require('@components/layout/top-nav-item.partial.html');
function atTopNavItemLink (scope, element, attrs, ctrl) {
scope.layoutVm = ctrl;
@ -12,12 +14,12 @@ function atTopNavItemLink (scope, element, attrs, ctrl) {
}
}
function atTopNavItem (pathService) {
function atTopNavItem () {
return {
restrict: 'E',
replace: true,
transclude: true,
templateUrl: pathService.getPartialPath('components/layout/top-nav-item'),
templateUrl,
require: '^^atLayout',
link: atTopNavItemLink,
scope: {
@ -25,6 +27,4 @@ function atTopNavItem (pathService) {
};
}
atTopNavItem.$inject = ['PathService'];
export default atTopNavItem;

View File

@ -1,3 +1,5 @@
const templateUrl = require('@components/modal/modal.partial.html');
const DEFAULT_ANIMATION_DURATION = 150;
function atModalLink (scope, el, attrs, controllers) {
@ -74,13 +76,13 @@ AtModalController.$inject = [
'ComponentsStrings'
]
function atModal (pathService) {
function atModal () {
return {
restrict: 'E',
replace: true,
transclude: true,
require: ['atModal'],
templateUrl: pathService.getPartialPath('components/modal/modal'),
templateUrl,
controller: AtModalController,
controllerAs: 'vm',
link: atModalLink,
@ -88,8 +90,4 @@ function atModal (pathService) {
};
}
atModal.$inject = [
'PathService'
];
export default atModal;

View File

@ -1,15 +1,15 @@
function atPanelBody (pathService) {
const templateUrl = require('@components/panel/body.partial.html');
function atPanelBody () {
return {
restrict: 'E',
replace: true,
transclude: true,
templateUrl: pathService.getPartialPath('components/panel/body'),
templateUrl,
scope: {
state: '='
}
};
}
atPanelBody.$inject = ['PathService'];
export default atPanelBody;

View File

@ -1,18 +1,18 @@
const templateUrl = require('@components/panel/heading.partial.html');
function link (scope, el, attrs, panel) {
panel.use(scope);
}
function atPanelHeading (pathService) {
function atPanelHeading () {
return {
restrict: 'E',
require: '^^atPanel',
replace: true,
transclude: true,
templateUrl: pathService.getPartialPath('components/panel/heading'),
templateUrl,
link
};
}
atPanelHeading.$inject = ['PathService'];
export default atPanelHeading;

View File

@ -1,3 +1,5 @@
const templateUrl = require('@components/panel/panel.partial.html');
function atPanelLink (scope, el, attrs, controllers) {
let panelController = controllers[0];
@ -26,13 +28,13 @@ function AtPanelController ($state) {
AtPanelController.$inject = ['$state'];
function atPanel (pathService, _$animate_) {
function atPanel () {
return {
restrict: 'E',
replace: true,
require: ['atPanel'],
transclude: true,
templateUrl: pathService.getPartialPath('components/panel/panel'),
templateUrl,
controller: AtPanelController,
controllerAs: 'vm',
link: atPanelLink,
@ -43,6 +45,4 @@ function atPanel (pathService, _$animate_) {
};
}
atPanel.$inject = ['PathService'];
export default atPanel;

View File

@ -1,3 +1,5 @@
const templateUrl = require('@components/popover/popover.partial.html');
const DEFAULT_POSITION = 'right';
const DEFAULT_ACTION = 'click';
const DEFAULT_ICON = 'fa fa-question-circle';
@ -201,13 +203,13 @@ function AtPopoverController () {
};
}
function atPopover (pathService) {
function atPopover () {
return {
restrict: 'E',
replace: true,
transclude: true,
require: ['atPopover'],
templateUrl: pathService.getPartialPath('components/popover/popover'),
templateUrl,
controller: AtPopoverController,
controllerAs: 'vm',
link: atPopoverLink,
@ -217,8 +219,4 @@ function atPopover (pathService) {
};
}
atPopover.$inject = [
'PathService'
];
export default atPopover;
export default atPopover;

View File

@ -1,3 +1,5 @@
const templateUrl = require('@components/tabs/group.partial.html');
function atTabGroupLink (scope, el, attrs, controllers) {
let groupController = controllers[0];
@ -26,13 +28,13 @@ function AtTabGroupController ($state) {
AtTabGroupController.$inject = ['$state'];
function atTabGroup (pathService, _$animate_) {
function atTabGroup () {
return {
restrict: 'E',
replace: true,
require: ['atTabGroup'],
transclude: true,
templateUrl: pathService.getPartialPath('components/tabs/group'),
templateUrl,
controller: AtTabGroupController,
controllerAs: 'vm',
link: atTabGroupLink,
@ -42,6 +44,4 @@ function atTabGroup (pathService, _$animate_) {
};
}
atTabGroup.$inject = ['PathService'];
export default atTabGroup;

View File

@ -1,3 +1,5 @@
const templateUrl = require('@components/tabs/tab.partial.html');
function atTabLink (scope, el, attrs, controllers) {
let groupController = controllers[0];
let tabController = controllers[1];
@ -31,13 +33,13 @@ function AtTabController ($state) {
AtTabController.$inject = ['$state'];
function atTab (pathService, _$animate_) {
function atTab () {
return {
restrict: 'E',
replace: true,
transclude: true,
require: ['^^atTabGroup', 'atTab'],
templateUrl: pathService.getPartialPath('components/tabs/tab'),
templateUrl,
controller: AtTabController,
controllerAs: 'vm',
link: atTabLink,
@ -47,6 +49,4 @@ function atTab (pathService, _$animate_) {
};
}
atTab.$inject = ['PathService'];
export default atTab;

View File

@ -1,3 +1,5 @@
const templateUrl = require('@components/truncate/truncate.partial.html');
function atTruncateLink (scope, el, attr, ctrl) {
let truncateController = ctrl;
let string = attr.string;
@ -44,12 +46,12 @@ function AtTruncateController (strings) {
AtTruncateController.$inject = ['ComponentsStrings'];
function atTruncate(pathService) {
function atTruncate() {
return {
restrict: 'E',
replace: true,
transclude: true,
templateUrl: pathService.getPartialPath('components/truncate/truncate'),
templateUrl,
controller: AtTruncateController,
controllerAs: 'vm',
link: atTruncateLink,
@ -61,8 +63,4 @@ function atTruncate(pathService) {
}
}
atTruncate.$inject = [
'PathService'
];
export default atTruncate;

View File

@ -1,12 +1,12 @@
function atPanelBody (pathService) {
const templateUrl = require('@components/utility/divider.partial.html');
function atPanelBody () {
return {
restrict: 'E',
replace: true,
templateUrl: pathService.getPartialPath('components/utility/divider'),
templateUrl,
scope: false
};
}
atPanelBody.$inject = ['PathService'];
export default atPanelBody;

View File

@ -1,9 +1,9 @@
import Base from './Base';
import Config from './Config';
import Credential from './Credential';
import CredentialType from './CredentialType';
import Me from './Me';
import Organization from './Organization';
import Base from '@models/Base';
import Config from '@models/Config';
import Credential from '@models/Credential';
import CredentialType from '@models/CredentialType';
import Me from '@models/Me';
import Organization from '@models/Organization';
angular
.module('at.lib.models', [])

View File

@ -1,8 +1,8 @@
import CacheService from './cache.service';
import EventService from './event.service';
import PathService from './path.service';
import BaseStringService from './base-string.service';
import AppStrings from './app.strings';
import CacheService from '@services/cache.service';
import EventService from '@services/event.service';
import PathService from '@services/path.service';
import BaseStringService from '@services/base-string.service';
import AppStrings from '@services/app.strings';
angular
.module('at.lib.services', [])

View File

@ -18,24 +18,24 @@
* NOTE: Styles below are a mix of 3rd-party dependencies and in-house code. For the 3rd-party
* stuff, we'd be better off managing them via npm where possible.
*/
@import '../../legacy-styles/fonts';
@import '../../legacy-styles/animations';
@import '../../legacy-styles/jquery-ui-overrides';
@import '../../legacy-styles/codemirror';
@import '../../legacy-styles/angular-scheduler';
@import '../../legacy-styles/log-viewer';
@import '../../legacy-styles/event-viewer';
@import '../../legacy-styles/job-details';
@import '../../legacy-styles/jobs';
@import '../../legacy-styles/inventory-edit';
@import '../../legacy-styles/stdout';
@import '../../legacy-styles/lists';
@import '../../legacy-styles/forms';
@import '../../legacy-styles/dashboard';
@import '../../legacy-styles/survey-maker';
@import '../../legacy-styles/text-label';
@import '../../legacy-styles/bootstrap-datepicker';
@import '../../legacy-styles/ansible-ui';
@import '../../legacy/styles/fonts';
@import '../../legacy/styles/animations';
@import '../../legacy/styles/jquery-ui-overrides';
@import '../../legacy/styles/codemirror';
@import '../../legacy/styles/angular-scheduler';
@import '../../legacy/styles/log-viewer';
@import '../../legacy/styles/event-viewer';
@import '../../legacy/styles/job-details';
@import '../../legacy/styles/jobs';
@import '../../legacy/styles/inventory-edit';
@import '../../legacy/styles/stdout';
@import '../../legacy/styles/lists';
@import '../../legacy/styles/forms';
@import '../../legacy/styles/dashboard';
@import '../../legacy/styles/survey-maker';
@import '../../legacy/styles/text-label';
@import '../../legacy/styles/bootstrap-datepicker';
@import '../../legacy/styles/ansible-ui';
// Dependency Style Overrides
@import '../../src/shared/bootstrap-settings';

View File

@ -1,39 +1,17 @@
/*************************************************
* Copyright (c) 2016 Ansible, Inc.
*
* All Rights Reserved
*************************************************/
// Vendor dependencies
import 'jquery';
import 'angular';
import 'angular-gettext';
import 'bootstrap';
import 'jquery-ui';
import 'bootstrap-datepicker';
import 'jquery.resize';
import 'codemirror';
import 'js-yaml';
import 'select2';
import uiRouter from 'angular-ui-router';
// backwards compatibility for $stateChange* events
import 'angular-ui-router/release/stateEvents';
// Configuration dependencies
global.$AnsibleConfig = null;
// Provided via Webpack DefinePlugin in webpack.config.js
global.$ENV = {} ;
// ui-router debugging
if ($ENV['route-debug']){
let trace = require('angular-ui-router').trace;
let trace = angular.module('ui.router').trace;
trace.enable();
}
var urlPrefix;
if ($basePath) {
urlPrefix = $basePath;
urlPrefix = `${$basePath}`;
}
// Modules
@ -73,22 +51,21 @@ import '../lib/models';
import '../lib/services';
import '../features';
var awApp = angular.module('awApp', [
// how to add CommonJS / AMD third-party dependencies:
// 1. npm install --save package-name
// 2. add package name to ./grunt-tasks/webpack.vendorFiles
require('angular-breadcrumb'),
require('angular-codemirror'),
require('angular-drag-and-drop-lists'),
require('angular-sanitize'),
require('angular-scheduler').name,
require('angular-tz-extensions'),
require('angular-md5'),
require('lr-infinite-scroll'),
require('ng-toast'),
'gettext',
angular.module('awApp', [
'I18N',
uiRouter,
'AngularCodeMirrorModule',
'angular-duration-format',
'angularMoment',
'AngularScheduler',
'angular-md5',
'dndLists',
'ncy-angular-breadcrumb',
'ngSanitize',
'ngCookies',
'ngToast',
'gettext',
'Timezones',
'ui.router',
'ui.router.state.events',
'lrInfiniteScroll',
@ -134,7 +111,6 @@ var awApp = angular.module('awApp', [
'at.lib.services',
'at.features',
])
.constant('AngularScheduler.partials', urlPrefix + 'lib/angular-scheduler/lib/')
.constant('AngularScheduler.useTimezone', true)
.constant('AngularScheduler.showUTCField', true)
@ -465,5 +441,3 @@ var awApp = angular.module('awApp', [
LoadConfig();
}
]);
export default awApp;

View File

@ -4,9 +4,6 @@
* Options: static height, custom breakpoint
*/
@import "./client/src/shared/branding/colors.default.less";
.OnePlusOne-container(@height: 100%; @breakpoint: 900px){
height: ~"calc(100vh - 150px)";
display: flex;

View File

@ -6,8 +6,6 @@
* Style conventions
* .ModuleName-component--subComponent
*/
@import "./client/src/shared/branding/colors.default.less";
.OnePlusTwo-container(@height: 100%; @breakpoint: 900px){
height: @height;

View File

@ -34,10 +34,10 @@ import orgAdminLookup from './org-admin-lookup/main';
import limitPanels from './limit-panels/main';
import multiSelectPreview from './multi-select-preview/main';
import credentialTypesLookup from './credentialTypesLookup.factory';
import 'angular-duration-format';
export default
angular.module('shared', [listGenerator.name,
angular.module('shared', [
listGenerator.name,
formGenerator.name,
lookupModal.name,
smartSearch.name,
@ -64,7 +64,7 @@ angular.module('shared', [listGenerator.name,
orgAdminLookup.name,
limitPanels.name,
multiSelectPreview.name,
require('angular-cookies'),
'ngCookies',
'angular-duration-format'
])
.factory('stateDefinitions', stateDefinitions)

View File

@ -1,7 +1,7 @@
import newMoment from './moment';
export default
angular.module('moment', [require('angular-moment').name])
angular.module('moment', ['angularMoment'])
.config(function() {
// Remove the global variable for moment
delete window.moment;

View File

@ -1,5 +1,3 @@
@import "./client/src/shared/branding/colors.default.less";
.position-center {
left: 0;
right: 0;
@ -255,4 +253,4 @@
max-width: ~"calc(100vw - 50px)";
}
}
}
}

View File

@ -0,0 +1,39 @@
require('@assets/custom-theme/jquery-ui-1.10.3.custom.min.css');
require('@assets/ansible-bootstrap.min.css');
require('@assets/fontcustom/fontcustom.css');
require('@modules/components-font-awesome/css/font-awesome.min.css');
require('@modules/select2/dist/css/select2.css');
require('@modules/codemirror/lib/codemirror.css');
require('@modules/codemirror/theme/elegant.css');
require('@modules/codemirror/addon/lint/lint.css');
require('@modules/nvd3/build/nv.d3.css');
require('@modules/ng-toast/dist/ngToast.min.css');
require('jquery');
require('jquery-resize');
require('jquery-ui');
require('bootstrap');
require('bootstrap-datepicker');
require('moment');
require('select2');
require('sprintf-js');
require('reconnectingwebsocket');
require('d3');
require('nvd3');
require('angular');
require('angular-cookies');
require('angular-sanitize');
require('angular-breadcrumb');
require('angular-codemirror');
require('angular-drag-and-drop-lists');
require('angular-duration-format');
require('angular-gettext');
require('angular-md5');
require('angular-moment');
require('angular-scheduler');
require('angular-tz-extensions');
require('angular-ui-router');
require('angular-ui-router-state-events');
require('ng-toast-provider');
require('ng-toast-directives');
require('ng-toast');
require('lr-infinite-scroll');

View File

@ -1,30 +0,0 @@
var django_port = process.env.npm_package_config_django_port,
django_host = process.env.npm_package_config_django_host;
module.exports = {
http: {
bsFiles: {
src: [
'static/**/*',
'!static/tower.vendor.js',
'!static/tower.vendor.map.js',
'!static/tower.js.map'
]
},
options: {
proxy: {
target: `https://${django_host}:${django_port}`,
ws: true
},
keepalive: false,
watchTask: true,
reloadDebounce: 1000,
// The browser-sync-client lib will write your current scroll position to window.name
// https://github.com/BrowserSync/browser-sync-client/blob/a2718faa91e11553feca7a3962313bf1ec6ba3e5/dist/index.js#L500
// This strategy is enabled in the core browser-sync lib, and not externally documented as an option. Yay!
// https://github.com/BrowserSync/browser-sync/blob/a522aaf12b6167d5591ed285eb3086f43a4d9ac2/lib/default-config.js#L312
scrollRestoreTechnique: null,
injectChanges: true
}
}
};

View File

@ -1,7 +0,0 @@
module.exports = {
options: { force: true },
static: 'static/*',
coverage: 'coverage/*',
tmp: '../../tmp',
jshint: 'coverage/jshint.xml'
};

View File

@ -1,17 +0,0 @@
module.exports = {
css: {
src: [
'static/assets/custom-theme/jquery-ui-1.10.3.custom.min.css',
'static/assets/ansible-bootstrap.min.css',
'static/assets/fontcustom/fontcustom.css',
'static/lib/components-font-awesome/css/font-awesome.min.css',
'static/lib/select2/dist/css/select2.css',
'static/lib/codemirror/lib/codemirror.css',
'static/lib/codemirror/theme/elegant.css',
'static/lib/codemirror/addon/lint/lint.css',
'static/lib/nvd3/build/nv.d3.css',
'static/lib/ng-toast/dist/ngToast.min.css'
],
dest: 'static/css/app.vendor.css'
}
};

View File

@ -1,61 +0,0 @@
module.exports = {
dev: {
tasks: [
'copy:vendor',
'copy:assets',
'copy:icons',
'copy:fonts',
'copy:images',
'copy:partials',
'copy:views',
'copy:languages',
'copy:config',
'less:dev'
]
},
// This concurrent target is intended for development ui builds that do not require raising browser-sync or filesystem polling
devNoSync: {
tasks: [
'copy:vendor',
'copy:assets',
'copy:icons',
'copy:fonts',
'copy:images',
'copy:partials',
'copy:views',
'copy:languages',
'copy:config',
'less:dev',
'webpack:dev'
]
},
prod: {
tasks: [
'newer:copy:vendor',
'newer:copy:assets',
'newer:copy:icons',
'newer:copy:fonts',
'newer:copy:images',
'newer:copy:partials',
'newer:copy:views',
'newer:copy:languages',
'newer:copy:config',
'newer:less:prod'
]
},
watch: {
tasks: [
'watch:css',
'watch:partials',
'watch:views',
'watch:assets',
[
'watch:config'
]
],
options: {
logConcurrentOutput: true
}
}
};

View File

@ -1,100 +0,0 @@
var staticFiles = ['angular-tz-extensions/tz/data/*',
'angular-scheduler/lib/angular-scheduler-detail.html',
'angular-scheduler/lib/angular-scheduler.html',
'nvd3/build/nv.d3.css',
'ng-toast/dist/ngToast.min.css',
'codemirror/addon/lint/lint.css',
'codemirror/theme/elegant.css',
'codemirror/lib/codemirror.css',
'select2/dist/css/select2.css',
'components-font-awesome/css/font-awesome.min.css',
'components-font-awesome/fonts/fontawesome-webfont.ttf',
'components-font-awesome/fonts/fontawesome-webfont.woff',
'components-font-awesome/fonts/fontawesome-webfont.woff2'
];
module.exports = {
fonts: {
files: [{
cwd: 'client/',
expand: true,
flatten: true,
filter: 'isFile',
src: 'assets/fontcustom/**/*',
dest: 'static/fonts/'
}]
},
icons: {
files: [{
cwd: 'node_modules/',
expand: true,
flatten: true,
filter: 'isFile',
src: 'components-font-awesome/fonts/*',
dest: 'static/fonts/'
}]
},
images: {
files: [{
cwd: 'client/',
expand: true,
flatten: true,
filter: 'isFile',
src: 'assets/custom-theme/images.new/*',
dest: 'static/images/'
}]
},
assets: {
files: [{
cwd: 'client/',
expand: true,
src: 'assets/**/*',
dest: 'static/'
}]
},
vendor: {
files: [{
expand: true,
cwd: 'node_modules/',
src: staticFiles,
dest: 'static/lib/'
}]
},
views: {
files: [{
cwd: 'client/features',
expand: true,
src: ['**/*.view.html'],
dest: 'static/views/'
}]
},
partials: {
files: [{
cwd: 'client/src',
expand: true,
src: ['**/*.partial.html'],
dest: 'static/partials'
}, {
cwd: 'client/src/partials',
expand: true,
src: ['*.html'],
dest: 'static/partials/'
}, {
cwd: 'client/lib/components',
expand: true,
src: ['**/*.partial.html'],
dest: 'static/partials/components/'
}]
},
languages: {
files: [{
cwd: 'client/',
expand: true,
src: 'languages/*.json',
dest: 'static/'
}]
},
config: {
files: { 'static/config.js': ['client/src/config.js'] }
}
};

View File

@ -1,22 +0,0 @@
module.exports = {
vendor: {
files: [
{
expand: true,
src: 'static/css/app.vendor.css',
dest: '.',
ext: '.vendor.css'
}
]
},
source: {
files: [
{
expand: true,
src: 'static/css/app.css',
dest: '.',
ext: '.css'
}
]
}
};

View File

@ -1,27 +0,0 @@
var AutoPrefixer = require('less-plugin-autoprefix');
var autoPrefixer = new AutoPrefixer({
browsers: [ 'last 2 versions' ]
});
module.exports = {
dev: {
files: {
'static/css/app.css': 'client/lib/theme/index.less'
},
options: {
sourceMap: true,
plugins: [ autoPrefixer ]
}
},
prod: {
files: {
'static/css/app.css': 'client/lib/theme/index.less'
},
options: {
compress: true,
sourceMap: false,
plugins: [ autoPrefixer ]
}
}
};

View File

@ -3,13 +3,14 @@ module.exports = {
options: {
format: 'json'
},
files: [ {
files: [{
expand: true,
dot: true,
dest: 'client/languages',
cwd: 'po',
ext: '.json',
src: ['*.po']
} ]
dot: true,
dest: 'client/languages',
cwd: 'po',
ext: '.json',
src: ['*.po']
}]
}
};

View File

@ -1,26 +0,0 @@
module.exports = {
css: {
files: 'client/**/*.less',
tasks: ['less:dev']
},
partials: {
files: [
'client/lib/components/**/*.partial.html',
'client/src/**/*.partial.html',
'client/src/partials/*.html'
],
tasks: ['newer:copy:partials']
},
views: {
files: 'client/features/**/*.view.html',
tasks: ['newer:copy:views']
},
assets: {
files: 'client/assets',
tasks: ['newer:copy:assets']
},
config: {
files: 'client/src/config.js',
tasks: ['newer:copy:config']
}
};

View File

@ -1,5 +0,0 @@
var config = require('../webpack.config.js');
module.exports = {
dev: config.dev,
prod: config.release
};

View File

@ -1,5 +1,4 @@
var path = require('path'),
webpack = require('webpack');
const webpackTestConfig = require('./build/webpack.test.js');
module.exports = function(config) {
config.set({
@ -16,80 +15,20 @@ module.exports = function(config) {
'jasmine',
],
reporters: ['progress', 'coverage', 'junit'],
files: [
files:[
'./client/src/vendor.js',
'./client/src/app.js',
'./node_modules/angular-mocks/angular-mocks.js',
{ pattern: './tests/**/*-test.js' },
'client/src/**/*.html'
],
preprocessors: {
'./client/src/vendor.js': ['webpack', 'sourcemap'],
'./client/src/app.js': ['webpack', 'sourcemap'],
'./tests/**/*-test.js': ['webpack', 'sourcemap'],
'client/src/**/*.html': ['html2js']
},
webpack: {
plugins: [
// Django-provided definitions
new webpack.DefinePlugin({
$basePath: '/static/'
}),
// vendor shims:
// [{expected_local_var : dependency}, ...]
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery',
_: 'lodash',
'CodeMirror': 'codemirror',
'$.fn.datepicker': 'bootstrap-datepicker'
})
],
module: {
loaders: [{
test: /\.angular.js$/,
loader: 'expose?angular'
},
{
test: /\.json$/,
loader: 'json-loader',
exclude: '/(node_modules)/'
},
{
test: /\.js$/,
loader: 'babel-loader',
include: [path.resolve() + '/tests/'],
exclude: '/(node_modules)/',
query: {
presets: ['es2015']
}
}, {
test: /\.js$/,
loader: 'babel-loader',
include: [
path.resolve() + '/client/src/',
path.resolve() + '/client/lib/',
path.resolve() + '/client/features/'
],
exclude: '/(node_modules)/',
query: {
presets: ['es2015'],
plugins: ['istanbul']
}
}
]
},
resolve: {
root: [],
modulesDirectory: ['node_modules'],
alias: {
'jquery.resize': path.resolve() + '/node_modules/javascript-detect-element-resize/jquery.resize.js',
'select2': path.resolve() + '/node_modules/select2/dist/js/select2.full.js'
}
},
devtool: 'inline-source-map',
debug: true,
cache: true
},
webpack: webpackTestConfig,
webpackMiddleware: {
stats: {
colors: true

File diff suppressed because it is too large Load Diff

View File

@ -1,65 +1,61 @@
{
"name": "ansible-tower",
"version": "3.1.0",
"name": "awx",
"version": "1.0.0",
"repository": {
"type": "git",
"url": ""
"url": "https://github.com/ansible/awx"
},
"config": {
"django_port": "8043",
"django_host": "localhost"
},
"engines": {
"node": "^6.3.1",
"node": "^6.11.3",
"npm": "^3.10.3"
},
"scripts": {
"ui-docker-machine": "ip=$(docker-machine ip $DOCKER_MACHINE_NAME); npm set ansible-tower:django_host ${ip}; grunt dev;",
"ui-docker": "grunt dev;",
"build-devel": "grunt devNoSync",
"ui-docker": "npm run watch;",
"build-devel": "npm run dev",
"pot": "grunt nggettext_extract",
"languages": "grunt nggettext_compile",
"build-release": "grunt release",
"pretest": "grunt clean:coverage",
"build-release": "npm run production",
"pretest": "",
"test": "karma start karma.conf.js",
"jshint": "grunt clean:jshint jshint:source --no-color",
"jshint": "grunt jshint:source --no-color",
"test:ci": "npm run test -- --single-run --reporter junit,dots --browsers=PhantomJS",
"lint": "./node_modules/.bin/eslint -c .eslintrc.js .",
"component-test": "./node_modules/.bin/karma start client/test/karma.conf.js",
"lint-dev": "./node_modules/.bin/nodemon --exec \"./node_modules/.bin/eslint -c .eslintrc.js .\" --watch \"client/components/**/*.js\"",
"component-dev": "./node_modules/.bin/karma start client/test/karma.conf.js --auto-watch --no-single-run"
},
"optionalDependencies": {
"browser-sync": "^2.14.0",
"grunt-browser-sync": "^2.2.0",
"grunt-contrib-watch": "^1.0.0",
"webpack-dev-server": "^1.14.1"
"dev": "./node_modules/.bin/webpack --config build/webpack.development.js --progress",
"watch": "./node_modules/.bin/webpack-dev-server --config build/webpack.watch.js --progress",
"production": "./node_modules/.bin/webpack --config build/webpack.production.js"
},
"devDependencies": {
"angular-mocks": "~1.4.14",
"babel-core": "^6.11.4",
"babel-core": "^6.26.0",
"babel-istanbul": "^0.11.0",
"babel-loader": "^6.2.4",
"babel-loader": "^7.1.2",
"babel-plugin-istanbul": "^2.0.0",
"babel-preset-es2015": "^6.9.0",
"babel-preset-es2015": "^6.24.1",
"clean-webpack-plugin": "^0.1.16",
"copy-webpack-plugin": "^4.0.1",
"css-loader": "^0.28.5",
"eslint": "^3.18.0",
"eslint-config-airbnb-base": "^11.1.1",
"eslint-plugin-import": "^2.2.0",
"expose-loader": "^0.7.1",
"expose-loader": "^0.7.3",
"extract-text-webpack-plugin": "^3.0.0",
"grunt": "^1.0.1",
"grunt-angular-gettext": "^2.2.3",
"grunt-cli": "^1.2.0",
"grunt-concurrent": "^2.3.0",
"grunt-contrib-clean": "^1.0.0",
"grunt-contrib-concat": "^1.0.1",
"grunt-contrib-copy": "^1.0.0",
"grunt-contrib-cssmin": "^2.2.0",
"grunt-contrib-jshint": "^1.0.0",
"grunt-contrib-less": "^1.3.0",
"grunt-extract-sourcemap": "^0.1.18",
"grunt-newer": "^1.2.0",
"grunt-webpack": "^1.0.11",
"imports-loader": "^0.6.5",
"html-loader": "^0.5.1",
"html-webpack-harddisk-plugin": "^0.1.0",
"html-webpack-plugin": "^2.30.1",
"imports-loader": "^0.7.1",
"jasmine-core": "^2.5.2",
"jshint": "^2.9.4",
"jshint-loader": "^0.8.3",
@ -77,13 +73,20 @@
"karma-sauce-launcher": "^1.0.0",
"karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "^1.8.0",
"less": "^2.7.2",
"less-loader": "^4.0.5",
"less-plugin-autoprefix": "^1.4.2",
"load-grunt-configs": "^1.0.0",
"load-grunt-tasks": "^3.5.0",
"minimist": "^1.2.0",
"ngtemplate-loader": "^2.0.1",
"phantomjs-prebuilt": "^2.1.12",
"script-loader": "^0.7.0",
"style-loader": "^0.18.2",
"time-grunt": "^1.4.0",
"webpack": "^1.13.1"
"uglifyjs-webpack-plugin": "^0.4.6",
"webpack": "^3.0.0",
"webpack-dev-server": "^2.7.1"
},
"dependencies": {
"angular": "~1.4.14",
@ -100,8 +103,8 @@
"angular-scheduler": "github:ansible/angular-scheduler#0.1.1",
"angular-tz-extensions": "github:ansible/angular-tz-extensions#0.3.13",
"angular-ui-router": "1.0.0-beta.3",
"bootstrap": "^3.1.1",
"bootstrap-datepicker": "^1.4.0",
"bootstrap": "^3.3.7",
"bootstrap-datepicker": "^1.7.1",
"codemirror": "^5.17.0",
"components-font-awesome": "^4.6.1",
"d3": "~3.3.13",

File diff suppressed because it is too large Load Diff

View File

@ -1,21 +1,14 @@
<!DOCTYPE html>
{% load i18n %}
<html lang="en" ng-app="awApp">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title ng-bind="tabTitle"></title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="{{ STATIC_URL }}css/app.vendor.css?v={{version}}" type="text/css">
<link rel="stylesheet" href="{{ STATIC_URL }}css/app.css?v={{version}}" type="text/css">
<link rel="shortcut icon" href="{{ STATIC_URL }}assets/favicon.ico?v={{version}}" />
<script>
var $basePath = "{{ STATIC_URL }}";
</script>
<script src="{{ STATIC_URL }}app.vendor.js?v={{version}}"></script>
<script src="{{ STATIC_URL }}app.js?v={{version}}"></script>
</head>
<title ng-bind="tabTitle"></title>
<script>var $basePath = '{{ STATIC_URL }}'</script>
<link href="css/vendor.ef74d311a51ca363f1e2.css" rel="stylesheet"><link href="css/app.ef74d311a51ca363f1e2.css" rel="stylesheet"><script type="text/javascript" src="js/vendor.ef74d311a51ca363f1e2.js"></script><script type="text/javascript" src="js/app.ef74d311a51ca363f1e2.js"></script></head>
<body data-user-agent="{{userAgent}}">
<at-layout>
@ -28,7 +21,7 @@
</div>
<!-- Password Dialog -->
<div id="password-modal" style="display: none;"></div>
<div id="idle-modal" style="display:none">{% blocktrans %}Your session will expire in <span id="remaining_seconds" class="IdleModal-remainingSeconds">60</span> seconds, would you like to continue?{% endblocktrans %}</div>
<div id="idle-modal" style="display:none" translate>Your session will expire in <span id="remaining_seconds" class="IdleModal-remainingSeconds">60</span> seconds, would you like to continue?</div>
<stream-detail-modal></stream-detail-modal>
<!-- Confirmation Dialog -->
<div id="prompt-modal" class="modal fade">
@ -43,7 +36,7 @@
<div class="Modal-body" ng-bind-html="promptBody" id="prompt-body">
</div>
<div class="Modal-footer">
<a href="#" data-target="#prompt-modal" data-dismiss="modal" id="prompt_cancel_btn" class="btn Modal-defaultButton Modal-footerButton">{% trans 'CANCEL' %}</a>
<a href="#" data-target="#prompt-modal" data-dismiss="modal" id="prompt_cancel_btn" class="btn Modal-defaultButton Modal-footerButton" translate>CANCEL</a>
<a href="" ng-class="promptActionBtnClass" ng-click="promptAction()" id="prompt_action_btn" class="btn Modal-footerButton" ng-bind="promptActionText"></a>
</div>
</div>
@ -64,7 +57,7 @@
<div id="alert-modal-msg" class="alert" ng-bind-html="alertBody"></div>
</div>
<div class="modal-footer">
<a href="#" ng-hide="disableButtons" data-target="#form-modal" data-dismiss="modal" id="alert_ok_btn" class="btn btn-default">{% trans 'OK' %}</a>
<a href="#" ng-hide="disableButtons" data-target="#form-modal" data-dismiss="modal" id="alert_ok_btn" class="btn btn-default" translate>OK</a>
</div>
</div>
<!-- modal-content -->
@ -83,7 +76,7 @@
<div id="alert2-modal-msg" class="alert" ng-bind-html="alertBody2"></div>
</div>
<div class="modal-footer">
<a href="#" ng-hide="disableButtons2" data-target="#form-modal2" data-dismiss="modal" id="alert2_ok_btn" class="btn btn-primary">{% trans 'OK' %}</a>
<a href="#" ng-hide="disableButtons2" data-target="#form-modal2" data-dismiss="modal" id="alert2_ok_btn" class="btn btn-primary">OK</a>
</div>
</div>
<!-- modal-content -->
@ -95,28 +88,27 @@
<div id="help-modal-dialog" style="display: none;"></div>
<div id="prompt-for-days" style="display:none">
<form name="prompt_for_days_form" id="prompt_for_days_form" class="MgmtCards-promptText">
{% trans 'Set how many days of data should be retained.' %}
<span translate>Set how many days of data should be retained.</span>
<br>
<input type="integer" id="days_to_keep" name="days_to_keep" ng-model="days_to_keep" ng-required="true" class="form-control Form-textInput" min=0 max=9999 style="margin-top:10px;" integer>
<div class="error" ng-show="prompt_for_days_form.days_to_keep.$dirty && (prompt_for_days_form.days_to_keep.$error.number || prompt_for_days_form.days_to_keep.$error.integer ||
prompt_for_days_form.days_to_keep.$error.required ||
prompt_for_days_form.days_to_keep.$error.min ||
prompt_for_days_form.days_to_keep.$error.max)">{% blocktrans %}Please enter an integer<span ng-show="prompt_for_days_form.days_to_keep.$dirty && prompt_for_days_form.days_to_keep.$error.min"> that is not negative</span><span ng-show="prompt_for_days_form.days_to_keep.$dirty && prompt_for_days_form.days_to_keep.$error.max"> that is lower than 9999</span>.{% endblocktrans %}</div>
prompt_for_days_form.days_to_keep.$error.max)" translate>Please enter an integer<span ng-show="prompt_for_days_form.days_to_keep.$dirty && prompt_for_days_form.days_to_keep.$error.min"> that is not negative</span><span ng-show="prompt_for_days_form.days_to_keep.$dirty && prompt_for_days_form.days_to_keep.$error.max"> that is lower than 9999</span>.</div>
</form>
</div>
<div id="prompt-for-days-facts" style="display:none">
<form name="prompt_for_days_facts_form" id="prompt_for_days_facts_form" class="MgmtCards-promptText">
<div style="padding-bottom:15px;">{% blocktrans %}For facts collected older than the time period specified, save one fact scan (snapshot) per time window (frequency). For example, facts older than 30 days are purged, while one weekly fact scan is kept.
<div style="padding-bottom:15px;"><span translate>For facts collected older than the time period specified, save one fact scan (snapshot) per time window (frequency). For example, facts older than 30 days are purged, while one weekly fact scan is kept.</span>
<br>
<br>
<span translate>CAUTION: Setting both numerical variables to "0" will delete all facts.</span>
<br>
<br> CAUTION: Setting both numerical variables to "0" will delete all facts.
<br>
<br>{% endblocktrans %}
</div>
<div class="form-group">
<label for="description">
<span class="label-text">
{% trans 'Select a time period after which to remove old facts' %}
</span>
<span class="label-text" translate>Select a time period after which to remove old facts</span>
</label>
<div class="row">
<div class="col-xs-6">
@ -129,13 +121,11 @@
<div class="error" ng-show="prompt_for_days_facts_form.keep_amount.$dirty && (prompt_for_days_facts_form.keep_amount.$error.number || prompt_for_days_facts_form.keep_amount.$error.integer ||
prompt_for_days_facts_form.keep_amount.$error.required ||
prompt_for_days_facts_form.keep_amount.$error.min ||
prompt_for_days_facts_form.keep_amount.$error.max)">{% blocktrans %}Please enter an integer<span ng-show="prompt_for_days_facts_form.keep_amount.$dirty && prompt_for_days_facts_form.keep_amount.$error.min"> that is not negative</span><span ng-show="prompt_for_days_facts_form.keep_amount.$dirty && prompt_for_days_facts_form.keep_amount.$error.max"> that is lower than 9999</span>.{% endblocktrans %}</div>
prompt_for_days_facts_form.keep_amount.$error.max)" translate>Please enter an integer<span ng-show="prompt_for_days_facts_form.keep_amount.$dirty && prompt_for_days_facts_form.keep_amount.$error.min"> that is not negative</span><span ng-show="prompt_for_days_facts_form.keep_amount.$dirty && prompt_for_days_facts_form.keep_amount.$error.max"> that is lower than 9999</span>.</div>
</div>
<div class="form-group ">
<label for="description">
<span class="label-text">
{% trans 'Select a frequency for snapshot retention' %}
</span>
<span class="label-text" translate>Select a frequency for snapshot retention</span>
</label>
<div class="row">
<div class="col-xs-6">
@ -148,13 +138,13 @@
<div class="error" ng-show="prompt_for_days_facts_form.granularity_keep_amount.$dirty && (prompt_for_days_facts_form.granularity_keep_amount.$error.number || prompt_for_days_facts_form.granularity_keep_amount.$error.integer ||
prompt_for_days_facts_form.granularity_keep_amount.$error.required ||
prompt_for_days_facts_form.granularity_keep_amount.$error.min ||
prompt_for_days_facts_form.granularity_keep_amount.$error.max)">{% blocktrans %}Please enter an integer<span ng-show="prompt_for_days_facts_form.granularity_keep_amount.$dirty && prompt_for_days_facts_form.granularity_keep_amount.$error.min"> that is not negative</span><span ng-show="prompt_for_days_facts_form.granularity_keep_amount.$dirty && prompt_for_days_facts_form.granularity_keep_amount.$error.max"> that is lower than 9999</span>.{% endblocktrans %}</div>
prompt_for_days_facts_form.granularity_keep_amount.$error.max)" translate>Please enter an integer<span ng-show="prompt_for_days_facts_form.granularity_keep_amount.$dirty && prompt_for_days_facts_form.granularity_keep_amount.$error.min"> that is not negative</span><span ng-show="prompt_for_days_facts_form.granularity_keep_amount.$dirty && prompt_for_days_facts_form.granularity_keep_amount.$error.max"> that is lower than 9999</span>.</div>
</div>
</form>
</div>
<div class="overlay"></div>
<div class="spinny"><i class="fa fa-cog fa-spin fa-2x"></i>
<p>{% trans 'working...' %}</p>
<p translate>working...</p>
</div>
</div>
</at-layout>

View File

@ -1,126 +0,0 @@
var awx_env,
path = require('path'),
webpack = require('webpack'),
options = require('minimist')(JSON.parse(process.env.npm_config_argv).remain),
merge = require('lodash').merge;
awx_env = {
'proxy': {
'django_host': process.env.npm_package_config_django_host,
'django_port': process.env.npm_package_config_django_port
}
};
merge(awx_env, options);
var vendorPkgs = [
'angular',
'angular-breadcrumb',
'angular-codemirror',
'angular-cookies',
'angular-drag-and-drop-lists',
'angular-duration-format',
'angular-gettext',
'angular-md5',
'angular-moment',
'angular-sanitize',
'angular-scheduler',
'angular-tz-extensions',
'angular-ui-router',
'bootstrap',
'bootstrap-datepicker',
'codemirror',
'd3',
//'javascript-detect-element-resize', // jquery-flavored dist is alias'd below
'jquery',
'jquery-ui',
'js-yaml',
'lodash',
'lr-infinite-scroll',
'moment',
'ng-toast',
'nvd3',
'select2',
'sprintf-js',
'reconnectingwebsocket'
];
var baseConfig = function() {
return {
entry: {
app: './client/src/app.js',
vendor: vendorPkgs
},
output: {
path: './static/',
filename: 'app.js'
},
plugins: [
// vendor shims:
// [{expected_local_var : dependency}, ...]
new webpack.ProvidePlugin({
'$': 'jquery',
'jQuery': 'jquery',
'window.jQuery': 'jquery',
'_': 'lodash',
'CodeMirror': 'codemirror',
'jsyaml': 'js-yaml',
'jsonlint': 'codemirror.jsonlint'
}),
new webpack.optimize.CommonsChunkPlugin('vendor', 'app.vendor.js')
],
module: {
loaders: [
{
// disable AMD loading (broken in this lib) and default to CommonJS (not broken)
test: /\.angular-tz-extensions.js$/,
loader: 'imports?define=>false'
},
{
// es6 -> es5
test: /\.js$/,
loader: 'babel-loader',
exclude: /(node_modules)/,
query: {
presets: ['es2015']
}
},
{
test: /\.json$/,
loader: 'json-loader',
exclude: /(node_modules)/
}
]
},
resolve: {
alias: {
'codemirror.jsonlint': path.resolve() + '/node_modules/codemirror/addon/lint/json-lint.js',
'jquery.resize': path.resolve() + '/node_modules/javascript-detect-element-resize/jquery.resize.js',
'select2': path.resolve() + '/node_modules/select2/dist/js/select2.full.js'
}
}
};
};
var dev = baseConfig();
dev.devtool = 'inline-source-map';
dev.watch = true;
dev.plugins.push(new webpack.DefinePlugin({ $ENV: JSON.stringify(awx_env) }));
dev.module.preLoaders = [
{
test: /\.js?$/,
loader: 'jshint-loader',
exclude: ['/(node_modules)/'],
include: [path.resolve() + '/client/src/'],
jshint: {
emitErrors: true
}
}
];
var release = baseConfig();
release.plugins.push(new webpack.DefinePlugin({ $ENV: {} }));
release.plugins.push(new webpack.optimize.UglifyJsPlugin({ mangle: false }));
module.exports = { dev: dev, release: release };