Add ngSwift containers and objects display
This patch adds listing of containers and objects in selected containers, but not additional functionality. That additional functionality will be added in subsequent patches. To test set DISABLED = False in _1921_project_ng_containers_panel.py Change-Id: I37980a7b84dbddb99d8f1d4d8235cc11917da30e Co-Author: Neill Cox <neill@ingenious.com.au> Partially-Implements: blueprint angularize-swift
This commit is contained in:
parent
b09f0e8c63
commit
4c39136997
@ -2,10 +2,14 @@
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Containers" %}{% endblock %}
|
||||
|
||||
{% block ng_route_base %}
|
||||
<base href="{{ WEBROOT }}">
|
||||
{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
{% include "horizon/common/_page_header.html" with title=_("Containers") %}
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block main %}
|
||||
[This content to be replaced in follow-on patch with actual interface.]
|
||||
<ng-include src="'{{ STATIC_URL }}dashboard/project/containers/containers.html'"></ng-include>
|
||||
{% endblock %}
|
||||
|
@ -12,15 +12,11 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from django.conf.urls import patterns
|
||||
from django.conf.urls import url
|
||||
|
||||
from openstack_dashboard.dashboards.project.ngcontainers import views
|
||||
|
||||
|
||||
VIEW_MOD = 'openstack_dashboard.dashboards.project.ngcontainers.views'
|
||||
|
||||
urlpatterns = patterns(
|
||||
'openstack_dashboard.dashboards.project.ngcontainers.views',
|
||||
url(r'^$', views.IndexView.as_view(), name='index'),
|
||||
)
|
||||
urlpatterns = [
|
||||
url(r'^(container/(?P<container_name>.+?)/(?P<subfolder_path>(.+/)+)?)?$',
|
||||
views.IndexView.as_view(), name='index')
|
||||
]
|
||||
|
@ -0,0 +1,51 @@
|
||||
.hz-container-accordion {
|
||||
cursor: pointer;
|
||||
|
||||
.accordion-toggle:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.panel-body {
|
||||
padding: 5px;
|
||||
|
||||
ul {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
// have the toggle <a> fill the whole heading to make it clickable
|
||||
.panel-heading {
|
||||
padding: 0;
|
||||
|
||||
& > h4 > a {
|
||||
padding: $panel-heading-padding;
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.hz-container-title,
|
||||
.hz-container-toggle {
|
||||
&, &:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.hz-objects {
|
||||
.page_title > th {
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.hz-object-path {
|
||||
margin-bottom: 0;
|
||||
padding-left: 0;
|
||||
padding-top: 0;
|
||||
|
||||
& > li {
|
||||
&:nth-child(2):before {
|
||||
content: ":";
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* (c) Copyright 2015 Rackspace US, Inc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var push = Array.prototype.push;
|
||||
|
||||
/**
|
||||
* @ngdoc overview
|
||||
* @name horizon.dashboard.project.containers
|
||||
*
|
||||
* @description
|
||||
* Provide a model for the display of containers.
|
||||
*/
|
||||
|
||||
angular
|
||||
.module('horizon.dashboard.project.containers')
|
||||
.factory('horizon.dashboard.project.containers.containers-model', ContainersModel);
|
||||
|
||||
ContainersModel.$inject = [
|
||||
'horizon.app.core.openstack-service-api.swift',
|
||||
'$q'
|
||||
];
|
||||
|
||||
/**
|
||||
* @ngdoc service
|
||||
* @name ContainersModel
|
||||
*
|
||||
* @description
|
||||
* This is responsible for providing data to the containers
|
||||
* interface. It is also the center point of communication
|
||||
* between the UI and services API.
|
||||
*/
|
||||
function ContainersModel(swiftAPI, $q) {
|
||||
var model = {
|
||||
info: {},
|
||||
containers: [],
|
||||
containerName: '',
|
||||
objects: [],
|
||||
folder: '',
|
||||
pseudo_folder_hierarchy: [],
|
||||
DELIMETER: '/', // TODO where is this configured in the current panel
|
||||
|
||||
initialize: initialize,
|
||||
selectContainer: selectContainer
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name ContainersModel.initialize
|
||||
* @returns {promise}
|
||||
*
|
||||
* @description
|
||||
* Send request to get data to initialize the model.
|
||||
*/
|
||||
function initialize() {
|
||||
return $q.all(
|
||||
swiftAPI.getContainers().then(function onContainers(data) {
|
||||
model.containers.length = 0;
|
||||
push.apply(model.containers, data.data.items);
|
||||
}),
|
||||
swiftAPI.getInfo().then(function onInfo(data) {
|
||||
model.swift_info = data.info;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function selectContainer(name, folder) {
|
||||
model.containerName = name;
|
||||
model.objects.length = 0;
|
||||
model.pseudo_folder_hierarchy.length = 0;
|
||||
model.folder = folder;
|
||||
|
||||
var spec = {
|
||||
delimiter: model.DELIMETER
|
||||
};
|
||||
if (folder) {
|
||||
spec.path = folder + model.DELIMETER;
|
||||
}
|
||||
|
||||
return swiftAPI.getObjects(name, spec).then(function onObjects(response) {
|
||||
push.apply(model.objects, response.data.items);
|
||||
if (folder) {
|
||||
push.apply(model.pseudo_folder_hierarchy, folder.split(model.DELIMETER) || [folder]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return model;
|
||||
}
|
||||
})();
|
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* (c) Copyright 2016 Rackspace US, Inc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
describe('horizon.dashboard.project.containers model', function() {
|
||||
beforeEach(module('horizon.app.core.openstack-service-api'));
|
||||
beforeEach(module('horizon.framework'));
|
||||
beforeEach(module('horizon.dashboard.project.containers'));
|
||||
|
||||
var service, $q, $rootScope, swiftAPI;
|
||||
|
||||
beforeEach(inject(function inject($injector, _$q_, _$rootScope_) {
|
||||
service = $injector.get('horizon.dashboard.project.containers.containers-model');
|
||||
$q = _$q_;
|
||||
$rootScope = _$rootScope_;
|
||||
swiftAPI = $injector.get('horizon.app.core.openstack-service-api.swift');
|
||||
}));
|
||||
|
||||
it('should initialise the model', function test() {
|
||||
expect(service.containers).toBeDefined();
|
||||
expect(service.DELIMETER).toBeDefined();
|
||||
});
|
||||
|
||||
it('should retrieve the swift info and user containers on initalize()', function test() {
|
||||
var infoDeferred = $q.defer();
|
||||
spyOn(swiftAPI, 'getInfo').and.returnValue(infoDeferred.promise);
|
||||
var containersDeferred = $q.defer();
|
||||
spyOn(swiftAPI, 'getContainers').and.returnValue(containersDeferred.promise);
|
||||
|
||||
service.initialize();
|
||||
expect(swiftAPI.getInfo).toHaveBeenCalled();
|
||||
expect(swiftAPI.getContainers).toHaveBeenCalled();
|
||||
|
||||
infoDeferred.resolve({info: 'spam'});
|
||||
containersDeferred.resolve({data: {items: ['two', 'items']}});
|
||||
$rootScope.$apply();
|
||||
|
||||
expect(service.swift_info).toEqual('spam');
|
||||
expect(service.containers).toEqual(['two', 'items']);
|
||||
});
|
||||
|
||||
it('should load container contents', function test() {
|
||||
var deferred = $q.defer();
|
||||
spyOn(swiftAPI, 'getObjects').and.returnValue(deferred.promise);
|
||||
|
||||
service.selectContainer('spam');
|
||||
|
||||
expect(service.containerName).toEqual('spam');
|
||||
expect(swiftAPI.getObjects).toHaveBeenCalledWith('spam', {delimiter: '/'});
|
||||
|
||||
deferred.resolve({data: {items: ['two', 'items']}});
|
||||
$rootScope.$apply();
|
||||
|
||||
expect(service.objects).toEqual(['two', 'items']);
|
||||
expect(service.pseudo_folder_hierarchy).toEqual([]);
|
||||
});
|
||||
|
||||
it('should load subfolder contents', function test() {
|
||||
var deferred = $q.defer();
|
||||
spyOn(swiftAPI, 'getObjects').and.returnValue(deferred.promise);
|
||||
|
||||
service.selectContainer('spam', 'ham');
|
||||
|
||||
expect(service.containerName).toEqual('spam');
|
||||
expect(service.folder).toEqual('ham');
|
||||
expect(swiftAPI.getObjects).toHaveBeenCalledWith('spam', {path: 'ham/', delimiter: '/'});
|
||||
|
||||
deferred.resolve({data: {items: ['two', 'items']}});
|
||||
$rootScope.$apply();
|
||||
expect(service.objects).toEqual(['two', 'items']);
|
||||
expect(service.pseudo_folder_hierarchy).toEqual(['ham']);
|
||||
});
|
||||
});
|
||||
})();
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* (c) Copyright 2015 Rackspace US, Inc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @ngdoc controller
|
||||
*
|
||||
* @name horizon.dashboard.project.containers.ContainersController
|
||||
*
|
||||
* @description
|
||||
* Controller for the interface around a list of containers for a single account.
|
||||
*/
|
||||
angular
|
||||
.module('horizon.dashboard.project.containers')
|
||||
.controller('horizon.dashboard.project.containers.ContainersController', ContainersController);
|
||||
|
||||
ContainersController.$inject = [
|
||||
'horizon.dashboard.project.containers.containers-model',
|
||||
'horizon.dashboard.project.containers.containerRoute',
|
||||
'$location'
|
||||
];
|
||||
|
||||
function ContainersController(containersModel, containerRoute, $location) {
|
||||
var ctrl = this;
|
||||
ctrl.model = containersModel;
|
||||
containersModel.initialize();
|
||||
ctrl.containerRoute = containerRoute;
|
||||
ctrl.selectedContainer = '';
|
||||
|
||||
ctrl.selectContainer = function (name) {
|
||||
ctrl.selectedContainer = name;
|
||||
$location.path(containerRoute + name);
|
||||
};
|
||||
}
|
||||
})();
|
@ -0,0 +1,59 @@
|
||||
/**
|
||||
* (c) Copyright 2016 Rackspace US, Inc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
describe('horizon.dashboard.project.containers containers controller', function() {
|
||||
beforeEach(module('horizon.app.core.openstack-service-api'));
|
||||
beforeEach(module('horizon.framework'));
|
||||
beforeEach(module('horizon.dashboard.project'));
|
||||
|
||||
var $location, controller, model;
|
||||
|
||||
beforeEach(inject(function ($injector) {
|
||||
controller = $injector.get('$controller');
|
||||
$location = $injector.get('$location');
|
||||
model = $injector.get('horizon.dashboard.project.containers.containers-model');
|
||||
}));
|
||||
|
||||
function createController() {
|
||||
return controller(
|
||||
'horizon.dashboard.project.containers.ContainersController', {
|
||||
'horizon.dashboard.project.containers.containerRoute': 'eggs '
|
||||
});
|
||||
}
|
||||
|
||||
it('should set containerRoute', function() {
|
||||
var ctrl = createController();
|
||||
expect(ctrl.containerRoute).toBeDefined();
|
||||
});
|
||||
|
||||
it('should invoke initialise the model when created', function() {
|
||||
spyOn(model, 'initialize');
|
||||
createController();
|
||||
expect(model.initialize).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should update current container name when one is selected', function () {
|
||||
spyOn($location, 'path');
|
||||
var ctrl = createController();
|
||||
ctrl.selectContainer('and spam');
|
||||
expect($location.path).toHaveBeenCalledWith('eggs and spam');
|
||||
expect(ctrl.selectedContainer).toEqual('and spam');
|
||||
});
|
||||
});
|
||||
})();
|
@ -0,0 +1,30 @@
|
||||
<div id="containers_wrapper" ng-controller="horizon.dashboard.project.containers.ContainersController as cc">
|
||||
<div class="col-md-3">
|
||||
<accordion class="hz-container-accordion">
|
||||
<accordion-group ng-repeat="container in cc.model.containers track by container.name"
|
||||
ng-class="{'panel-primary': container.name === cc.selectedContainer}"
|
||||
ng-click="cc.selectContainer(container.name)">
|
||||
<accordion-heading>
|
||||
<span class="hz-container-title truncate" title="{$ container.name $}">
|
||||
{$ container.name $}
|
||||
</span>
|
||||
</accordion-heading>
|
||||
|
||||
<ul>
|
||||
<li><translate>Object Count</translate>: {$container.container_object_count$}</li>
|
||||
<li><translate>Size</translate>: {$container.container_bytes_used | bytes$}</li>
|
||||
<li>
|
||||
<translate>Access</translate>:
|
||||
<span ng-if="container.is_public"><translate>Public</translate></span>
|
||||
<span ng-if="!container.is_public"><translate>Private</translate></span>
|
||||
</li>
|
||||
<li><translate>Timestamp</translate>: {$container.timestamp$}</li>
|
||||
</ul>
|
||||
</accordion-group>
|
||||
</accordion>
|
||||
</div>
|
||||
|
||||
<div class="col-md-9">
|
||||
<div ng-view class="objects_wrapper"></div>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,61 @@
|
||||
/**
|
||||
* (c) Copyright 2015 Rackspace, US, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @ngdoc overview
|
||||
* @ngname horizon.dashboard.project.containers
|
||||
*
|
||||
* @description
|
||||
* Provides the services and widgets required
|
||||
* to support and display the project containers panel.
|
||||
*/
|
||||
angular
|
||||
.module('horizon.dashboard.project.containers', ['ngRoute'])
|
||||
.config(config);
|
||||
|
||||
config.$inject = [
|
||||
'$provide',
|
||||
'$routeProvider',
|
||||
'$windowProvider'
|
||||
];
|
||||
|
||||
/**
|
||||
* @name horizon.dashboard.project.containers.basePath
|
||||
* @description Base path for the project dashboard
|
||||
*/
|
||||
function config($provide, $routeProvider, $windowProvider) {
|
||||
var path = $windowProvider.$get().STATIC_URL + 'dashboard/project/containers/';
|
||||
$provide.constant('horizon.dashboard.project.containers.basePath', path);
|
||||
|
||||
var baseRoute = $windowProvider.$get().WEBROOT + 'project/ngcontainers/';
|
||||
var containerRoute = baseRoute + 'container/';
|
||||
$provide.constant('horizon.dashboard.project.containers.containerRoute', containerRoute);
|
||||
|
||||
$routeProvider
|
||||
.when(baseRoute, {
|
||||
templateUrl: path + 'select-container.html'
|
||||
})
|
||||
.when(containerRoute + ':containerName', {
|
||||
templateUrl: path + 'objects.html'
|
||||
})
|
||||
.when(containerRoute + ':containerName/:folder*', {
|
||||
templateUrl: path + 'objects.html'
|
||||
});
|
||||
}
|
||||
})();
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* (c) Copyright 2016 Rackspace US, Inc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
describe('horizon.dashboard.project.containers.containerRoute constant', function () {
|
||||
var containerRoute;
|
||||
|
||||
beforeEach(module('horizon.dashboard.project.containers'));
|
||||
beforeEach(inject(function ($injector) {
|
||||
containerRoute = $injector.get('horizon.dashboard.project.containers.containerRoute');
|
||||
}));
|
||||
|
||||
it('should be defined', function () {
|
||||
expect(containerRoute).toBeDefined();
|
||||
});
|
||||
});
|
||||
})();
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* (c) Copyright 2015 Rackspace US, Inc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @ngdoc controller
|
||||
*
|
||||
* @name horizon.dashboard.project.containers.ObjectsController
|
||||
*
|
||||
* @description
|
||||
* Controller for the interface around the objects in a single container.
|
||||
*/
|
||||
angular
|
||||
.module('horizon.dashboard.project.containers')
|
||||
.controller('horizon.dashboard.project.containers.ObjectsController', ObjectsController);
|
||||
|
||||
ObjectsController.$inject = [
|
||||
'horizon.dashboard.project.containers.containers-model',
|
||||
'horizon.dashboard.project.containers.containerRoute',
|
||||
'$routeParams'
|
||||
];
|
||||
|
||||
function ObjectsController(containersModel, containerRoute, $routeParams) {
|
||||
var ctrl = this;
|
||||
|
||||
ctrl.model = containersModel;
|
||||
|
||||
ctrl.containerURL = containerRoute + $routeParams.containerName + '/';
|
||||
if (angular.isDefined($routeParams.folder)) {
|
||||
ctrl.currentURL = ctrl.containerURL + $routeParams.folder + '/';
|
||||
} else {
|
||||
ctrl.currentURL = ctrl.containerURL;
|
||||
}
|
||||
|
||||
ctrl.model.selectContainer($routeParams.containerName, $routeParams.folder);
|
||||
}
|
||||
})();
|
@ -0,0 +1,65 @@
|
||||
/**
|
||||
* (c) Copyright 2016 Rackspace US, Inc
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License. You may obtain
|
||||
* a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
describe('horizon.dashboard.project.containers objects controller', function() {
|
||||
var $routeParams, controller, model;
|
||||
|
||||
beforeEach(module('horizon.framework'));
|
||||
beforeEach(module('horizon.app.core.openstack-service-api'));
|
||||
|
||||
beforeEach(module('horizon.dashboard.project.containers', function before($provide) {
|
||||
$routeParams = {};
|
||||
$provide.value('$routeParams', $routeParams);
|
||||
}));
|
||||
|
||||
beforeEach(inject(function ($injector) {
|
||||
controller = $injector.get('$controller');
|
||||
model = $injector.get('horizon.dashboard.project.containers.containers-model');
|
||||
}));
|
||||
|
||||
function createController() {
|
||||
return controller('horizon.dashboard.project.containers.ObjectsController', {
|
||||
'horizon.dashboard.project.containers.containerRoute': 'eggs/'
|
||||
});
|
||||
}
|
||||
|
||||
it('should load contents', function test () {
|
||||
spyOn(model, 'selectContainer');
|
||||
$routeParams.containerName = 'spam';
|
||||
var ctrl = createController();
|
||||
|
||||
expect(ctrl.containerURL).toEqual('eggs/spam/');
|
||||
expect(ctrl.currentURL).toEqual('eggs/spam/');
|
||||
|
||||
expect(model.selectContainer).toHaveBeenCalledWith('spam', undefined);
|
||||
});
|
||||
|
||||
it('should handle subfolders', function test () {
|
||||
spyOn(model, 'selectContainer');
|
||||
$routeParams.containerName = 'spam';
|
||||
$routeParams.folder = 'ham';
|
||||
var ctrl = createController();
|
||||
|
||||
expect(ctrl.containerURL).toEqual('eggs/spam/');
|
||||
expect(ctrl.currentURL).toEqual('eggs/spam/ham/');
|
||||
|
||||
expect(model.selectContainer).toHaveBeenCalledWith('spam', 'ham');
|
||||
});
|
||||
});
|
||||
})();
|
@ -0,0 +1,50 @@
|
||||
<table class="table hz-objects table-hover table-striped"
|
||||
ng-controller="horizon.dashboard.project.containers.ObjectsController as oc"
|
||||
st-table="displayContents" st-safe-src="oc.model.objects"
|
||||
hz-table default-sort="name">
|
||||
<thead>
|
||||
<tr class="page_title table_caption">
|
||||
<th colspan="4">
|
||||
<ol class="breadcrumb hz-object-path">
|
||||
<li class="h4">
|
||||
<a ng-href="{$ oc.containerURL $}">{$ oc.model.containerName $}</a>
|
||||
</li>
|
||||
<li ng-repeat="pf in oc.model.pseudo_folder_hierarchy track by $index" ng-class="{'active':$last}">
|
||||
<span>
|
||||
<a ng-href="{$ oc.containerURL + oc.model.pseudo_folder_hierarchy.slice(0, $index + 1).join(oc.model.DELIMETER) $}"
|
||||
ng-if="!$last">{$ pf $}</a>
|
||||
<span ng-if="$last">{$ pf $}</span>
|
||||
</span>
|
||||
</li>
|
||||
</ol>
|
||||
</th>
|
||||
</tr>
|
||||
|
||||
<tr class="table_caption">
|
||||
<th colspan="4" class="search-header">
|
||||
<hz-search-bar group-classes="input-group-sm"
|
||||
icon-classes="fa-search" input-classes="form-control" placeholder="Filter">
|
||||
</hz-search-bar>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr ng-repeat="file in displayContents track by $index">
|
||||
<td>
|
||||
<a ng-if="file.is_subdir" ng-href="{$ oc.currentURL + file.name $}">{$ file.name $}</a>
|
||||
<span ng-if="file.is_object">{$ file.name $}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span ng-if="file.is_object">{$file.bytes | bytes$}</span>
|
||||
<span ng-if="file.is_subdir"><translate>folder</translate></span>
|
||||
</td>
|
||||
<td>
|
||||
</td>
|
||||
</tr>
|
||||
<tr hz-no-items items="displayContents">
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<tfoot hz-table-footer items="displayContents"></tfoot>
|
||||
</table>
|
@ -0,0 +1,7 @@
|
||||
<table class="table table-bordered tablestriped">
|
||||
<tbody>
|
||||
<tr class="odd empty">
|
||||
<td><translate>Select a container to browse.</translate></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
@ -25,6 +25,7 @@
|
||||
*/
|
||||
angular
|
||||
.module('horizon.dashboard.project', [
|
||||
'horizon.dashboard.project.containers',
|
||||
'horizon.dashboard.project.images',
|
||||
'horizon.dashboard.project.workflow'
|
||||
])
|
||||
|
@ -24,3 +24,7 @@ ADD_PANEL = ('openstack_dashboard.dashboards.project.'
|
||||
'ngcontainers.panel.NGContainers')
|
||||
|
||||
DISABLED = True
|
||||
|
||||
ADD_SCSS_FILES = [
|
||||
'dashboard/project/containers/_containers.scss',
|
||||
]
|
||||
|
@ -96,7 +96,8 @@
|
||||
'horizon.framework.util.tech-debt.helper-functions',
|
||||
'$cookieStore',
|
||||
'$http',
|
||||
'$cookies'
|
||||
'$cookies',
|
||||
'$route'
|
||||
];
|
||||
|
||||
function updateHorizon(
|
||||
@ -105,7 +106,8 @@
|
||||
hzUtils,
|
||||
$cookieStore,
|
||||
$http,
|
||||
$cookies
|
||||
$cookies,
|
||||
$route
|
||||
) {
|
||||
|
||||
$http.defaults.headers.post['X-CSRFToken'] = $cookies.csrftoken;
|
||||
@ -124,6 +126,11 @@
|
||||
gettextCatalog.setCurrentLanguage(horizon.languageCode);
|
||||
gettextCatalog.setStrings(horizon.languageCode, django.catalog);
|
||||
|
||||
// because of angular startup, and our use of ng-include with
|
||||
// embedded ng-view, we need to re-kick ngRoute after everything's
|
||||
// resolved
|
||||
$route.reload();
|
||||
|
||||
/*
|
||||
* cookies are updated at the end of current $eval, so for the horizon
|
||||
* namespace we need to wrap it in a $apply function.
|
||||
|
@ -4,5 +4,4 @@
|
||||
@import "components/forms";
|
||||
@import "components/navbar";
|
||||
@import "components/navs";
|
||||
@import "components/panels";
|
||||
@import "components/type";
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
@import "components/breadcrumb_header";
|
||||
@import "components/context_selection";
|
||||
@import "components/login";
|
||||
@import "components/messages";
|
||||
@import "components/navbar";
|
||||
@import "components/pie_charts";
|
||||
|
@ -1,3 +1,3 @@
|
||||
.panel {
|
||||
.login .panel {
|
||||
@include box-shadow(0 3px 7px rgba(0, 0, 0, 0.3));
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user