mirror of
https://github.com/ansible/awx.git
synced 2026-03-16 16:37:30 -02:30
org cards implementation with rollups
This commit is contained in:
@@ -27,6 +27,7 @@
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
padding-bottom: 20px;
|
padding-bottom: 20px;
|
||||||
|
min-height: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Form-title--is_superuser{
|
.Form-title--is_superuser{
|
||||||
@@ -69,6 +70,7 @@
|
|||||||
.Form-tabHolder{
|
.Form-tabHolder{
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
|
min-height: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.Form-tab {
|
.Form-tab {
|
||||||
|
|||||||
@@ -569,9 +569,14 @@ var tower = angular.module('Tower', [
|
|||||||
}
|
}
|
||||||
}).
|
}).
|
||||||
|
|
||||||
|
state('organizations.cards', {
|
||||||
|
url: '/foo',
|
||||||
|
templateUrl: urlPrefix + 'organizations/cards.partial.html',
|
||||||
|
}).
|
||||||
|
|
||||||
state('organizations.add', {
|
state('organizations.add', {
|
||||||
url: '/add',
|
url: '/add',
|
||||||
templateUrl: urlPrefix + 'partials/organizations.html',
|
templateUrl: urlPrefix + 'partials/organizations.crud.html',
|
||||||
controller: OrganizationsAdd,
|
controller: OrganizationsAdd,
|
||||||
ncyBreadcrumb: {
|
ncyBreadcrumb: {
|
||||||
parent: "organizations",
|
parent: "organizations",
|
||||||
@@ -586,7 +591,7 @@ var tower = angular.module('Tower', [
|
|||||||
|
|
||||||
state('organizations.edit', {
|
state('organizations.edit', {
|
||||||
url: '/:organization_id',
|
url: '/:organization_id',
|
||||||
templateUrl: urlPrefix + 'partials/organizations.html',
|
templateUrl: urlPrefix + 'partials/organizations.crud.html',
|
||||||
controller: OrganizationsEdit,
|
controller: OrganizationsEdit,
|
||||||
resolve: {
|
resolve: {
|
||||||
features: ['FeaturesService', function(FeaturesService) {
|
features: ['FeaturesService', function(FeaturesService) {
|
||||||
|
|||||||
@@ -12,27 +12,58 @@
|
|||||||
|
|
||||||
|
|
||||||
export function OrganizationsList($stateParams, $scope, $rootScope, $location,
|
export function OrganizationsList($stateParams, $scope, $rootScope, $location,
|
||||||
$log, Rest, Alert, Prompt, GenerateList, OrganizationList, SearchInit,
|
$log, Rest, Alert, Prompt, ClearScope, ProcessErrors, GetBasePath, Wait,
|
||||||
PaginateInit, ClearScope, ProcessErrors, GetBasePath, SelectionInit, Wait,
|
|
||||||
Stream, $state) {
|
Stream, $state) {
|
||||||
|
|
||||||
ClearScope();
|
ClearScope();
|
||||||
|
|
||||||
var list = OrganizationList,
|
var defaultUrl = GetBasePath('organizations');
|
||||||
generate = GenerateList,
|
|
||||||
paths = $location.path().replace(/^\//, '').split('/'),
|
var parseCardData = function (cards) {
|
||||||
mode = (paths[0] === 'organizations') ? 'edit' : 'select',
|
return cards.map(function (card) {
|
||||||
defaultUrl = GetBasePath('organizations'),
|
var val = {};
|
||||||
url;
|
val.name = card.name;
|
||||||
|
val.id = card.id;
|
||||||
|
if (card.id + "" === cards.activeCard) {
|
||||||
|
val.isActiveCard = true;
|
||||||
|
}
|
||||||
|
val.description = card.description || undefined;
|
||||||
|
return val;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var getOrganization = function (id) {
|
||||||
|
Rest.setUrl(defaultUrl);
|
||||||
|
Rest.get()
|
||||||
|
.success(function (data) {
|
||||||
|
data.results.activeCard = id;
|
||||||
|
$scope.orgCount = data.count;
|
||||||
|
$scope.orgCards = parseCardData(data.results);
|
||||||
|
Wait("stop");
|
||||||
|
})
|
||||||
|
.error(function (data, status) {
|
||||||
|
ProcessErrors($scope, data, status, null, { hdr: 'Error!',
|
||||||
|
msg: 'Call to ' + defaultUrl + ' failed. DELETE returned status: ' + status });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.$on("ReloadOrganzationCards", function(e, id) {
|
||||||
|
$scope.activeCard = id;
|
||||||
|
getOrganization(id);
|
||||||
|
});
|
||||||
|
|
||||||
|
$scope.$on("HideOrgListHeader", function() {
|
||||||
|
$scope.hideListHeader = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
$scope.$on("ShowOrgListHeader", function() {
|
||||||
|
$scope.hideListHeader = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
getOrganization();
|
||||||
|
|
||||||
generate.inject(OrganizationList, { mode: mode, scope: $scope });
|
|
||||||
$rootScope.flashMessage = null;
|
$rootScope.flashMessage = null;
|
||||||
|
|
||||||
if (mode === 'select') {
|
|
||||||
url = GetBasePath('projects') + $stateParams.project_id + '/organizations/';
|
|
||||||
SelectionInit({ scope: $scope, list: list, url: url, returnToCaller: 1 });
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($scope.removePostRefresh) {
|
if ($scope.removePostRefresh) {
|
||||||
$scope.removePostRefresh();
|
$scope.removePostRefresh();
|
||||||
}
|
}
|
||||||
@@ -42,20 +73,6 @@ export function OrganizationsList($stateParams, $scope, $rootScope, $location,
|
|||||||
$('#prompt-modal').modal('hide');
|
$('#prompt-modal').modal('hide');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Initialize search and pagination, then load data
|
|
||||||
SearchInit({
|
|
||||||
scope: $scope,
|
|
||||||
set: list.name,
|
|
||||||
list: list,
|
|
||||||
url: defaultUrl
|
|
||||||
});
|
|
||||||
PaginateInit({
|
|
||||||
scope: $scope,
|
|
||||||
list: list,
|
|
||||||
url: defaultUrl
|
|
||||||
});
|
|
||||||
$scope.search(list.iterator);
|
|
||||||
|
|
||||||
$scope.showActivity = function () {
|
$scope.showActivity = function () {
|
||||||
Stream({ scope: $scope });
|
Stream({ scope: $scope });
|
||||||
};
|
};
|
||||||
@@ -65,6 +82,7 @@ export function OrganizationsList($stateParams, $scope, $rootScope, $location,
|
|||||||
};
|
};
|
||||||
|
|
||||||
$scope.editOrganization = function (id) {
|
$scope.editOrganization = function (id) {
|
||||||
|
$scope.activeCard = id;
|
||||||
$state.transitionTo('organizations.edit', {organization_id: id});
|
$state.transitionTo('organizations.edit', {organization_id: id});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -77,7 +95,10 @@ export function OrganizationsList($stateParams, $scope, $rootScope, $location,
|
|||||||
Rest.setUrl(url);
|
Rest.setUrl(url);
|
||||||
Rest.destroy()
|
Rest.destroy()
|
||||||
.success(function () {
|
.success(function () {
|
||||||
$scope.search(list.iterator);
|
if ($state.current.name !== "organzations") {
|
||||||
|
$state.transitionTo("organizations");
|
||||||
|
}
|
||||||
|
$scope.$emit("ReloadOrganzationCards");
|
||||||
})
|
})
|
||||||
.error(function (data, status) {
|
.error(function (data, status) {
|
||||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!',
|
ProcessErrors($scope, data, status, null, { hdr: 'Error!',
|
||||||
@@ -94,9 +115,8 @@ export function OrganizationsList($stateParams, $scope, $rootScope, $location,
|
|||||||
}
|
}
|
||||||
|
|
||||||
OrganizationsList.$inject = ['$stateParams', '$scope', '$rootScope',
|
OrganizationsList.$inject = ['$stateParams', '$scope', '$rootScope',
|
||||||
'$location', '$log', 'Rest', 'Alert', 'Prompt', 'generateList',
|
'$location', '$log', 'Rest', 'Alert', 'Prompt', 'ClearScope',
|
||||||
'OrganizationList', 'SearchInit', 'PaginateInit', 'ClearScope',
|
'ProcessErrors', 'GetBasePath', 'Wait',
|
||||||
'ProcessErrors', 'GetBasePath', 'SelectionInit', 'Wait',
|
|
||||||
'Stream', '$state'
|
'Stream', '$state'
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -115,6 +135,8 @@ export function OrganizationsAdd($scope, $rootScope, $compile, $location, $log,
|
|||||||
generator.inject(form, { mode: 'add', related: false, scope: $scope});
|
generator.inject(form, { mode: 'add', related: false, scope: $scope});
|
||||||
generator.reset();
|
generator.reset();
|
||||||
|
|
||||||
|
$scope.$emit("HideOrgListHeader");
|
||||||
|
|
||||||
// Save
|
// Save
|
||||||
$scope.formSave = function () {
|
$scope.formSave = function () {
|
||||||
generator.clearApiErrors();
|
generator.clearApiErrors();
|
||||||
@@ -125,6 +147,7 @@ export function OrganizationsAdd($scope, $rootScope, $compile, $location, $log,
|
|||||||
Rest.post({ name: $scope.name, description: $scope.description })
|
Rest.post({ name: $scope.name, description: $scope.description })
|
||||||
.success(function (data) {
|
.success(function (data) {
|
||||||
Wait('stop');
|
Wait('stop');
|
||||||
|
$scope.$emit("ReloadOrganzationCards", data.id);
|
||||||
if (base === 'organizations') {
|
if (base === 'organizations') {
|
||||||
$rootScope.flashMessage = "New organization successfully created!";
|
$rootScope.flashMessage = "New organization successfully created!";
|
||||||
$location.path('/organizations/' + data.id);
|
$location.path('/organizations/' + data.id);
|
||||||
@@ -139,6 +162,8 @@ export function OrganizationsAdd($scope, $rootScope, $compile, $location, $log,
|
|||||||
};
|
};
|
||||||
|
|
||||||
$scope.formCancel = function () {
|
$scope.formCancel = function () {
|
||||||
|
$scope.$emit("ReloadOrganzationCards");
|
||||||
|
$scope.$emit("ShowOrgListHeader");
|
||||||
$state.transitionTo('organizations');
|
$state.transitionTo('organizations');
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -166,6 +191,10 @@ export function OrganizationsEdit($scope, $rootScope, $compile, $location, $log,
|
|||||||
id = $stateParams.organization_id,
|
id = $stateParams.organization_id,
|
||||||
relatedSets = {};
|
relatedSets = {};
|
||||||
|
|
||||||
|
$scope.$emit("HideOrgListHeader");
|
||||||
|
|
||||||
|
$scope.$emit("ReloadOrganzationCards", id);
|
||||||
|
|
||||||
$scope.organization_id = id;
|
$scope.organization_id = id;
|
||||||
|
|
||||||
generator.inject(form, { mode: 'edit', related: true, scope: $scope});
|
generator.inject(form, { mode: 'edit', related: true, scope: $scope});
|
||||||
@@ -225,11 +254,12 @@ export function OrganizationsEdit($scope, $rootScope, $compile, $location, $log,
|
|||||||
}
|
}
|
||||||
Rest.setUrl(defaultUrl + id + '/');
|
Rest.setUrl(defaultUrl + id + '/');
|
||||||
Rest.put(params)
|
Rest.put(params)
|
||||||
.success(function () {
|
.success(function (data) {
|
||||||
Wait('stop');
|
Wait('stop');
|
||||||
$scope.organization_name = $scope.name;
|
$scope.organization_name = $scope.name;
|
||||||
master = params;
|
master = params;
|
||||||
$rootScope.flashMessage = "Your changes were successfully saved!";
|
$rootScope.flashMessage = "Your changes were successfully saved!";
|
||||||
|
$scope.$emit("ReloadOrganzationCards", data.id);
|
||||||
})
|
})
|
||||||
.error(function (data, status) {
|
.error(function (data, status) {
|
||||||
ProcessErrors($scope, data, status, OrganizationForm, { hdr: 'Error!',
|
ProcessErrors($scope, data, status, OrganizationForm, { hdr: 'Error!',
|
||||||
@@ -244,6 +274,8 @@ export function OrganizationsEdit($scope, $rootScope, $compile, $location, $log,
|
|||||||
};
|
};
|
||||||
|
|
||||||
$scope.formCancel = function () {
|
$scope.formCancel = function () {
|
||||||
|
$scope.$emit("ReloadOrganzationCards");
|
||||||
|
$scope.$emit("ShowOrgListHeader");
|
||||||
$state.transitionTo('organizations');
|
$state.transitionTo('organizations');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -82,8 +82,6 @@ export default
|
|||||||
scope.getPage(currentPage, set, iterator);
|
scope.getPage(currentPage, set, iterator);
|
||||||
});
|
});
|
||||||
} else if ($location.$$url.split("/")[1] === params.set && $location.$$url.split("/")[2] && $location.$$url.split("/")[2] !== "add" && !scope.getNewPage) {
|
} else if ($location.$$url.split("/")[1] === params.set && $location.$$url.split("/")[2] && $location.$$url.split("/")[2] !== "add" && !scope.getNewPage) {
|
||||||
delete $rootScope.rowBeingEdited;
|
|
||||||
delete $rootScope.listBeingEdited;
|
|
||||||
var id = $location.$$url.split("/")[2];
|
var id = $location.$$url.split("/")[2];
|
||||||
var restUrl = params.url.split("?")[0];
|
var restUrl = params.url.split("?")[0];
|
||||||
var pageSize = scope[iterator + '_page_size'];
|
var pageSize = scope[iterator + '_page_size'];
|
||||||
|
|||||||
98
awx/ui/client/src/organizations/orgcards.block.less
Normal file
98
awx/ui/client/src/organizations/orgcards.block.less
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
/** @define OrgCards */
|
||||||
|
|
||||||
|
.OrgCards {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.OrgCards-card {
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 5px;
|
||||||
|
border: 1px solid #e8e8e8;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: baseline;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.OrgCards-card--selected {
|
||||||
|
padding-left: 16px;
|
||||||
|
border-left: 5px solid #1678C4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.OrgCards-header {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
align-items: baseline;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.OrgCards-label {
|
||||||
|
margin-top: 0px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #848992;
|
||||||
|
margin-bottom: 25px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.OrgCards-actionItems {
|
||||||
|
margin-left: auto;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.OrgCards-actionItem {
|
||||||
|
margin-left: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.OrgCards-description {
|
||||||
|
margin-bottom: 0px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1179px) {
|
||||||
|
.OrgCards-card {
|
||||||
|
width: ~"calc(25% - 15px)";
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.OrgCards-card:nth-child(4n+4) {
|
||||||
|
margin-right: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 901px) and (max-width: 1178px) {
|
||||||
|
.OrgCards-card {
|
||||||
|
width: ~"calc(33% - 11px)";
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.OrgCards-card:nth-child(3n+3) {
|
||||||
|
margin-right: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 616px) and (max-width: 900px) {
|
||||||
|
.OrgCards-card {
|
||||||
|
width: ~"calc(50% - 10px)";
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.OrgCards-card:nth-child(2n+2) {
|
||||||
|
margin-right: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 615px) {
|
||||||
|
.OrgCards-card {
|
||||||
|
width: 100%;
|
||||||
|
margin-right: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
4
awx/ui/client/src/partials/organizations.crud.html
Normal file
4
awx/ui/client/src/partials/organizations.crud.html
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<div class="tab-pane" id="organizations">
|
||||||
|
<div ui-view></div>
|
||||||
|
<div ng-cloak id="htmlTemplate" class="Panel"></div>
|
||||||
|
</div>
|
||||||
@@ -1,4 +1,47 @@
|
|||||||
<div class="tab-pane" id="organizations">
|
<div class="tab-pane" id="organizations">
|
||||||
<div ui-view></div>
|
<div ui-view></div>
|
||||||
<div ng-cloak id="htmlTemplate" class="Panel"></div>
|
<div ng-cloak id="htmlTemplate" class="Panel" ng-hide="hideListHeader">
|
||||||
|
<div class="List-header">
|
||||||
|
<div class="List-title">
|
||||||
|
<div class="List-titleText">
|
||||||
|
organizations
|
||||||
|
</div>
|
||||||
|
<span class="badge List-titleBadge">
|
||||||
|
{{ orgCount }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="List-actions">
|
||||||
|
<button class="btn List-buttonSubmit"
|
||||||
|
aw-tool-tip="Create a new organization"
|
||||||
|
ng-click="addOrganization()">
|
||||||
|
+ ADD
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="OrgCards">
|
||||||
|
<div class="OrgCards-card"
|
||||||
|
ng-class="{'OrgCards-card--selected': activeCard === card.id || card.isActiveCard }"
|
||||||
|
ng-repeat="card in orgCards track by card.id">
|
||||||
|
<div class="OrgCards-header">
|
||||||
|
<h3 class="OrgCards-label">{{ card.name }}</h3>
|
||||||
|
<div class="OrgCards-actionItems">
|
||||||
|
<button class="OrgCards-actionItem
|
||||||
|
List-actionButton"
|
||||||
|
ng-click="editOrganization(card.id)">
|
||||||
|
<i class="OrgCards-actionItemIcon fa fa-pencil">
|
||||||
|
</i>
|
||||||
|
</button>
|
||||||
|
<button class="OrgCards-actionItem List-actionButton
|
||||||
|
List-actionButton--delete"
|
||||||
|
ng-click="deleteOrganization(card.id, card.name)">
|
||||||
|
<i class="OrgCards-actionItemIcon
|
||||||
|
fa fa-trash-o">
|
||||||
|
</i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="OrgCards-description">{{ card.description || "Place organization description here" }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -53,7 +53,7 @@
|
|||||||
@list-pagin-bord-act: @default-icon-hov;
|
@list-pagin-bord-act: @default-icon-hov;
|
||||||
@list-pagin-bg-act: @default-icon-hov;
|
@list-pagin-bg-act: @default-icon-hov;
|
||||||
@list-title-txt: @default-interface-txt;
|
@list-title-txt: @default-interface-txt;
|
||||||
@list-title-badge: @default-icon-hov;
|
@list-title-badge: @default-icon;
|
||||||
@list-srch-inpt-bg: @default-secondary-bg;
|
@list-srch-inpt-bg: @default-secondary-bg;
|
||||||
@list-srch-inpt-txt: @default-data-txt;
|
@list-srch-inpt-txt: @default-data-txt;
|
||||||
@list-srch-inpt-ph-txt: @default-icon;
|
@list-srch-inpt-ph-txt: @default-icon;
|
||||||
|
|||||||
Reference in New Issue
Block a user