diff --git a/awx/ui/client/components/_index.less b/awx/ui/client/components/_index.less
index 068cb5f609..5bd6f2be23 100644
--- a/awx/ui/client/components/_index.less
+++ b/awx/ui/client/components/_index.less
@@ -1,4 +1,5 @@
@import 'badge/_index';
+@import 'form/_index';
@import 'input/_index';
@import 'panel/_index';
@import 'popover/_index';
diff --git a/awx/ui/client/components/badge/_index.less b/awx/ui/client/components/badge/_index.less
index c3d69b7ef4..a3f3927a81 100644
--- a/awx/ui/client/components/badge/_index.less
+++ b/awx/ui/client/components/badge/_index.less
@@ -1,8 +1,8 @@
.at-Badge {
- font-size: @at-font-sm;
- padding: 0 @at-padding-sm;
+ font-size: @at-font-size;
+ padding: 0 @at-space-2x;
margin: 0;
background-color: @at-gray;
color: @at-white;
- border-radius: @at-border-radius-md;
+ border-radius: @at-border-radius;
}
diff --git a/awx/ui/client/components/form/_index.less b/awx/ui/client/components/form/_index.less
new file mode 100644
index 0000000000..593626f5ca
--- /dev/null
+++ b/awx/ui/client/components/form/_index.less
@@ -0,0 +1,7 @@
+.at-FormActionGroup {
+ margin-top: @at-space-6x;
+
+ button:last-child {
+ margin-left: @at-space-5x;
+ }
+}
diff --git a/awx/ui/client/components/form/form-action-group.directive.js b/awx/ui/client/components/form/form-action-group.directive.js
new file mode 100644
index 0000000000..f13fcf7250
--- /dev/null
+++ b/awx/ui/client/components/form/form-action-group.directive.js
@@ -0,0 +1,16 @@
+function atFormActionGroup (pathService) {
+ return {
+ restrict: 'E',
+ transclude: true,
+ replace: true,
+ require: '^^at-form',
+ templateUrl: pathService.getPartialPath('components/form/form-action-group'),
+ scope: {
+ config: '='
+ }
+ };
+}
+
+atFormActionGroup.$inject = ['PathService'];
+
+export default atFormActionGroup;
diff --git a/awx/ui/client/components/form/form-action-group.partial.html b/awx/ui/client/components/form/form-action-group.partial.html
new file mode 100644
index 0000000000..4c7d3d00c3
--- /dev/null
+++ b/awx/ui/client/components/form/form-action-group.partial.html
@@ -0,0 +1,5 @@
+
diff --git a/awx/ui/client/components/form/form-action.directive.js b/awx/ui/client/components/form/form-action.directive.js
new file mode 100644
index 0000000000..0f99d2d332
--- /dev/null
+++ b/awx/ui/client/components/form/form-action.directive.js
@@ -0,0 +1,44 @@
+function link (scope, el, attrs, form) {
+ form.use('action', scope, el);
+
+ switch(scope.config.type) {
+ case 'cancel':
+ applyCancelProperties(scope);
+ break;
+ case 'save':
+ applySaveProperties(scope);
+ break;
+ }
+}
+
+function applyCancelProperties (scope) {
+ scope.text = 'CANCEL';
+ scope.fill = 'Hollow';
+ scope.color = 'white';
+ scope.disabled = false;
+}
+
+function applySaveProperties (scope) {
+ scope.text = 'SAVE';
+ scope.fill = '';
+ scope.color = 'green';
+ scope.disabled = true;
+}
+
+function atFormAction (pathService) {
+ return {
+ restrict: 'E',
+ transclude: true,
+ replace: true,
+ require: '^^at-form',
+ templateUrl: pathService.getPartialPath('components/form/form-action'),
+ link,
+ scope: {
+ config: '='
+ }
+ };
+}
+
+atFormAction.$inject = ['PathService'];
+
+export default atFormAction;
diff --git a/awx/ui/client/components/form/form-action.partial.html b/awx/ui/client/components/form/form-action.partial.html
new file mode 100644
index 0000000000..bb85f7ed1e
--- /dev/null
+++ b/awx/ui/client/components/form/form-action.partial.html
@@ -0,0 +1,4 @@
+
diff --git a/awx/ui/client/components/form/form.directive.js b/awx/ui/client/components/form/form.directive.js
index 5922a08b20..38f0924471 100644
--- a/awx/ui/client/components/form/form.directive.js
+++ b/awx/ui/client/components/form/form.directive.js
@@ -1,12 +1,23 @@
-function use (componentScope, componentElement) {
+function use (type, componentScope, componentElement) {
let vm = this;
- let input = vm.track(componentElement);
+ let component;
- componentScope.meta = input;
+ switch (type) {
+ case 'input':
+ component = vm.trackInput(componentElement);
+ break;
+ case 'action':
+ component = vm.trackAction(componentElement);
+ break;
+ default:
+ throw new Error('An at-form cannot use component type:', type);
+ }
+
+ componentScope.meta = component;
}
-function track (componentElement) {
+function trackInput (componentElement) {
let vm = this;
let input = {
@@ -24,12 +35,27 @@ function track (componentElement) {
return input;
}
-function controller () {
+function trackAction (componentElement) {
+ let vm = this;
+
+ let action = {
+ el: componentElement
+ };
+
+ vm.actions.push(action);
+
+ return action;
+}
+
+function AtFormController () {
let vm = this;
vm.inputs = [];
+ vm.actions = [];
+
vm.use = use;
- vm.track = track;
+ vm.trackInput = trackInput;
+ vm.trackAction = trackAction;
}
function atForm (pathService) {
@@ -37,7 +63,7 @@ function atForm (pathService) {
restrict: 'E',
transclude: true,
templateUrl: pathService.getPartialPath('components/form/form'),
- controller,
+ controller: AtFormController,
controllerAs: 'vm',
scope: {
config: '='
diff --git a/awx/ui/client/components/index.js b/awx/ui/client/components/index.js
index 6877297d62..c71407dbe3 100644
--- a/awx/ui/client/components/index.js
+++ b/awx/ui/client/components/index.js
@@ -1,5 +1,7 @@
import badge from './badge/badge.directive';
import form from './form/form.directive';
+import formAction from './form/form-action.directive';
+import formActionGroup from './form/form-action-group.directive';
import inputLabel from './input/label.directive';
import inputSearch from './input/search.directive';
import inputSelect from './input/select.directive';
@@ -15,6 +17,8 @@ angular
.module('at.components', [])
.directive('atBadge', badge)
.directive('atForm', form)
+ .directive('atFormAction', formAction)
+ .directive('atFormActionGroup', formActionGroup)
.directive('atInputLabel', inputLabel)
.directive('atInputSearch', inputSearch)
.directive('atInputSelect', inputSelect)
diff --git a/awx/ui/client/components/input/_index.less b/awx/ui/client/components/input/_index.less
index 1c15dca610..129c386dfe 100644
--- a/awx/ui/client/components/input/_index.less
+++ b/awx/ui/client/components/input/_index.less
@@ -1,40 +1,36 @@
.at-Input {
- .at-Placeholder(@at-gray-dark);
+ .at-mixin-Placeholder(@at-gray-dark-3x);
background: @at-white;
- border-radius: @at-border-radius-md;
- color: @at-gray-darkest;
+ border-radius: @at-border-radius;
+ color: @at-gray-dark-3x;
&, &:active {
- border-color: @at-gray-light;
+ border-color: @at-gray-dark-2x;
}
&:focus {
- border-color: @at-link;
+ border-color: @at-blue;
}
}
-.at-Input--placeholder {
- color: @at-gray;
-}
-
.at-Input--focus {
- border-color: @at-link;
+ border-color: @at-blue;
}
.at-InputLabel {
- color: @at-gray-dark;
- font-size: @at-font-sm;
- font-weight: @at-font-weight-sm;
+ color: @at-gray-dark-4x;
+ font-size: @at-font-size-2x;
+ font-weight: @at-font-weight;
text-transform: uppercase;
}
.at-InputLabel-required {
- color: @at-danger;
- font-weight: @at-font-weight-lg;
- font-size: @at-font-lg;
- line-height: @at-font-xs;
- margin: @at-margin-xs @at-margin-xs 0 0;
+ color: @at-red;
+ font-weight: @at-font-weight-2x;
+ font-size: @at-font-size-4x;
+ line-height: @at-line-height-short;
+ margin: @at-space @at-space 0 0;
}
.at-InputGroup {
@@ -45,13 +41,13 @@
position: absolute;
z-index: 3;
pointer-events: none;
- right: @at-padding-sm;
- top: @at-padding-sm;
+ right: @at-space-4x;
+ top: @at-space-4x;
}
}
.at-InputSelect {
- height: @at-input-height-md;
+ height: @at-input-height;
position: relative;
}
@@ -62,6 +58,7 @@
}
.at-InputSelect-select {
+ cursor: pointer;
position: absolute;
z-index: 1;
top: 0;
diff --git a/awx/ui/client/components/input/select.directive.js b/awx/ui/client/components/input/select.directive.js
index 4bd605df44..d1ef291dc4 100644
--- a/awx/ui/client/components/input/select.directive.js
+++ b/awx/ui/client/components/input/select.directive.js
@@ -2,7 +2,7 @@ let eventService;
let pathService;
function link (scope, el, attrs, form) {
- form.use(scope, el);
+ form.use('input', scope, el);
let apply = eventService.listenWith(scope);
@@ -11,9 +11,8 @@ function link (scope, el, attrs, form) {
input.addEventListener('focus', apply(select.focus));
select.addEventListener('mousedown', apply(() => scope.open = !scope.open));
- select.addEventListener('change', () => apply(() => scope.open = false));
+ select.addEventListener('change', apply(() => scope.open = false));
select.addEventListener('focus', apply(() => input.classList.add('at-Input--focus')));
-
select.addEventListener('blur', apply(() => {
input.classList.remove('at-Input--focus');
scope.open = scope.open && false;
diff --git a/awx/ui/client/components/input/text.directive.js b/awx/ui/client/components/input/text.directive.js
index 5bb3b57490..c46a7a9a18 100644
--- a/awx/ui/client/components/input/text.directive.js
+++ b/awx/ui/client/components/input/text.directive.js
@@ -1,5 +1,5 @@
function link (scope, el, attrs, form) {
- form.use(scope, el);
+ form.use('input', scope, el);
}
function atInputText (pathService) {
diff --git a/awx/ui/client/components/panel/_index.less b/awx/ui/client/components/panel/_index.less
index fca076deb3..3770023b6c 100644
--- a/awx/ui/client/components/panel/_index.less
+++ b/awx/ui/client/components/panel/_index.less
@@ -1,6 +1,7 @@
.at-Panel {
- margin: @at-margin-md 0 0 0;
- padding: @at-padding-md;
+ margin: @at-space-6x 0 0 0;
+ padding: @at-space-6x;
+ border-color: @at-gray-dark;
}
.at-Panel-heading {
@@ -9,20 +10,20 @@
}
.at-Panel-dismiss {
- .at-IconButton();
+ .at-mixin-ButtonIcon();
text-align: right;
}
.at-Panel-body {
- margin: @at-margin-md 0 0 0;
+ margin: @at-space-6x 0 0 0;
padding: 0;
}
.at-Panel-headingTitle {
- color: @at-gray-dark;
- font-size: @at-font-md;
- font-weight: bold;
- line-height: 0.9;
+ color: @at-gray-dark-4x;
+ font-size: @at-font-size-3x;
+ font-weight: @at-font-weight-2x;
+ line-height: @at-line-height-short;
text-transform: uppercase;
margin: 0;
padding: 0;
diff --git a/awx/ui/client/components/panel/heading.partial.html b/awx/ui/client/components/panel/heading.partial.html
index 1f5b2ed682..d6aa273e8c 100644
--- a/awx/ui/client/components/panel/heading.partial.html
+++ b/awx/ui/client/components/panel/heading.partial.html
@@ -6,7 +6,7 @@
diff --git a/awx/ui/client/components/popover/_index.less b/awx/ui/client/components/popover/_index.less
index 72fe359eba..b3bbb5f60a 100644
--- a/awx/ui/client/components/popover/_index.less
+++ b/awx/ui/client/components/popover/_index.less
@@ -1,7 +1,7 @@
.at-Popover-icon {
- .at-IconButton();
- font-size: @at-font-md;
- padding: 0 0 0 @at-padding-xxs;
+ .at-mixin-ButtonIcon();
+ font-size: @at-font-size-3x;
+ padding: 0 0 0 @at-space-2x;
margin: 0;
}
@@ -9,22 +9,22 @@
visibility: hidden;
opacity: 0;
color: @at-white;
- background-color: @at-gray-dark;
+ background-color: @at-gray-dark-4x;
max-width: @at-popover-width;
- padding: @at-padding-md;
+ padding: @at-space-4x;
height: auto;
position: fixed;
z-index: 2000;
- margin: 0 0 0 @at-margin-md;
- border-radius: @at-border-radius-md;
+ margin: 0 0 0 @at-space-6x;
+ border-radius: @at-border-radius;
box-shadow: 0 5px 10px rgba(0,0,0, 0.2);
transition: opacity .15s linear;
}
.at-Popover-arrow {
- color: @at-gray-dark;
+ color: @at-gray-dark-4x;
position: fixed;
z-index: 1999;
padding: 0;
- margin: -@at-margin-xxs 0 0 0;
+ margin: -@at-space 0 0 0;
}
diff --git a/awx/ui/client/components/toggle/_index.less b/awx/ui/client/components/toggle/_index.less
index 4e5a52f4bf..0c3e0a824a 100644
--- a/awx/ui/client/components/toggle/_index.less
+++ b/awx/ui/client/components/toggle/_index.less
@@ -5,7 +5,7 @@
}
&:hover {
- background-color: @at-gray-lighter;
+ background-color: @at-gray-light-2x;
}
& > span:hover {
@@ -16,17 +16,17 @@
.at-ToggleButton--show {
&, &:hover, &:focus {
- background-color: @at-link;
- border-color: @at-link;
+ background-color: @at-blue;
+ border-color: @at-blue;
color: @at-white;
}
}
.at-ToggleContent-well {
- margin: @at-margin-sm 0 0 0;
- padding: @at-padding-md;
- border-radius: 4px;
+ margin: @at-space-2x 0 0 0;
+ padding: @at-space-3x;
+ border-radius: @at-border-radius;
border: 1px solid transparent;
- background-color: @at-gray-lightest;
- color: @at-gray-dark;
+ background-color: @at-gray-light-2x;
+ color: @at-gray-dark-2x;
}
diff --git a/awx/ui/client/src/credentials/add-credentials.controller.js b/awx/ui/client/src/credentials/add-credentials.controller.js
index 2f32e4a66b..5fa9eea0cb 100644
--- a/awx/ui/client/src/credentials/add-credentials.controller.js
+++ b/awx/ui/client/src/credentials/add-credentials.controller.js
@@ -34,6 +34,14 @@ function AddCredentialsController (credentialType) {
value: 'id',
data: credentialType.categorizeByKind()
};
+
+ vm.save = {
+ type: 'save'
+ };
+
+ vm.cancel = {
+ type: 'cancel'
+ };
}
AddCredentialsController.$inject = [
diff --git a/awx/ui/client/src/credentials/add-credentials.view.html b/awx/ui/client/src/credentials/add-credentials.view.html
index cb5f3f5c83..05ba307a44 100644
--- a/awx/ui/client/src/credentials/add-credentials.view.html
+++ b/awx/ui/client/src/credentials/add-credentials.view.html
@@ -1,12 +1,21 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/awx/ui/client/theme/_common.less b/awx/ui/client/theme/_common.less
index d85df32ae1..35317df60c 100644
--- a/awx/ui/client/theme/_common.less
+++ b/awx/ui/client/theme/_common.less
@@ -5,29 +5,36 @@
*
*/
-// 1. Buttons
-// ------------------------------------------------------------------------------------------------
-.at-Button--success {
- .at-Button(@at-success, @at-white);
-}
-.at-Button--link {
- .at-Button(@at-link, @at-white);
-}
-.at-Button--danger {
- .at-Button(@at-danger, @at-white);
-}
-.at-Button--default {
- .at-Button(@at-white, @at-gray);
+// 1. Buttons -------------------------------------------------------------------------------------
- border-color: @at-gray-light;
-
- &:hover {
- background: @at-gray-lightest;
- }
+.at-Button--green {
+ .at-mixin-Button();
+ .at-mixin-ButtonColor('at-green', 'at-white');
+}
+
+.at-Button--blue {
+ .at-mixin-Button();
+ .at-mixin-ButtonColor('at-blue', 'at-white');
}
-.at-Button--icon {
- padding: @at-padding-xxs @at-padding-sm;
- font-size: @at-font-lg;
+.at-Button--red {
+ .at-mixin-Button();
+ .at-mixin-ButtonColor('at-red', 'at-white');
}
+.at-ButtonHollow--white {
+ .at-mixin-Button();
+ .at-mixin-ButtonHollow('at-gray-dark-4x', 'at-gray-dark-2x');
+
+ border-color: @at-gray-dark-2x;
+
+ &:hover, &:focus {
+ color: @at-gray-dark-4x;
+ background-color: @at-white--hover;
+ }
+}
+
+.at-ButtonIcon {
+ padding: @at-space-2x @at-space-4x;
+ font-size: @at-font-size-3x;
+}
diff --git a/awx/ui/client/theme/_mixins.less b/awx/ui/client/theme/_mixins.less
index ab8627e33f..28368fa30a 100644
--- a/awx/ui/client/theme/_mixins.less
+++ b/awx/ui/client/theme/_mixins.less
@@ -1,17 +1,4 @@
-.at-IconButton () {
- line-height: 0.9;
- color: @at-gray-light;
-
- & > i {
- cursor: pointer;
- }
-
- & > i:hover {
- color: @at-gray;
- }
-}
-
-.at-Placeholder (@color) {
+.at-mixin-Placeholder (@color) {
&:-moz-placeholder {
color: @color;
}
@@ -23,13 +10,54 @@
}
}
-.at-Button (@bg, @color) {
- color: @color;
- background-color: @bg;
- padding: @at-padding-xs @at-padding-md;
+.at-mixin-Button () {
+ padding: @at-space-2x @at-space-4x;
+}
- &:hover {
- color: @color;
- background-color: '@{bg}-dark';
+.at-mixin-ButtonColor (@background, @color, @hover: '@{background}--hover') {
+ background-color: @@background;
+
+ &, &:hover, &:focus {
+ color: @@color;
+ }
+
+ &:hover, &:focus {
+ background-color: @@hover;
+ }
+
+ &[disabled] {
+ background-color: fade(@@background, 60%);
+ }
+}
+
+.at-mixin-ButtonHollow (@color, @hover: '@{color}--hover') {
+ background-color: @at-white;
+
+ color: @@color;
+ border-color: @@color;
+
+ &:hover, &:focus {
+ color: @@hover;
+ border-color: @@hover;
+ background-color: @at-white;
+ }
+
+ &[disabled] {
+ background-color: fade(@@color, 30%);
+ border-color: fade(@@color, 30%);
+ color: @at-white;
+ }
+}
+
+.at-mixin-ButtonIcon () {
+ line-height: @at-line-height-short;
+ color: @at-gray-dark-2x;
+
+ & > i {
+ cursor: pointer;
+ }
+
+ & > i:hover {
+ color: @at-gray-dark-3x;
}
}
diff --git a/awx/ui/client/theme/_variables.less b/awx/ui/client/theme/_variables.less
index 047990befc..852700b147 100644
--- a/awx/ui/client/theme/_variables.less
+++ b/awx/ui/client/theme/_variables.less
@@ -1,39 +1,65 @@
+/**
+ * All variables used in the UI.
+ *
+ * 1. Colors
+ * 2. Typography
+ * 3. Layout
+ * 4. Misc
+ */
+
+// 1. Colors --------------------------------------------------------------------------------------
+@at-gray-light-5x: #fcfcfc;
+@at-gray-light-4x: #fafafa;
+@at-gray-light-3x: #f6f6f6;
+@at-gray-light-2x: #f2f2f2;
+@at-gray-light: #ebebeb;
+@at-gray: #e1e1e1;
+@at-gray-dark: #d7d7d7;
+@at-gray-dark-2x: #b7b7b7;
+@at-gray-dark-3x: #8f8992;
+@at-gray-dark-4x: #707070;
+@at-gray-dark-5x: #161b1f;
+
@at-white: #ffffff;
-@at-gray-lightest: #fafafa;
-@at-gray-lighter: #f6f6f6;
-@at-gray-light: #b7b7b7;
-@at-gray: #848992;
-@at-gray-dark: #707070;
-@at-gray-darkest: #161b1f;
-@at-link: #337ab7;
-@at-link-dark: #286090;
-@at-success: #5cb85c;
-@at-success-dark: #449D44;
-@at-danger: #d9534f;
+@at-white--hover: #f2f2f2;
-@at-font-xs: 12px;
-@at-font-sm: 13px;
-@at-font-md: 14px;
-@at-font-lg: 16px;
+@at-blue: #337ab7;
+@at-blue--hover: #286090;
-@at-font-weight-sm: 400;
-@at-font-weight-md: 700;
-@at-font-weight-lg: 900;
+@at-green: #5cb85c;
+@at-green--hover: #449D44;
-@at-padding-xxs: 5px;
-@at-padding-xs: 6px;
-@at-padding-sm: 10px;
-@at-padding-md: 20px;
+@at-yellow: #f0ad4e;
+@at-yellow--hover: #ec971f;
-@at-margin-xxs: 3px;
-@at-margin-xs: 4px;
-@at-margin-sm: 10px;
-@at-margin-md: 20px;
+@at-red: #d9534f;
+@at-red--hover: #c9302c;
-@at-border-radius-md: 5px;
+@at-redAlert: #ff0000;
+@at-redAlert--hover: #d81f1f;
-@at-input-height-md: 34px;
+// 2. Typography ----------------------------------------------------------------------------------
+@at-font-size: 12px;
+@at-font-size-2x: 13px;
+@at-font-size-3x: 14px;
+@at-font-size-4x: 16px;
-@at-line-height-md: 24px;
+@at-font-weight: 400;
+@at-font-weight-2x: 700;
+@at-font-weight-3x: 900;
+@at-line-height-short: 0.9;
+@at-line-height: 24px;
+
+// 3. Layout --------------------------------------------------------------------------------------
+@at-space: 3px;
+@at-space-2x: 4px;
+@at-space-3x: 5px;
+@at-space-4x: 10px;
+@at-space-5x: 15px;
+@at-space-6x: 20px;
+
+// 4. Misc --------------------------------------------------------------------------------------
+@at-border-radius: 5px;
+@at-input-height: 34px;
@at-popover-width: 320px;