Browse Source

Initial ui cookiecutter commit

Change-Id: I1e2fb3ecf56d50bf6ba1bcdbdf62b724b84772a0
Kaitlin Farr 1 year ago
parent
commit
a2f556e3f5
66 changed files with 3575 additions and 0 deletions
  1. 14
    0
      CONTRIBUTING.rst
  2. 4
    0
      HACKING.rst
  3. 175
    0
      LICENSE
  4. 9
    0
      MANIFEST.in
  5. 64
    0
      README.rst
  6. 5
    0
      babel-django.cfg
  7. 14
    0
      babel-djangojs.cfg
  8. 0
    0
      castellan_ui/__init__.py
  9. 0
    0
      castellan_ui/api/__init__.py
  10. 131
    0
      castellan_ui/api/client.py
  11. 86
    0
      castellan_ui/api/rest_api.py
  12. 0
    0
      castellan_ui/content/__init__.py
  13. 0
    0
      castellan_ui/content/manages/__init__.py
  14. 23
    0
      castellan_ui/content/manages/panel.py
  15. 19
    0
      castellan_ui/content/manages/tests.py
  16. 20
    0
      castellan_ui/content/manages/urls.py
  17. 36
    0
      castellan_ui/enabled/_90_project_castellan_panelgroup.py
  18. 21
    0
      castellan_ui/enabled/_91_project_castellan_manages_panel.py
  19. 0
    0
      castellan_ui/enabled/__init__.py
  20. 151
    0
      castellan_ui/karma.conf.js
  21. 37
    0
      castellan_ui/static/dashboard/castellan/castellan.module.js
  22. 23
    0
      castellan_ui/static/dashboard/castellan/castellan.module.spec.js
  23. 8
    0
      castellan_ui/static/dashboard/castellan/castellan.scss
  24. 81
    0
      castellan_ui/static/dashboard/castellan/castellan.service.js
  25. 87
    0
      castellan_ui/static/dashboard/castellan/manages/actions/actions.module.js
  26. 103
    0
      castellan_ui/static/dashboard/castellan/manages/actions/create.service.js
  27. 156
    0
      castellan_ui/static/dashboard/castellan/manages/actions/delete.service.js
  28. 122
    0
      castellan_ui/static/dashboard/castellan/manages/actions/update.service.js
  29. 57
    0
      castellan_ui/static/dashboard/castellan/manages/details/details.module.js
  30. 6
    0
      castellan_ui/static/dashboard/castellan/manages/details/drawer.html
  31. 43
    0
      castellan_ui/static/dashboard/castellan/manages/details/overview.controller.js
  32. 16
    0
      castellan_ui/static/dashboard/castellan/manages/details/overview.html
  33. 166
    0
      castellan_ui/static/dashboard/castellan/manages/manages.module.js
  34. 23
    0
      castellan_ui/static/dashboard/castellan/manages/manages.module.spec.js
  35. 0
    0
      castellan_ui/static/dashboard/castellan/manages/manages.scss
  36. 62
    0
      castellan_ui/static/dashboard/castellan/manages/manages.service.js
  37. 51
    0
      castellan_ui/static/dashboard/castellan/manages/manages.service.spec.js
  38. 5
    0
      castellan_ui/static/dashboard/castellan/manages/panel.html
  39. 4
    0
      castellan_ui/static/dashboard/castellan/manages/workflow/info.help.html
  40. 62
    0
      castellan_ui/static/dashboard/castellan/manages/workflow/manage-model.js
  41. 6
    0
      castellan_ui/static/dashboard/castellan/manages/workflow/recipe.help.html
  42. 210
    0
      castellan_ui/static/dashboard/castellan/manages/workflow/workflow.service.js
  43. 0
    0
      castellan_ui/test/__init__.py
  44. 0
    0
      castellan_ui/test/integration_tests/__init__.py
  45. 37
    0
      castellan_ui/test/settings.py
  46. 14
    0
      castellan_ui/version.py
  47. 152
    0
      doc/Makefile
  48. 443
    0
      doc/source/conf.py
  49. 10
    0
      doc/source/configuration/index.rst
  50. 9
    0
      doc/source/contributor/api.rst
  51. 16
    0
      doc/source/contributor/index.rst
  52. 33
    0
      doc/source/index.rst
  53. 53
    0
      doc/source/install/index.rst
  54. 23
    0
      manage.py
  55. 32
    0
      package.json
  56. 0
    0
      releasenotes/notes/.placeholder
  57. 285
    0
      releasenotes/source/conf.py
  58. 8
    0
      releasenotes/source/index.rst
  59. 5
    0
      releasenotes/source/unreleased.rst
  60. 17
    0
      requirements.txt
  61. 29
    0
      setup.cfg
  62. 27
    0
      setup.py
  63. 28
    0
      test-requirements.txt
  64. 96
    0
      test-shim.js
  65. 88
    0
      tools/tox_install.sh
  66. 70
    0
      tox.ini

+ 14
- 0
CONTRIBUTING.rst View File

@@ -0,0 +1,14 @@
1
+If you would like to contribute to the development of OpenStack, you must
2
+follow the steps in this page:
3
+https://docs.openstack.org/infra/manual/developers.html
4
+
5
+If you already have a good understanding of how the system works and your
6
+OpenStack accounts are set up, you can skip to the development workflow
7
+section of this documentation to learn how changes to OpenStack should be
8
+submitted for review via the Gerrit tool:
9
+https://docs.openstack.org/infra/manual/developers.html#development-workflow
10
+
11
+Pull requests submitted through GitHub will be ignored.
12
+
13
+Bugs should be filed on Launchpad, not GitHub:
14
+https://bugs.launchpad.net/castellan-ui

+ 4
- 0
HACKING.rst View File

@@ -0,0 +1,4 @@
1
+castellan-ui Style Commandments
2
+===============================================
3
+
4
+Read the OpenStack Style Commandments https://docs.openstack.org/hacking/latest/

+ 175
- 0
LICENSE View File

@@ -0,0 +1,175 @@
1
+
2
+                                 Apache License
3
+                           Version 2.0, January 2004
4
+                        http://www.apache.org/licenses/
5
+
6
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+   1. Definitions.
9
+
10
+      "License" shall mean the terms and conditions for use, reproduction,
11
+      and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+      "Licensor" shall mean the copyright owner or entity authorized by
14
+      the copyright owner that is granting the License.
15
+
16
+      "Legal Entity" shall mean the union of the acting entity and all
17
+      other entities that control, are controlled by, or are under common
18
+      control with that entity. For the purposes of this definition,
19
+      "control" means (i) the power, direct or indirect, to cause the
20
+      direction or management of such entity, whether by contract or
21
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+      outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+      "You" (or "Your") shall mean an individual or Legal Entity
25
+      exercising permissions granted by this License.
26
+
27
+      "Source" form shall mean the preferred form for making modifications,
28
+      including but not limited to software source code, documentation
29
+      source, and configuration files.
30
+
31
+      "Object" form shall mean any form resulting from mechanical
32
+      transformation or translation of a Source form, including but
33
+      not limited to compiled object code, generated documentation,
34
+      and conversions to other media types.
35
+
36
+      "Work" shall mean the work of authorship, whether in Source or
37
+      Object form, made available under the License, as indicated by a
38
+      copyright notice that is included in or attached to the work
39
+      (an example is provided in the Appendix below).
40
+
41
+      "Derivative Works" shall mean any work, whether in Source or Object
42
+      form, that is based on (or derived from) the Work and for which the
43
+      editorial revisions, annotations, elaborations, or other modifications
44
+      represent, as a whole, an original work of authorship. For the purposes
45
+      of this License, Derivative Works shall not include works that remain
46
+      separable from, or merely link (or bind by name) to the interfaces of,
47
+      the Work and Derivative Works thereof.
48
+
49
+      "Contribution" shall mean any work of authorship, including
50
+      the original version of the Work and any modifications or additions
51
+      to that Work or Derivative Works thereof, that is intentionally
52
+      submitted to Licensor for inclusion in the Work by the copyright owner
53
+      or by an individual or Legal Entity authorized to submit on behalf of
54
+      the copyright owner. For the purposes of this definition, "submitted"
55
+      means any form of electronic, verbal, or written communication sent
56
+      to the Licensor or its representatives, including but not limited to
57
+      communication on electronic mailing lists, source code control systems,
58
+      and issue tracking systems that are managed by, or on behalf of, the
59
+      Licensor for the purpose of discussing and improving the Work, but
60
+      excluding communication that is conspicuously marked or otherwise
61
+      designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+      "Contributor" shall mean Licensor and any individual or Legal Entity
64
+      on behalf of whom a Contribution has been received by Licensor and
65
+      subsequently incorporated within the Work.
66
+
67
+   2. Grant of Copyright License. Subject to the terms and conditions of
68
+      this License, each Contributor hereby grants to You a perpetual,
69
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+      copyright license to reproduce, prepare Derivative Works of,
71
+      publicly display, publicly perform, sublicense, and distribute the
72
+      Work and such Derivative Works in Source or Object form.
73
+
74
+   3. Grant of Patent License. Subject to the terms and conditions of
75
+      this License, each Contributor hereby grants to You a perpetual,
76
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+      (except as stated in this section) patent license to make, have made,
78
+      use, offer to sell, sell, import, and otherwise transfer the Work,
79
+      where such license applies only to those patent claims licensable
80
+      by such Contributor that are necessarily infringed by their
81
+      Contribution(s) alone or by combination of their Contribution(s)
82
+      with the Work to which such Contribution(s) was submitted. If You
83
+      institute patent litigation against any entity (including a
84
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+      or a Contribution incorporated within the Work constitutes direct
86
+      or contributory patent infringement, then any patent licenses
87
+      granted to You under this License for that Work shall terminate
88
+      as of the date such litigation is filed.
89
+
90
+   4. Redistribution. You may reproduce and distribute copies of the
91
+      Work or Derivative Works thereof in any medium, with or without
92
+      modifications, and in Source or Object form, provided that You
93
+      meet the following conditions:
94
+
95
+      (a) You must give any other recipients of the Work or
96
+          Derivative Works a copy of this License; and
97
+
98
+      (b) You must cause any modified files to carry prominent notices
99
+          stating that You changed the files; and
100
+
101
+      (c) You must retain, in the Source form of any Derivative Works
102
+          that You distribute, all copyright, patent, trademark, and
103
+          attribution notices from the Source form of the Work,
104
+          excluding those notices that do not pertain to any part of
105
+          the Derivative Works; and
106
+
107
+      (d) If the Work includes a "NOTICE" text file as part of its
108
+          distribution, then any Derivative Works that You distribute must
109
+          include a readable copy of the attribution notices contained
110
+          within such NOTICE file, excluding those notices that do not
111
+          pertain to any part of the Derivative Works, in at least one
112
+          of the following places: within a NOTICE text file distributed
113
+          as part of the Derivative Works; within the Source form or
114
+          documentation, if provided along with the Derivative Works; or,
115
+          within a display generated by the Derivative Works, if and
116
+          wherever such third-party notices normally appear. The contents
117
+          of the NOTICE file are for informational purposes only and
118
+          do not modify the License. You may add Your own attribution
119
+          notices within Derivative Works that You distribute, alongside
120
+          or as an addendum to the NOTICE text from the Work, provided
121
+          that such additional attribution notices cannot be construed
122
+          as modifying the License.
123
+
124
+      You may add Your own copyright statement to Your modifications and
125
+      may provide additional or different license terms and conditions
126
+      for use, reproduction, or distribution of Your modifications, or
127
+      for any such Derivative Works as a whole, provided Your use,
128
+      reproduction, and distribution of the Work otherwise complies with
129
+      the conditions stated in this License.
130
+
131
+   5. Submission of Contributions. Unless You explicitly state otherwise,
132
+      any Contribution intentionally submitted for inclusion in the Work
133
+      by You to the Licensor shall be under the terms and conditions of
134
+      this License, without any additional terms or conditions.
135
+      Notwithstanding the above, nothing herein shall supersede or modify
136
+      the terms of any separate license agreement you may have executed
137
+      with Licensor regarding such Contributions.
138
+
139
+   6. Trademarks. This License does not grant permission to use the trade
140
+      names, trademarks, service marks, or product names of the Licensor,
141
+      except as required for reasonable and customary use in describing the
142
+      origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+   7. Disclaimer of Warranty. Unless required by applicable law or
145
+      agreed to in writing, Licensor provides the Work (and each
146
+      Contributor provides its Contributions) on an "AS IS" BASIS,
147
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+      implied, including, without limitation, any warranties or conditions
149
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+      PARTICULAR PURPOSE. You are solely responsible for determining the
151
+      appropriateness of using or redistributing the Work and assume any
152
+      risks associated with Your exercise of permissions under this License.
153
+
154
+   8. Limitation of Liability. In no event and under no legal theory,
155
+      whether in tort (including negligence), contract, or otherwise,
156
+      unless required by applicable law (such as deliberate and grossly
157
+      negligent acts) or agreed to in writing, shall any Contributor be
158
+      liable to You for damages, including any direct, indirect, special,
159
+      incidental, or consequential damages of any character arising as a
160
+      result of this License or out of the use or inability to use the
161
+      Work (including but not limited to damages for loss of goodwill,
162
+      work stoppage, computer failure or malfunction, or any and all
163
+      other commercial damages or losses), even if such Contributor
164
+      has been advised of the possibility of such damages.
165
+
166
+   9. Accepting Warranty or Additional Liability. While redistributing
167
+      the Work or Derivative Works thereof, You may choose to offer,
168
+      and charge a fee for, acceptance of support, warranty, indemnity,
169
+      or other liability obligations and/or rights consistent with this
170
+      License. However, in accepting such obligations, You may act only
171
+      on Your own behalf and on Your sole responsibility, not on behalf
172
+      of any other Contributor, and only if You agree to indemnify,
173
+      defend, and hold each Contributor harmless for any liability
174
+      incurred by, or claims asserted against, such Contributor by reason
175
+      of your accepting any such warranty or additional liability.

+ 9
- 0
MANIFEST.in View File

@@ -0,0 +1,9 @@
1
+include AUTHORS
2
+include ChangeLog
3
+exclude .gitignore
4
+exclude .gitreview
5
+include setup.py
6
+
7
+recursive-include castellan_ui *.js *.html *.scss
8
+
9
+global-exclude *.pyc

+ 64
- 0
README.rst View File

@@ -0,0 +1,64 @@
1
+===============================
2
+Castellan UI
3
+===============================
4
+
5
+Generic Key Manager interface UI plugin for Horizon
6
+
7
+* Free software: Apache license
8
+* Source: http://git.openstack.org/cgit/openstack/castellan-ui
9
+* Bugs: http://bugs.launchpad.net/castellan-ui
10
+
11
+Features
12
+--------
13
+
14
+* TODO
15
+
16
+Enabling in DevStack
17
+--------------------
18
+
19
+Add this repo as an external repository into your ``local.conf`` file::
20
+
21
+    [[local|localrc]]
22
+    enable_plugin castellan_ui https://github.com/openstack/castellan-ui
23
+
24
+Manual Installation
25
+-------------------
26
+
27
+Begin by cloning the Horizon and Castellan UI repositories::
28
+
29
+    git clone https://github.com/openstack/horizon
30
+    git clone https://github.com/openstack/castellan-ui
31
+
32
+Create a virtual environment and install Horizon dependencies::
33
+
34
+    cd horizon
35
+    python tools/install_venv.py
36
+
37
+Set up your ``local_settings.py`` file::
38
+
39
+    cp openstack_dashboard/local/local_settings.py.example openstack_dashboard/local/local_settings.py
40
+
41
+Open up the copied ``local_settings.py`` file in your preferred text
42
+editor. You will want to customize several settings:
43
+
44
+-  ``OPENSTACK_HOST`` should be configured with the hostname of your
45
+   OpenStack server. Verify that the ``OPENSTACK_KEYSTONE_URL`` and
46
+   ``OPENSTACK_KEYSTONE_DEFAULT_ROLE`` settings are correct for your
47
+   environment. (They should be correct unless you modified your
48
+   OpenStack server to change them.)
49
+
50
+Install Castellan UI with all dependencies in your virtual environment::
51
+
52
+    tools/with_venv.sh pip install -e ../castellan-ui/
53
+
54
+And enable it in Horizon::
55
+
56
+    ln -s ../castellan-ui/castellan_ui/enabled/_90_project_castellan_panelgroup.py openstack_dashboard/local/enabled
57
+    ln -s ../castellan-ui/castellan_ui/enabled/_91_project_castellan_manages_panel.py openstack_dashboard/local/enabled
58
+
59
+To run horizon with the newly enabled Castellan UI plugin run::
60
+
61
+    ./run_tests.sh --runserver 0.0.0.0:8080
62
+
63
+to have the application start on port 8080 and the horizon dashboard will be
64
+available in your browser at http://localhost:8080/

+ 5
- 0
babel-django.cfg View File

@@ -0,0 +1,5 @@
1
+[extractors]
2
+django = django_babel.extract:extract_django
3
+
4
+[python: **.py]
5
+[django: templates/**.html]

+ 14
- 0
babel-djangojs.cfg View File

@@ -0,0 +1,14 @@
1
+[extractors]
2
+# We use a custom extractor to find translatable strings in AngularJS
3
+# templates. The extractor is included in horizon.utils for now.
4
+# See http://babel.pocoo.org/docs/messages/#referencing-extraction-methods for
5
+# details on how this works.
6
+angular = horizon.utils.babel_extract_angular:extract_angular
7
+
8
+[javascript: **.js]
9
+
10
+# We need to look into all static folders for HTML files.
11
+# The **/static ensures that we also search within
12
+# /openstack_dashboard/dashboards/XYZ/static which will ensure
13
+# that plugins are also translated.
14
+[angular: **/static/**.html]

+ 0
- 0
castellan_ui/__init__.py View File


+ 0
- 0
castellan_ui/api/__init__.py View File


+ 131
- 0
castellan_ui/api/client.py View File

@@ -0,0 +1,131 @@
1
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
2
+#    not use this file except in compliance with the License. You may obtain
3
+#    a copy of the License at
4
+#
5
+#         http://www.apache.org/licenses/LICENSE-2.0
6
+#
7
+#    Unless required by applicable law or agreed to in writing, software
8
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10
+#    License for the specific language governing permissions and limitations
11
+#    under the License.
12
+
13
+
14
+from __future__ import absolute_import
15
+
16
+import logging
17
+
18
+from castellan import key_manager
19
+
20
+from horizon import exceptions
21
+from horizon.utils.memoized import memoized
22
+from openstack_dashboard.api import base
23
+
24
+# for stab, should remove when use CLI API
25
+import copy
26
+from datetime import datetime
27
+import uuid
28
+
29
+
30
+LOG = logging.getLogger(__name__)
31
+
32
+ATTRIBUTES = ['name', 'description', 'enabled', 'size', 'temperature',
33
+              'base', 'flavor', 'topping']
34
+
35
+STUB_DATA = {}
36
+
37
+
38
+# for stab, should be removed when use CLI API
39
+class StubResponse(object):
40
+
41
+    def __init__(self, info):
42
+        self._info = info
43
+
44
+    def __repr__(self):
45
+        reprkeys = sorted(k for k in self.__dict__.keys() if k[0] != '_')
46
+        info = ", ".join("%s=%s" % (k, getattr(self, k)) for k in reprkeys)
47
+        return "<%s %s>" % (self.__class__.__name__, info)
48
+
49
+    def to_dict(self):
50
+        return copy.deepcopy(self._info)
51
+
52
+
53
+@memoized
54
+def apiclient(request):
55
+    api_url = ""
56
+
57
+    try:
58
+        api_url = base.url_for(request, 'manage')
59
+    except exceptions.ServiceCatalogException:
60
+        LOG.debug('No Manage Management service is configured.')
61
+        return None
62
+
63
+    LOG.debug('castellan connection created using the token "%s" and url'
64
+              '"%s"' % (request.user.token.id, api_url))
65
+    c = key_manager.API()
66
+    return c
67
+
68
+
69
+def manage_create(request, **kwargs):
70
+    args = {}
71
+    for (key, value) in kwargs.items():
72
+        if key in ATTRIBUTES:
73
+            args[str(key)] = value
74
+        else:
75
+            raise exceptions.BadRequest(
76
+                "Key must be in %s" % ",".join(ATTRIBUTES))
77
+    # created = apiclient(request).manages.create(**args)
78
+
79
+    # create dummy response
80
+    args["uuid"] = uuid.uuid1().hex
81
+    args["created_at"] = datetime.now().isoformat()
82
+    created = StubResponse(args)
83
+    for k in args:
84
+        setattr(created, k, args[k])
85
+    STUB_DATA[created.uuid] = created
86
+
87
+    return created
88
+
89
+
90
+def manage_update(request, id, **kwargs):
91
+    args = {}
92
+    for (key, value) in kwargs.items():
93
+        if key in ATTRIBUTES:
94
+            args[str(key)] = value
95
+        else:
96
+            raise exceptions.BadRequest(
97
+                "Key must be in %s" % ",".join(ATTRIBUTES))
98
+    # updated = apiclient(request).manage.update(id, **args)
99
+
100
+    # update dummy response
101
+    args["uuid"] = id
102
+    args["updated_at"] = datetime.now().isoformat()
103
+    updated = StubResponse(args)
104
+    for k in args:
105
+        setattr(updated, k, args[k])
106
+    STUB_DATA[updated.uuid] = updated
107
+
108
+    return updated
109
+
110
+
111
+def manage_delete(request, id):
112
+    # deleted = apiclient(request).manages.delete(id)
113
+    deleted = STUB_DATA.pop(id)
114
+
115
+    return deleted
116
+
117
+
118
+def manage_list(
119
+        request, limit=None, marker=None, sort_key=None,
120
+        sort_dir=None, detail=True):
121
+
122
+    # list = apiclient(request).Manages.list(limit, marker, sort_key,
123
+    #                                             sort_dir, detail)
124
+    list = [STUB_DATA[data] for data in STUB_DATA]
125
+    return list
126
+
127
+
128
+def manage_show(request, id):
129
+    # show = apiclient(request).manages.get(id)
130
+    show = STUB_DATA.get(id)
131
+    return show

+ 86
- 0
castellan_ui/api/rest_api.py View File

@@ -0,0 +1,86 @@
1
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
2
+#    not use this file except in compliance with the License. You may obtain
3
+#    a copy of the License at
4
+#
5
+#         http://www.apache.org/licenses/LICENSE-2.0
6
+#
7
+#    Unless required by applicable law or agreed to in writing, software
8
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10
+#    License for the specific language governing permissions and limitations
11
+#    under the License.
12
+
13
+from django.views import generic
14
+
15
+from castellan_ui.api import client
16
+
17
+from openstack_dashboard.api.rest import urls
18
+from openstack_dashboard.api.rest import utils as rest_utils
19
+
20
+
21
+def change_to_id(obj):
22
+    """Change key named 'uuid' to 'id'
23
+
24
+    API returns objects with a field called 'uuid' many of Horizons
25
+    directives however expect objects to have a field called 'id'.
26
+    """
27
+    obj['id'] = obj.pop('uuid')
28
+    return obj
29
+
30
+
31
+@urls.register
32
+class Manage(generic.View):
33
+    """API for retrieving a single Manage"""
34
+    url_regex = r'castellan/manages/(?P<id>[^/]+)$'
35
+
36
+    @rest_utils.ajax()
37
+    def get(self, request, id):
38
+        """Get a specific manage"""
39
+        return change_to_id(client.manage_show(request, id).to_dict())
40
+
41
+    @rest_utils.ajax(data_required=True)
42
+    def post(self, request, id):
43
+        """Update a Manage.
44
+
45
+        Returns the updated Manage object on success.
46
+        """
47
+        manage = client.manage_update(request, id, **request.DATA)
48
+        return rest_utils.CreatedResponse(
49
+            '/api/castellan/manage/%s' % manage.uuid,
50
+            manage.to_dict())
51
+
52
+
53
+@urls.register
54
+class Manages(generic.View):
55
+    """API for Manages"""
56
+    url_regex = r'castellan/manages/$'
57
+
58
+    @rest_utils.ajax()
59
+    def get(self, request):
60
+        """Get a list of the Manages for a project.
61
+
62
+        The returned result is an object with property 'items' and each
63
+        item under this is a Manage.
64
+        """
65
+        result = client.manage_list(request)
66
+        return {'items': [change_to_id(n.to_dict()) for n in result]}
67
+
68
+    @rest_utils.ajax(data_required=True)
69
+    def delete(self, request):
70
+        """Delete one or more Manages by id.
71
+
72
+        Returns HTTP 204 (no content) on successful deletion.
73
+        """
74
+        for id in request.DATA:
75
+            client.manage_delete(request, id)
76
+
77
+    @rest_utils.ajax(data_required=True)
78
+    def put(self, request):
79
+        """Create a new Manage.
80
+
81
+        Returns the new Manage object on success.
82
+        """
83
+        manage = client.manage_create(request, **request.DATA)
84
+        return rest_utils.CreatedResponse(
85
+            '/api/castellan/manage/%s' % manage.uuid,
86
+            manage.to_dict())

+ 0
- 0
castellan_ui/content/__init__.py View File


+ 0
- 0
castellan_ui/content/manages/__init__.py View File


+ 23
- 0
castellan_ui/content/manages/panel.py View File

@@ -0,0 +1,23 @@
1
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
2
+#    not use this file except in compliance with the License. You may obtain
3
+#    a copy of the License at
4
+#
5
+#         http://www.apache.org/licenses/LICENSE-2.0
6
+#
7
+#    Unless required by applicable law or agreed to in writing, software
8
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10
+#    License for the specific language governing permissions and limitations
11
+#    under the License.
12
+
13
+from django.utils.translation import ugettext_lazy as _
14
+import horizon
15
+
16
+# This panel will be loaded from horizon, because specified in enabled file.
17
+# To register REST api, import below here.
18
+from castellan_ui.api import rest_api  # noqa: F401
19
+
20
+
21
+class Manages(horizon.Panel):
22
+    name = _("Manages")
23
+    slug = "manages"

+ 19
- 0
castellan_ui/content/manages/tests.py View File

@@ -0,0 +1,19 @@
1
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
2
+#    not use this file except in compliance with the License. You may obtain
3
+#    a copy of the License at
4
+#
5
+#         http://www.apache.org/licenses/LICENSE-2.0
6
+#
7
+#    Unless required by applicable law or agreed to in writing, software
8
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10
+#    License for the specific language governing permissions and limitations
11
+#    under the License.
12
+
13
+from openstack_dashboard.test import helpers as test
14
+
15
+
16
+class ManagesTests(test.TestCase):
17
+    # Unit tests for manage.
18
+    def test_me(self):
19
+        self.assertTrue(1 + 1 == 2)

+ 20
- 0
castellan_ui/content/manages/urls.py View File

@@ -0,0 +1,20 @@
1
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
2
+#    not use this file except in compliance with the License. You may obtain
3
+#    a copy of the License at
4
+#
5
+#         http://www.apache.org/licenses/LICENSE-2.0
6
+#
7
+#    Unless required by applicable law or agreed to in writing, software
8
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10
+#    License for the specific language governing permissions and limitations
11
+#    under the License.
12
+
13
+from django.conf.urls import url
14
+from django.utils.translation import ugettext_lazy as _
15
+from horizon.browsers import views
16
+
17
+title = _("Manages")
18
+urlpatterns = [
19
+    url('', views.AngularIndexView.as_view(title=title), name='index'),
20
+]

+ 36
- 0
castellan_ui/enabled/_90_project_castellan_panelgroup.py View File

@@ -0,0 +1,36 @@
1
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
2
+#    not use this file except in compliance with the License. You may obtain
3
+#    a copy of the License at
4
+#
5
+#         http://www.apache.org/licenses/LICENSE-2.0
6
+#
7
+#    Unless required by applicable law or agreed to in writing, software
8
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10
+#    License for the specific language governing permissions and limitations
11
+#    under the License.
12
+
13
+from django.utils.translation import ugettext_lazy as _
14
+
15
+# The slug of the panel group to be added to HORIZON_CONFIG. Required.
16
+PANEL_GROUP = 'castellan'
17
+# The display name of the PANEL_GROUP. Required.
18
+PANEL_GROUP_NAME = _('Castellan')
19
+# The slug of the dashboard the PANEL_GROUP associated with. Required.
20
+PANEL_GROUP_DASHBOARD = 'project'
21
+
22
+ADD_INSTALLED_APPS = ['castellan_ui']
23
+
24
+ADD_ANGULAR_MODULES = [
25
+    'horizon.dashboard.castellan'
26
+]
27
+
28
+ADD_JS_FILES = [
29
+    'horizon/lib/angular/angular-route.js'
30
+]
31
+
32
+ADD_SCSS_FILES = [
33
+    'dashboard/castellan/castellan.scss'
34
+]
35
+
36
+AUTO_DISCOVER_STATIC_FILES = True

+ 21
- 0
castellan_ui/enabled/_91_project_castellan_manages_panel.py View File

@@ -0,0 +1,21 @@
1
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
2
+#    not use this file except in compliance with the License. You may obtain
3
+#    a copy of the License at
4
+#
5
+#         http://www.apache.org/licenses/LICENSE-2.0
6
+#
7
+#    Unless required by applicable law or agreed to in writing, software
8
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10
+#    License for the specific language governing permissions and limitations
11
+#    under the License.
12
+
13
+# The slug of the panel to be added to HORIZON_CONFIG. Required.
14
+PANEL = 'manages'
15
+# The slug of the panel group the PANEL is associated with.
16
+PANEL_GROUP = 'castellan'
17
+# The slug of the dashboard the PANEL associated with. Required.
18
+PANEL_DASHBOARD = 'project'
19
+
20
+# Python panel class of the PANEL to be added.
21
+ADD_PANEL = 'castellan_ui.content.manages.panel.Manages'

+ 0
- 0
castellan_ui/enabled/__init__.py View File


+ 151
- 0
castellan_ui/karma.conf.js View File

@@ -0,0 +1,151 @@
1
+/*
2
+ * Licensed under the Apache License, Version 2.0 (the 'License');
3
+ * you may not use this file except in compliance with the License.
4
+ * You may obtain a copy of the License at
5
+ *
6
+ *    http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Unless required by applicable law or agreed to in writing, software
9
+ * distributed under the License is distributed on an 'AS IS' BASIS,
10
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ * See the License for the specific language governing permissions and
12
+ * limitations under the License.
13
+ */
14
+
15
+'use strict';
16
+
17
+var fs = require('fs');
18
+var path = require('path');
19
+
20
+module.exports = function (config) {
21
+  // This tox venv is setup in the post-install npm step
22
+  var toxPath = '../.tox/py27/lib/python2.7/site-packages/';
23
+
24
+  config.set({
25
+    preprocessors: {
26
+      // Used to collect templates for preprocessing.
27
+      // NOTE: the templates must also be listed in the files section below.
28
+      './static/**/*.html': ['ng-html2js'],
29
+      // Used to indicate files requiring coverage reports.
30
+      './static/**/!(*.spec).js': ['coverage'],
31
+    },
32
+
33
+    // Sets up module to process templates.
34
+    ngHtml2JsPreprocessor: {
35
+      prependPrefix: '/',
36
+      moduleName: 'templates'
37
+    },
38
+
39
+    basePath: './',
40
+
41
+    // Contains both source and test files.
42
+    files: [
43
+      /*
44
+       * shim, partly stolen from /i18n/js/horizon/
45
+       * Contains expected items not provided elsewhere (dynamically by
46
+       * Django or via jasmine template.
47
+       */
48
+      '../test-shim.js',
49
+
50
+      // from jasmine.html
51
+      toxPath + 'xstatic/pkg/jquery/data/jquery.js',
52
+      toxPath + 'xstatic/pkg/angular/data/angular.js',
53
+      toxPath + 'xstatic/pkg/angular/data/angular-route.js',
54
+      toxPath + 'xstatic/pkg/angular/data/angular-mocks.js',
55
+      toxPath + 'xstatic/pkg/angular/data/angular-cookies.js',
56
+      toxPath + 'xstatic/pkg/angular_bootstrap/data/angular-bootstrap.js',
57
+      toxPath + 'xstatic/pkg/angular_gettext/data/angular-gettext.js',
58
+      toxPath + 'xstatic/pkg/angular/data/angular-sanitize.js',
59
+      toxPath + 'xstatic/pkg/d3/data/d3.js',
60
+      toxPath + 'xstatic/pkg/rickshaw/data/rickshaw.js',
61
+      toxPath + 'xstatic/pkg/angular_smart_table/data/smart-table.js',
62
+      toxPath + 'xstatic/pkg/angular_lrdragndrop/data/lrdragndrop.js',
63
+      toxPath + 'xstatic/pkg/spin/data/spin.js',
64
+      toxPath + 'xstatic/pkg/spin/data/spin.jquery.js',
65
+      toxPath + 'xstatic/pkg/tv4/data/tv4.js',
66
+      toxPath + 'xstatic/pkg/objectpath/data/ObjectPath.js',
67
+      toxPath + 'xstatic/pkg/angular_schema_form/data/schema-form.js',
68
+      toxPath + 'xstatic/pkg/angular_fileupload/data/ng-file-upload.js',
69
+
70
+
71
+      // TODO: These should be mocked.
72
+      toxPath + '/horizon/static/horizon/js/horizon.js',
73
+
74
+      /**
75
+       * Include framework source code from horizon that we need.
76
+       * Otherwise, karma will not be able to find them when testing.
77
+       * These files should be mocked in the foreseeable future.
78
+       */
79
+      toxPath + 'horizon/static/framework/**/*.module.js',
80
+      toxPath + 'horizon/static/framework/**/!(*.spec|*.mock).js',
81
+      toxPath + 'openstack_dashboard/static/**/*.module.js',
82
+      toxPath + 'openstack_dashboard/static/**/!(*.spec|*.mock).js',
83
+      toxPath + 'openstack_dashboard/dashboards/**/static/**/*.module.js',
84
+      toxPath + 'openstack_dashboard/dashboards/**/static/**/!(*.spec|*.mock).js',
85
+
86
+      /**
87
+       * First, list all the files that defines application's angular modules.
88
+       * Those files have extension of `.module.js`. The order among them is
89
+       * not significant.
90
+       */
91
+      './static/**/*.module.js',
92
+
93
+      /**
94
+       * Followed by other JavaScript files that defines angular providers
95
+       * on the modules defined in files listed above. And they are not mock
96
+       * files or spec files defined below. The order among them is not
97
+       * significant.
98
+       */
99
+      './static/**/!(*.spec|*.mock).js',
100
+
101
+      /**
102
+       * Then, list files for mocks with `mock.js` extension. The order
103
+       * among them should not be significant.
104
+       */
105
+      toxPath + 'openstack_dashboard/static/**/*.mock.js',
106
+
107
+      /**
108
+       * Finally, list files for spec with `spec.js` extension. The order
109
+       * among them should not be significant.
110
+       */
111
+      './static/**/*.spec.js',
112
+
113
+      /**
114
+       * Angular external templates
115
+       */
116
+      './static/**/*.html'
117
+    ],
118
+
119
+    autoWatch: true,
120
+
121
+    frameworks: ['jasmine'],
122
+
123
+    browsers: ['Chrome'],
124
+
125
+    browserNoActivityTimeout: 60000,
126
+
127
+    reporters: ['progress', 'coverage', 'threshold'],
128
+
129
+    plugins: [
130
+      'karma-chrome-launcher',
131
+      'karma-jasmine',
132
+      'karma-ng-html2js-preprocessor',
133
+      'karma-coverage',
134
+      'karma-threshold-reporter'
135
+    ],
136
+
137
+    // Places coverage report in HTML format in the subdirectory below.
138
+    coverageReporter: {
139
+      type: 'html',
140
+      dir: '../cover/karma/'
141
+    },
142
+
143
+    // Coverage threshold values.
144
+    thresholdReporter: {
145
+      statements: 10, // target 100
146
+      branches: 0, // target 100
147
+      functions: 10, // target 100
148
+      lines: 10 // target 100
149
+    }
150
+  });
151
+};

+ 37
- 0
castellan_ui/static/dashboard/castellan/castellan.module.js View File

@@ -0,0 +1,37 @@
1
+/**
2
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
3
+ * not use this file except in compliance with the License. You may obtain
4
+ * a copy of the License at
5
+ *
6
+ *    http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Unless required by applicable law or agreed to in writing, software
9
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11
+ * License for the specific language governing permissions and limitations
12
+ * under the License.
13
+ */
14
+
15
+(function() {
16
+  'use strict';
17
+
18
+  /**
19
+   * @ngdoc overview
20
+   * @name horizon.dashboard.castellan
21
+   * @description
22
+   * Dashboard module to host various castellan panels.
23
+   */
24
+  angular
25
+    .module('horizon.dashboard.castellan', [
26
+      'horizon.dashboard.castellan.manages',
27
+      'ngRoute'
28
+    ])
29
+    .config(config)
30
+
31
+  config.$inject = ['$provide', '$windowProvider', '$routeProvider'];
32
+
33
+  function config($provide, $windowProvider, $routeProvider) {
34
+    var path = $windowProvider.$get().STATIC_URL + 'dashboard/castellan/';
35
+    $provide.constant('horizon.dashboard.castellan.basePath', path);
36
+  }
37
+})();

+ 23
- 0
castellan_ui/static/dashboard/castellan/castellan.module.spec.js View File

@@ -0,0 +1,23 @@
1
+/**
2
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
3
+ * not use this file except in compliance with the License. You may obtain
4
+ * a copy of the License at
5
+ *
6
+ *    http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Unless required by applicable law or agreed to in writing, software
9
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11
+ * License for the specific language governing permissions and limitations
12
+ * under the License.
13
+ */
14
+(function() {
15
+  'use strict';
16
+
17
+  describe('horizon.dashboard.castellan', function() {
18
+    it('should exist', function() {
19
+      expect(angular.module('horizon.dashboard.castellan')).toBeDefined();
20
+    });
21
+  });
22
+
23
+})();

+ 8
- 0
castellan_ui/static/dashboard/castellan/castellan.scss View File

@@ -0,0 +1,8 @@
1
+@import "manages/manages";
2
+
3
+.batch-action {
4
+  float: right;
5
+  action-list {
6
+    padding-left: 0.3em;
7
+  }
8
+}

+ 81
- 0
castellan_ui/static/dashboard/castellan/castellan.service.js View File

@@ -0,0 +1,81 @@
1
+/**
2
+ * Licensed under the Apache License, Version 2.0 (the "License");
3
+ * you may not use this file except in compliance with the License.
4
+ * You may obtain a copy of the License at
5
+ *
6
+ *    http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Unless required by applicable law or agreed to in writing, software
9
+ * distributed under the License is distributed on an "AS IS" BASIS,
10
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ * See the License for the specific language governing permissions and
12
+ * limitations under the License.
13
+ */
14
+(function () {
15
+  'use strict';
16
+
17
+  angular
18
+    .module('horizon.app.core.openstack-service-api')
19
+    .factory('horizon.app.core.openstack-service-api.castellan', API);
20
+
21
+  API.$inject = [
22
+    'horizon.framework.util.http.service',
23
+    'horizon.framework.widgets.toast.service',
24
+    'horizon.framework.util.i18n.gettext'
25
+  ];
26
+
27
+  function API(apiService, toastService, gettext) {
28
+    var service = {
29
+      getManage: getManage,
30
+      getManages: getManages,
31
+      createManage: createManage,
32
+      updateManage: updateManage,
33
+      deleteManage: deleteManage,
34
+    };
35
+
36
+    return service;
37
+
38
+    ///////////////
39
+    // Manages //
40
+    ///////////////
41
+
42
+    function getManage(id) {
43
+      return apiService.get('/api/castellan/manages/' + id)
44
+        .error(function() {
45
+          var msg = gettext('Unable to retrieve the Manage with id: %(id)s.');
46
+          toastService.add('error', interpolate(msg, {id: id}, true));
47
+        });
48
+    }
49
+
50
+    function getManages() {
51
+      return apiService.get('/api/castellan/manages/')
52
+        .error(function() {
53
+          toastService.add('error', gettext('Unable to retrieve the Manages.'));
54
+        });
55
+    }
56
+
57
+    function createManage(params) {
58
+      return apiService.put('/api/castellan/manages/', params)
59
+        .error(function() {
60
+          var msg = gettext('Unable to create the Manage with name: %(name)s');
61
+          toastService.add('error', interpolate(msg, { name: params.name }, true));
62
+        });
63
+    }
64
+
65
+    function updateManage(id, params) {
66
+      return apiService.post('/api/castellan/manages/' + id, params)
67
+        .error(function() {
68
+          var msg = gettext('Unable to update the Manage with id: %(id)s');
69
+          toastService.add('error', interpolate(msg, { id: params.id }, true));
70
+        });
71
+    }
72
+
73
+    function deleteManage(id, suppressError) {
74
+      var promise = apiService.delete('/api/castellan/manages/', [id]);
75
+      return suppressError ? promise : promise.error(function() {
76
+        var msg = gettext('Unable to delete the Manage with id: %(id)s');
77
+        toastService.add('error', interpolate(msg, { id: id }, true));
78
+      });
79
+    }
80
+  }
81
+}());

+ 87
- 0
castellan_ui/static/dashboard/castellan/manages/actions/actions.module.js View File

@@ -0,0 +1,87 @@
1
+/**
2
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
3
+ * not use this file except in compliance with the License. You may obtain
4
+ * a copy of the License at
5
+ *
6
+ *    http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Unless required by applicable law or agreed to in writing, software
9
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11
+ * License for the specific language governing permissions and limitations
12
+ * under the License.
13
+ */
14
+
15
+(function() {
16
+  'use strict';
17
+
18
+  /**
19
+   * @ngdoc overview
20
+   * @ngname horizon.dashboard.castellan.manages.actions
21
+   *
22
+   * @description
23
+   * Provides all of the actions for Manages.
24
+   */
25
+  angular
26
+    .module('horizon.dashboard.castellan.manages.actions', [
27
+      'horizon.framework',
28
+      'horizon.dashboard.castellan'
29
+    ])
30
+    .run(registerManageActions);
31
+
32
+  registerManageActions.$inject = [
33
+    'horizon.framework.conf.resource-type-registry.service',
34
+    'horizon.framework.util.i18n.gettext',
35
+    'horizon.dashboard.castellan.manages.create.service',
36
+    'horizon.dashboard.castellan.manages.update.service',
37
+    'horizon.dashboard.castellan.manages.delete.service',
38
+    'horizon.dashboard.castellan.manages.resourceType'
39
+  ];
40
+
41
+  function registerManageActions (
42
+    registry,
43
+    gettext,
44
+    createManageService,
45
+    updateManageService,
46
+    deleteManageService,
47
+    resourceType
48
+  ) {
49
+    var managesResourceType = registry.getResourceType(resourceType);
50
+    managesResourceType.globalActions
51
+      .append({
52
+        id: 'createManageAction',
53
+        service: createManageService,
54
+        template: {
55
+          type: 'create',
56
+          text: gettext('Create Manage')
57
+        }
58
+      });
59
+
60
+    managesResourceType.batchActions
61
+      .append({
62
+        id: 'batchDeleteManageAction',
63
+        service: deleteManageService,
64
+        template: {
65
+          type: 'delete-selected',
66
+          text: gettext('Delete Manages')
67
+        }
68
+      });
69
+
70
+    managesResourceType.itemActions
71
+      .append({
72
+        id: 'updateManageAction',
73
+        service: updateManageService,
74
+        template: {
75
+          text: gettext('Update Manage')
76
+        }
77
+      })
78
+      .append({
79
+        id: 'deleteManageAction',
80
+        service: deleteManageService,
81
+        template: {
82
+          type: 'delete',
83
+          text: gettext('Delete Manage')
84
+        }
85
+      });
86
+  }
87
+})();

+ 103
- 0
castellan_ui/static/dashboard/castellan/manages/actions/create.service.js View File

@@ -0,0 +1,103 @@
1
+/**
2
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
3
+ * not use this file except in compliance with the License. You may obtain
4
+ * a copy of the License at
5
+ *
6
+ *    http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Unless required by applicable law or agreed to in writing, software
9
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11
+ * License for the specific language governing permissions and limitations
12
+ * under the License.
13
+ */
14
+
15
+(function() {
16
+  'use strict';
17
+
18
+  /**
19
+   * @ngdoc overview
20
+   * @name horizon.dashboard.castellan.manages.create.service
21
+   * @description Service for the manage create modal
22
+   */
23
+  angular
24
+    .module('horizon.dashboard.castellan.manages')
25
+    .factory('horizon.dashboard.castellan.manages.create.service', createService);
26
+
27
+  createService.$inject = [
28
+    '$location',
29
+    'horizon.app.core.openstack-service-api.castellan',
30
+    'horizon.app.core.openstack-service-api.policy',
31
+    'horizon.framework.util.actions.action-result.service',
32
+    'horizon.framework.util.i18n.gettext',
33
+    'horizon.framework.util.q.extensions',
34
+    'horizon.framework.widgets.toast.service',
35
+    'horizon.dashboard.castellan.manages.events',
36
+    'horizon.dashboard.castellan.manages.model',
37
+    'horizon.dashboard.castellan.manages.resourceType',
38
+    'horizon.dashboard.castellan.manages.workflow'
39
+  ];
40
+
41
+  function createService(
42
+    $location, api, policy, actionResult, gettext, $qExtensions,
43
+    toast, events, model, resourceType, workflow
44
+  ) {
45
+
46
+    var message = {
47
+      success: gettext('Manage %s was successfully created.')
48
+    };
49
+
50
+    var service = {
51
+      initAction: initAction,
52
+      perform: perform,
53
+      allowed: allowed
54
+    };
55
+
56
+    return service;
57
+
58
+    //////////////
59
+
60
+    // fixme: include this function in your service
61
+    // if you plan to emit events to the parent controller,
62
+    // otherwise remove it
63
+    function initAction() {
64
+    }
65
+
66
+    // fixme: if newScope is unnecessary, remove it
67
+    /* eslint-disable no-unused-vars */
68
+    function perform(selected, newScope) {
69
+      // modal title, buttons
70
+      var title, submitText, submitIcon;
71
+      title = gettext("Create Manage");
72
+      submitText = gettext("Create");
73
+      submitIcon = "fa fa-check";
74
+      model.init();
75
+
76
+      var result = workflow.init(title, submitText, submitIcon, model.spec);
77
+      return result.then(submit);
78
+    }
79
+
80
+    function allowed() {
81
+      return $qExtensions.booleanAsPromise(true);
82
+      // fixme: if you need to set policy, change as follow
83
+      //return policy.ifAllowed({ rules: [['manage', 'create_manage']] });
84
+    }
85
+
86
+    function submit() {
87
+      model.cleanProperties();
88
+      return api.createManage(model.spec).then(success);
89
+    }
90
+
91
+    function success(response) {
92
+      response.data.id = response.data.uuid;
93
+      toast.add('success', interpolate(message.success, [response.data.id]));
94
+      var result = actionResult.getActionResult()
95
+                   .created(resourceType, response.data.id);
96
+      if (result.result.failed.length === 0 && result.result.created.length > 0) {
97
+        $location.path('/project/manages');
98
+      } else {
99
+        return result.result;
100
+      }
101
+    }
102
+  }
103
+})();

+ 156
- 0
castellan_ui/static/dashboard/castellan/manages/actions/delete.service.js View File

@@ -0,0 +1,156 @@
1
+/**
2
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
3
+ * not use self file except in compliance with the License. You may obtain
4
+ * a copy of the License at
5
+ *
6
+ *    http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Unless required by applicable law or agreed to in writing, software
9
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11
+ * License for the specific language governing permissions and limitations
12
+ * under the License.
13
+ */
14
+
15
+(function() {
16
+  'use strict';
17
+
18
+  /**
19
+   * @ngDoc factory
20
+   * @name horizon.dashboard.castellan.manages.delete.service
21
+   * @Description
22
+   * Brings up the delete manages confirmation modal dialog.
23
+   * On submit, delete selected resources.
24
+   * On cancel, do nothing.
25
+   */
26
+  angular
27
+    .module('horizon.dashboard.castellan.manages')
28
+    .factory('horizon.dashboard.castellan.manages.delete.service', deleteService);
29
+
30
+  deleteService.$inject = [
31
+    '$location',
32
+    '$q',
33
+    'horizon.app.core.openstack-service-api.castellan',
34
+    'horizon.app.core.openstack-service-api.policy',
35
+    'horizon.framework.util.actions.action-result.service',
36
+    'horizon.framework.util.i18n.gettext',
37
+    'horizon.framework.util.q.extensions',
38
+    'horizon.framework.widgets.modal.deleteModalService',
39
+    'horizon.framework.widgets.toast.service',
40
+    'horizon.dashboard.castellan.manages.resourceType',
41
+    'horizon.dashboard.castellan.manages.events'
42
+  ];
43
+
44
+  function deleteService(
45
+    $location, $q, api, policy, actionResult, gettext, $qExtensions,
46
+    deleteModal, toast, resourceType, events
47
+  ) {
48
+    var scope;
49
+    var context = {
50
+      labels: null,
51
+      deleteEntity: deleteEntity,
52
+      successEvent: events.DELETE_SUCCESS
53
+    };
54
+    var service = {
55
+      initAction: initAction,
56
+      allowed: allowed,
57
+      perform: perform
58
+    };
59
+    var notAllowedMessage =
60
+      gettext("You are not allowed to delete manages: %s");
61
+
62
+    return service;
63
+
64
+    //////////////
65
+
66
+    // fixme: include this function in your service
67
+    // if you plan to emit events to the parent controller,
68
+    // otherwise remove it
69
+    function initAction() {
70
+    }
71
+
72
+    function allowed() {
73
+      return $qExtensions.booleanAsPromise(true);
74
+      // fixme: if you need to set policy, change as follow
75
+      //return policy.ifAllowed({ rules: [['manage', 'delete_manage']] });
76
+    }
77
+
78
+    // delete selected resource objects
79
+    function perform(selected, newScope) {
80
+      scope = newScope;
81
+      selected = angular.isArray(selected) ? selected : [selected];
82
+      context.labels = labelize(selected.length);
83
+      return $qExtensions.allSettled(selected.map(checkPermission)).then(afterCheck);
84
+    }
85
+
86
+    function labelize(count) {
87
+      return {
88
+        title: ngettext('Confirm Delete Manage',
89
+                        'Confirm Delete Manages', count),
90
+        /* eslint-disable max-len */
91
+        message: ngettext('You have selected "%s". Please confirm your selection. Deleted manage is not recoverable.',
92
+                          'You have selected "%s". Please confirm your selection. Deleted manages are not recoverable.', count),
93
+        /* eslint-enable max-len */
94
+        submit: ngettext('Delete Manage',
95
+                         'Delete Manages', count),
96
+        success: ngettext('Deleted Manage: %s.',
97
+                          'Deleted Manages: %s.', count),
98
+        error: ngettext('Unable to delete Manage: %s.',
99
+                        'Unable to delete Manages: %s.', count)
100
+      };
101
+    }
102
+
103
+    // for batch delete
104
+    function checkPermission(selected) {
105
+      return {promise: allowed(selected), context: selected};
106
+    }
107
+
108
+    // for batch delete
109
+    function afterCheck(result) {
110
+      var outcome = $q.reject();  // Reject the promise by default
111
+      if (result.fail.length > 0) {
112
+        toast.add('error', getMessage(notAllowedMessage, result.fail));
113
+        outcome = $q.reject(result.fail);
114
+      }
115
+      if (result.pass.length > 0) {
116
+        outcome = deleteModal.open(scope, result.pass.map(getEntity), context).then(createResult);
117
+      }
118
+      return outcome;
119
+    }
120
+
121
+    function createResult(deleteModalResult) {
122
+      // To make the result of this action generically useful, reformat the return
123
+      // from the deleteModal into a standard form
124
+      var result = actionResult.getActionResult();
125
+      deleteModalResult.pass.forEach(function markDeleted(item) {
126
+        result.deleted(resourceType, getEntity(item).id);
127
+      });
128
+      deleteModalResult.fail.forEach(function markFailed(item) {
129
+        result.failed(resourceType, getEntity(item).id);
130
+      });
131
+      if (result.result.failed.length === 0 && result.result.deleted.length > 0) {
132
+        $location.path('/project/manages');
133
+      } else {
134
+        return result.result;
135
+      }
136
+    }
137
+
138
+    function getMessage(message, entities) {
139
+      return interpolate(message, [entities.map(getName).join(", ")]);
140
+    }
141
+
142
+    function getName(result) {
143
+      return getEntity(result).name;
144
+    }
145
+
146
+    // for batch delete
147
+    function getEntity(result) {
148
+      return result.context;
149
+    }
150
+
151
+    // call delete REST API
152
+    function deleteEntity(id) {
153
+      return api.deleteManage(id, true);
154
+    }
155
+  }
156
+})();

+ 122
- 0
castellan_ui/static/dashboard/castellan/manages/actions/update.service.js View File

@@ -0,0 +1,122 @@
1
+/**
2
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
3
+ * not use this file except in compliance with the License. You may obtain
4
+ * a copy of the License at
5
+ *
6
+ *    http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Unless required by applicable law or agreed to in writing, software
9
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11
+ * License for the specific language governing permissions and limitations
12
+ * under the License.
13
+ */
14
+
15
+(function() {
16
+  'use strict';
17
+
18
+  /**
19
+   * @ngdoc overview
20
+   * @name horizon.dashboard.castellan.manages.update.service
21
+   * @description Service for the manage update modal
22
+   */
23
+  angular
24
+    .module('horizon.dashboard.castellan.manages')
25
+    .factory('horizon.dashboard.castellan.manages.update.service', updateService);
26
+
27
+  updateService.$inject = [
28
+    '$location',
29
+    'horizon.app.core.openstack-service-api.castellan',
30
+    'horizon.app.core.openstack-service-api.policy',
31
+    'horizon.framework.util.actions.action-result.service',
32
+    'horizon.framework.util.i18n.gettext',
33
+    'horizon.framework.util.q.extensions',
34
+    'horizon.framework.widgets.toast.service',
35
+    'horizon.dashboard.castellan.manages.events',
36
+    'horizon.dashboard.castellan.manages.model',
37
+    'horizon.dashboard.castellan.manages.resourceType',
38
+    'horizon.dashboard.castellan.manages.workflow'
39
+  ];
40
+
41
+  function updateService(
42
+    $location, api, policy, actionResult, gettext, $qExtensions,
43
+    toast, events, model, resourceType, workflow
44
+  ) {
45
+
46
+    var message = {
47
+      success: gettext('Manage %s was successfully updated.')
48
+    };
49
+
50
+    var service = {
51
+      initAction: initAction,
52
+      perform: perform,
53
+      allowed: allowed
54
+    };
55
+
56
+    var id;
57
+
58
+    return service;
59
+
60
+    //////////////
61
+
62
+    // fixme: include this function in your service
63
+    // if you plan to emit events to the parent controller,
64
+    // otherwise remove it
65
+    function initAction() {
66
+    }
67
+
68
+    // fixme: if newScope is unnecessary, remove it
69
+    /* eslint-disable no-unused-vars */
70
+    function perform(selected, newScope) {
71
+      // modal title, buttons
72
+      var title, submitText, submitIcon;
73
+      title = gettext("Update Manage");
74
+      submitText = gettext("Update");
75
+      submitIcon = "fa fa-check";
76
+      model.init();
77
+
78
+      // load current data
79
+      id = selected.id;
80
+      var deferred = api.getManage(id);
81
+      deferred.then(onLoad);
82
+
83
+      function onLoad(response) {
84
+        model.spec.id = response.data.id;
85
+        model.spec.name = response.data.name;
86
+        model.spec.description = response.data.description;
87
+        model.spec.enabled = response.data.enabled;
88
+        model.spec.size = response.data.size;
89
+        model.spec.temperature = response.data.temperature;
90
+        model.spec.base = response.data.base;
91
+        model.spec.flavor = response.data.flavor;
92
+        model.spec.topping = response.data.topping;
93
+      }
94
+
95
+      var result = workflow.init(title, submitText, submitIcon, model.spec);
96
+      return result.then(submit);
97
+    }
98
+
99
+    function allowed() {
100
+      return $qExtensions.booleanAsPromise(true);
101
+      // fixme: if you need to set policy, change as follow
102
+      //return policy.ifAllowed({ rules: [['manage', 'update_manage']] });
103
+    }
104
+
105
+    function submit() {
106
+      model.cleanProperties();
107
+      return api.updateManage(id, model.spec).then(success);
108
+    }
109
+
110
+    function success(response) {
111
+      response.data.id = response.data.uuid;
112
+      toast.add('success', interpolate(message.success, [response.data.id]));
113
+      var result = actionResult.getActionResult()
114
+                   .updated(resourceType, response.data.id);
115
+      if (result.result.failed.length === 0 && result.result.updated.length > 0) {
116
+        $location.path('/project/manages');
117
+      } else {
118
+        return result.result;
119
+      }
120
+    }
121
+  }
122
+})();

+ 57
- 0
castellan_ui/static/dashboard/castellan/manages/details/details.module.js View File

@@ -0,0 +1,57 @@
1
+/**
2
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
3
+ * not use this file except in compliance with the License. You may obtain
4
+ * a copy of the License at
5
+ *
6
+ *    http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Unless required by applicable law or agreed to in writing, software
9
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11
+ * License for the specific language governing permissions and limitations
12
+ * under the License.
13
+ */
14
+
15
+(function() {
16
+  'use strict';
17
+
18
+  /**
19
+   * @ngdoc overview
20
+   * @ngname horizon.dashboard.castellan.manages.details
21
+   *
22
+   * @description
23
+   * Provides details features for Manage.
24
+   */
25
+  angular
26
+    .module('horizon.dashboard.castellan.manages.details', [
27
+      'horizon.app.core',
28
+      'horizon.framework.conf'
29
+    ])
30
+    .run(registerDetails);
31
+
32
+  registerDetails.$inject = [
33
+    'horizon.app.core.openstack-service-api.castellan',
34
+    'horizon.dashboard.castellan.manages.basePath',
35
+    'horizon.dashboard.castellan.manages.resourceType',
36
+    'horizon.framework.conf.resource-type-registry.service'
37
+  ];
38
+
39
+  function registerDetails(
40
+    api,
41
+    basePath,
42
+    resourceType,
43
+    registry
44
+  ) {
45
+    registry.getResourceType(resourceType)
46
+      .setLoadFunction(loadFunction)
47
+      .detailsViews.append({
48
+        id: 'manageDetailsOverview',
49
+        name: gettext('Overview'),
50
+        template: basePath + 'details/overview.html'
51
+      });
52
+
53
+    function loadFunction(identifier) {
54
+      return api.getManage(identifier);
55
+    }
56
+  }
57
+})();

+ 6
- 0
castellan_ui/static/dashboard/castellan/manages/details/drawer.html View File

@@ -0,0 +1,6 @@
1
+<hz-resource-property-list
2
+  resource-type-name="OS::Castellan::Manage"
3
+  item="item"
4
+  property-groups="[['id'],
5
+                    ['topping', 'created_at', 'updated_at']]">
6
+</hz-resource-property-list>

+ 43
- 0
castellan_ui/static/dashboard/castellan/manages/details/overview.controller.js View File

@@ -0,0 +1,43 @@
1
+/*
2
+ * Licensed under the Apache License, Version 2.0 (the 'License');
3
+ * you may not use this file except in compliance with the License.
4
+ * You may obtain a copy of the License at
5
+ *
6
+ *    http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Unless required by applicable law or agreed to in writing, software
9
+ * distributed under the License is distributed on an 'AS IS' BASIS,
10
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ * See the License for the specific language governing permissions and
12
+ * limitations under the License.
13
+ */
14
+(function() {
15
+  "use strict";
16
+
17
+  angular
18
+    .module('horizon.dashboard.castellan.manages')
19
+    .controller('horizon.dashboard.castellan.manages.OverviewController', controller);
20
+
21
+  controller.$inject = [
22
+    '$scope',
23
+    'horizon.dashboard.castellan.manages.resourceType',
24
+    'horizon.dashboard.castellan.manages.events',
25
+    'horizon.framework.conf.resource-type-registry.service'
26
+  ];
27
+
28
+  function controller(
29
+    $scope,
30
+    resourceType,
31
+    events,
32
+    registry
33
+  ) {
34
+    var ctrl = this;
35
+    ctrl.manage = {};
36
+
37
+    $scope.context.loadPromise.then(onGetManage);
38
+
39
+    function onGetManage(manage) {
40
+      ctrl.manage = manage.data;
41
+    }
42
+  }
43
+})();

+ 16
- 0
castellan_ui/static/dashboard/castellan/manages/details/overview.html View File

@@ -0,0 +1,16 @@
1
+<div ng-controller="horizon.dashboard.castellan.manages.OverviewController as ctrl">
2
+  <div class="row">
3
+    <div class="col-md-12 detail">
4
+      <h3 translate>Manage</h3>
5
+      <hr>
6
+      <hz-resource-property-list
7
+        resource-type-name="OS::Castellan::Manage"
8
+        cls="dl-horizontal"
9
+        item="ctrl.manage"
10
+        property-groups="[['name', 'description', 'enabled'],
11
+                          ['size', 'temperature', 'base', 'flavor', 'topping'],
12
+                          ['id', 'created_at', 'updated_at']]">
13
+      </hz-resource-property-list>
14
+    </div>
15
+  </div>
16
+</div>

+ 166
- 0
castellan_ui/static/dashboard/castellan/manages/manages.module.js View File

@@ -0,0 +1,166 @@
1
+/**
2
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
3
+ * not use this file except in compliance with the License. You may obtain
4
+ * a copy of the License at
5
+ *
6
+ *    http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Unless required by applicable law or agreed to in writing, software
9
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11
+ * License for the specific language governing permissions and limitations
12
+ * under the License.
13
+ */
14
+
15
+(function() {
16
+  'use strict';
17
+
18
+  /**
19
+   * @ngdoc overview
20
+   * @name horizon.dashboard.castellan.manages
21
+   * @ngModule
22
+   * @description
23
+   * Provides all the services and widgets require to display the Manage
24
+   * panel
25
+   */
26
+  angular
27
+    .module('horizon.dashboard.castellan.manages', [
28
+      'ngRoute',
29
+      'horizon.dashboard.castellan.manages.actions',
30
+      'horizon.dashboard.castellan.manages.details'
31
+    ])
32
+    .constant('horizon.dashboard.castellan.manages.events', events())
33
+    .constant('horizon.dashboard.castellan.manages.resourceType', 'OS::Castellan::Manage')
34
+    .run(run)
35
+    .config(config);
36
+
37
+  /**
38
+   * @ngdoc constant
39
+   * @name horizon.dashboard.castellan.manages.events
40
+   * @description A list of events used by Manage
41
+   */
42
+  function events() {
43
+    return {
44
+      CREATE_SUCCESS: 'horizon.dashboard.castellan.manages.CREATE_SUCCESS',
45
+      DELETE_SUCCESS: 'horizon.dashboard.castellan.manages.DELETE_SUCCESS'
46
+    };
47
+  }
48
+
49
+  run.$inject = [
50
+    'horizon.framework.conf.resource-type-registry.service',
51
+    'horizon.dashboard.castellan.manages.service',
52
+    'horizon.dashboard.castellan.manages.basePath',
53
+    'horizon.dashboard.castellan.manages.resourceType'
54
+  ];
55
+
56
+  function run(registry, service, basePath, resourceType) {
57
+    registry.getResourceType(resourceType)
58
+    .setNames(gettext('Manage'), gettext('Manages'))
59
+    // for detail summary view on table row 
60
+    .setSummaryTemplateUrl(basePath + 'details/drawer.html')
61
+    // for table row items and detail summary view.
62
+    .setProperties(properties())
63
+    .setListFunction(service.getPromise)
64
+    .tableColumns
65
+    .append({
66
+      id: 'name',
67
+      priority: 1,
68
+      sortDefault: true,
69
+      filters: ['noName'],
70
+      urlFunction: service.urlFunction
71
+    })
72
+    .append({
73
+      id: 'size',
74
+      priority: 1,
75
+      filters: ['noValue']
76
+    })
77
+    .append({
78
+      id: 'temperature',
79
+      priority: 1,
80
+      filters: ['noValue']
81
+    })
82
+    .append({
83
+      id: 'base',
84
+      priority: 1,
85
+      filters: ['noValue']
86
+    })
87
+    .append({
88
+      id: 'flavor',
89
+      priority: 1,
90
+      filters: ['noValue']
91
+    })
92
+    .append({
93
+      id: 'topping',
94
+      priority: 2,
95
+      filters: ['noValue']
96
+    })
97
+    .append({
98
+      id: 'created_at',
99
+      priority: 2
100
+    })
101
+    .append({
102
+      id: 'updated_at',
103
+      priority: 2
104
+    });
105
+    // for magic-search
106
+    registry.getResourceType(resourceType).filterFacets
107
+    .append({
108
+      'label': gettext('Name'),
109
+      'name': 'name',
110
+      'singleton': true
111
+    })
112
+    .append({
113
+      'label': gettext('Base'),
114
+      'name': 'base',
115
+      'singleton': true
116
+    })
117
+    .append({
118
+      'label': gettext('Flavor'),
119
+      'name': 'flavor',
120
+      'singleton': true
121
+    })
122
+    .append({
123
+      'label': gettext('ID'),
124
+      'name': 'id',
125
+      'singleton': true
126
+    });
127
+  }
128
+
129
+  function properties() {
130
+    return {
131
+      id: { label: gettext('ID'), filters: ['noValue'] },
132
+      name: { label: gettext('Name'), filters: ['noName'] },
133
+      description: { label: gettext('Description'), filters: ['noValue'] },
134
+      enabled: { label: gettext('Enabled'), filters: ['yesno'] },
135
+      size: { label: gettext('Size'), filters: ['noValue'] },
136
+      temperature: { label: gettext('Temperature'), filters: ['noValue'] },
137
+      base: { label: gettext('Base'), filters: ['noValue'] },
138
+      flavor: { label: gettext('Flavor'), filters: ['noValue'] },
139
+      topping: { label: gettext('Topping'), filters: ['noValue'] },
140
+      created_at: { label: gettext('Created'), filters: ['simpleDate', 'noValue'] },
141
+      updated_at: { label: gettext('Updated'), filters: ['simpleDate', 'noValue'] }
142
+    };
143
+  }
144
+
145
+  config.$inject = [
146
+    '$provide',
147
+    '$windowProvider',
148
+    '$routeProvider'
149
+  ];
150
+
151
+  /**
152
+   * @name config
153
+   * @param {Object} $provide
154
+   * @param {Object} $windowProvider
155
+   * @param {Object} $routeProvider
156
+   * @description Routes used by this module.
157
+   * @returns {undefined} Returns nothing
158
+   */
159
+  function config($provide, $windowProvider, $routeProvider) {
160
+    var path = $windowProvider.$get().STATIC_URL + 'dashboard/castellan/manages/';
161
+    $provide.constant('horizon.dashboard.castellan.manages.basePath', path);
162
+    $routeProvider.when('/project/manages', {
163
+      templateUrl: path + 'panel.html'
164
+    });
165
+  }
166
+})();

+ 23
- 0
castellan_ui/static/dashboard/castellan/manages/manages.module.spec.js View File

@@ -0,0 +1,23 @@
1
+/**
2
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
3
+ * not use this file except in compliance with the License. You may obtain
4
+ * a copy of the License at
5
+ *
6
+ *    http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Unless required by applicable law or agreed to in writing, software
9
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11
+ * License for the specific language governing permissions and limitations
12
+ * under the License.
13
+ */
14
+(function() {
15
+  'use strict';
16
+
17
+  describe('horizon.dashboard.castellan.manages', function() {
18
+    it('should exist', function() {
19
+      expect(angular.module('horizon.dashboard.castellan.manages')).toBeDefined();
20
+    });
21
+  });
22
+
23
+})();

+ 0
- 0
castellan_ui/static/dashboard/castellan/manages/manages.scss View File


+ 62
- 0
castellan_ui/static/dashboard/castellan/manages/manages.service.js View File

@@ -0,0 +1,62 @@
1
+/**
2
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
3
+ * not use this file except in compliance with the License. You may obtain
4
+ * a copy of the License at
5
+ *
6
+ *    http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Unless required by applicable law or agreed to in writing, software
9
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11
+ * License for the specific language governing permissions and limitations
12
+ * under the License.
13
+ */
14
+
15
+(function() {
16
+  "use strict";
17
+
18
+  angular.module('horizon.dashboard.castellan.manages')
19
+    .factory('horizon.dashboard.castellan.manages.service',
20
+      service);
21
+
22
+  service.$inject = [
23
+    '$filter',
24
+    'horizon.app.core.detailRoute',
25
+    'horizon.app.core.openstack-service-api.castellan'
26
+  ];
27
+
28
+  /*
29
+   * @ngdoc factory
30
+   * @name horizon.dashboard.castellan.manages.service
31
+   *
32
+   * @description
33
+   * This service provides functions that are used through the Manages
34
+   * features.  These are primarily used in the module registrations
35
+   * but do not need to be restricted to such use.  Each exposed function
36
+   * is documented below.
37
+   */
38
+  function service($filter, detailRoute, api) {
39
+    return {
40
+      getPromise: getPromise,
41
+      urlFunction: urlFunction
42
+    };
43
+
44
+    function getPromise(params) {
45
+      return api.getManages(params).then(modifyResponse);
46
+    }
47
+
48
+    function modifyResponse(response) {
49
+      return {data: {items: response.data.items.map(modifyItem)}};
50
+
51
+      function modifyItem(item) {
52
+        var timestamp = item.updated_at ? item.updated_at : item.created_at;
53
+        item.trackBy = item.id.concat(timestamp);
54
+        return item;
55
+      };
56
+    }
57
+
58
+    function urlFunction(item) {
59
+      return detailRoute + 'OS::Castellan::Manage/' + item.id;
60
+    }
61
+  }
62
+})();

+ 51
- 0
castellan_ui/static/dashboard/castellan/manages/manages.service.spec.js View File

@@ -0,0 +1,51 @@
1
+/**
2
+ * Licensed under the Apache License, Version 2.0 (the "License");
3
+ * you may not use this file except in compliance with the License.
4
+ * You may obtain a copy of the License at
5
+ *
6
+ *    http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Unless required by applicable law or agreed to in writing, software
9
+ * distributed under the License is distributed on an "AS IS" BASIS,
10
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ * See the License for the specific language governing permissions and
12
+ * limitations under the License.
13
+ */
14
+(function() {
15
+  "use strict";
16
+
17
+  describe('Manages service', function() {
18
+    var service;
19
+    beforeEach(module('horizon.dashboard.castellan.manages'));
20
+    beforeEach(inject(function($injector) {
21
+      service = $injector.get('horizon.dashboard.castellan.manages.service');
22
+    }));
23
+
24
+    describe('getPromise', function() {
25
+      it("provides a promise", inject(function($q, $injector, $timeout) {
26
+        var api = $injector.get('horizon.app.core.openstack-service-api.castellan');
27
+        var deferred = $q.defer();
28
+        spyOn(api, 'getManages').and.returnValue(deferred.promise);
29
+        var result = service.getPromise({});
30
+        deferred.resolve({
31
+          data:{
32
+            items: [{id: 123, name: 'resource1'}]
33
+          }
34
+        });
35
+        $timeout.flush();
36
+        expect(api.getManages).toHaveBeenCalled();
37
+        expect(result.$$state.value.data.items[0].name).toBe('resource1');
38
+      }));
39
+    });
40
+
41
+    describe('urlFunction', function() {
42
+      it("get url", inject(function() {
43
+        var detailRoute = $injector.get('horizon.app.core.detailRoute');
44
+        var result = service.urlFunction({id:"123abc"});
45
+        expect(result).toBe(detailRoute + "OS::Castellan::Manage/123abc");
46
+      }));
47
+    });
48
+
49
+  });
50
+
51
+})();

+ 5
- 0
castellan_ui/static/dashboard/castellan/manages/panel.html View File

@@ -0,0 +1,5 @@
1
+<hz-resource-panel resource-type-name="OS::Castellan::Manage">
2
+  <hz-resource-table resource-type-name="OS::Castellan::Manage"
3
+                     track-by="trackBy">
4
+  </hz-resource-table>
5
+</hz-resource-panel>

+ 4
- 0
castellan_ui/static/dashboard/castellan/manages/workflow/info.help.html View File

@@ -0,0 +1,4 @@
1
+<dl>
2
+  <dt translate>Manage Name</dt>
3
+  <dd translate>An arbitrary human-readable name</dd>
4
+</dl>

+ 62
- 0
castellan_ui/static/dashboard/castellan/manages/workflow/manage-model.js View File

@@ -0,0 +1,62 @@
1
+/**
2
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
3
+ * not use this file except in compliance with the License. You may obtain
4
+ * a copy of the License at
5
+ *
6
+ *    http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Unless required by applicable law or agreed to in writing, software
9
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11
+ * License for the specific language governing permissions and limitations
12
+ * under the License.
13
+ */
14
+
15
+(function() {
16
+  'use strict';
17
+
18
+  /**
19
+   * @ngdoc model
20
+   * @name horizon.dashboard.castellan.manages.model
21
+   * @description Service for the manage model
22
+   */
23
+  angular
24
+    .module('horizon.dashboard.castellan.manages')
25
+    .factory('horizon.dashboard.castellan.manages.model', model);
26
+
27
+  model.$inject = [
28
+  ];
29
+
30
+  function model() {
31
+    var model = {
32
+      // params
33
+      "spec": {},
34
+
35
+      // methods
36
+      "init": init,
37
+      "cleanProperties": cleanProperties
38
+    };
39
+
40
+    function init() {
41
+      // initialize model
42
+      model.spec = {
43
+        "id": "",
44
+        "name": "",  // text required
45
+        "description": "",  // textarea
46
+        "enabled": true,  // checkbox
47
+        "size": "M",  // radio
48
+        "temperature": "H",  // radio
49
+        "base": "",  // select
50
+        "flavor": "",  // select
51
+        "topping": ""  // checkboxes
52
+      };
53
+    }
54
+
55
+    function cleanProperties() {
56
+      delete model.spec.id;
57
+      delete model.spec.tabs;
58
+    }
59
+
60
+    return model;
61
+  }
62
+})();

+ 6
- 0
castellan_ui/static/dashboard/castellan/manages/workflow/recipe.help.html View File

@@ -0,0 +1,6 @@
1
+<dl>
2
+  <dt translate>Base</dt>
3
+  <dd translate>Choose base drink.</dd>
4
+  <dt translate>Other options</dt>
5
+  <dd translate>Choose favorite options.</dd>
6
+</dl>

+ 210
- 0
castellan_ui/static/dashboard/castellan/manages/workflow/workflow.service.js View File

@@ -0,0 +1,210 @@
1
+/**
2
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
3
+ * not use this file except in compliance with the License. You may obtain
4
+ * a copy of the License at
5
+ *
6
+ *    http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Unless required by applicable law or agreed to in writing, software
9
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11
+ * License for the specific language governing permissions and limitations
12
+ * under the License.
13
+ */
14
+
15
+(function() {
16
+  'use strict';
17
+
18
+  /**
19
+   * @ngdoc workflow
20
+   * @name horizon.dashboard.castellan.manages.workflow
21
+   * @description Service for the create/update workflow
22
+   */
23
+  angular
24
+    .module('horizon.dashboard.castellan.manages')
25
+    .factory('horizon.dashboard.castellan.manages.workflow', workflow);
26
+
27
+  workflow.$inject = [
28
+    'horizon.dashboard.castellan.basePath',
29
+    'horizon.framework.util.i18n.gettext',
30
+    'horizon.framework.widgets.form.ModalFormService'
31
+  ];
32
+
33
+  function workflow(basePath, gettext, modal) {
34
+    var workflow = {
35
+      init: init
36
+    };
37
+
38
+    function init(title, submitText, submitIcon, model) {
39
+      var schema, form;
40
+
41
+      // schema
42
+      schema = {
43
+        "type": "object",
44
+        "properties": {
45
+          "name": {
46
+            "title": gettext("Name"),
47
+            "type": "string"
48
+          },
49
+          "description": {
50
+            "title": gettext("Description"),
51
+            "type": "string"
52
+          },
53
+          "enabled": {
54
+            "title": gettext("Enabled"),
55
+            "type": "boolean",
56
+            "default": true
57
+          },
58
+          "size": {
59
+            "title": gettext("Size"),
60
+            "type": "string",
61
+            "default": "M"
62
+          },
63
+          "temperature": {
64
+            "title": gettext("Temperature"),
65
+            "type": "string",
66
+            "default": "H"
67
+          },
68
+          "base": {
69
+            "title": gettext("Base"),
70
+            "type": "string",
71
+            "default": ""
72
+          },
73
+          "flavor": {
74
+            "title": gettext("Flavor"),
75
+            "type": "string",
76
+            "default": ""
77
+          },
78
+          "topping": {
79
+            "title": gettext("Topping")
80
+          }
81
+        }
82
+      };
83
+
84
+      // form
85
+      form = [
86
+        {
87
+          "type": "tabs",
88
+          "tabs": [
89
+            {
90
+              "title": gettext("Info"),
91
+              "help": basePath + "manages/workflow/info.help.html",
92
+              "items": [
93
+                {
94
+                  "key": "name",
95
+                  "placeholder": gettext("Name of the manage."),
96
+                  "required": true
97
+                },
98
+                {
99
+                  "key": "description",
100
+                  "type": "textarea"
101
+                },
102
+                {
103
+                  "key": "enabled",
104
+                  "type": "checkbox"
105
+                }
106
+              ]
107
+            },
108
+            {
109
+              "title": gettext("Recipe"),
110
+              "help": basePath + "manages/workflow/recipe.help.html",
111
+              "items": [
112
+                {
113
+                  "key": "size",
114
+                  "type": "radiobuttons",
115
+                  "titleMap": [
116
+                    {"value": "S", "name": gettext("Small")},
117
+                    {"value": "M", "name": gettext("Medium")},
118
+                    {"value": "L", "name": gettext("Large")},
119
+                    {"value": "XL", "name": gettext("Extra Large")}
120
+                  ]
121
+                },
122
+                {
123
+                  "key": "temperature",
124
+                  "type": "radiobuttons",
125
+                  "titleMap": [
126
+                    {"value": "H", "name": gettext("Hot")},
127
+                    {"value": "I", "name": gettext("Ice")}
128
+                  ]
129
+                },
130
+                {
131
+                  "key": "base",
132
+                  "type": "select",
133
+                  "titleMap": [
134
+                    {"value": "", "name": gettext("Choose base.")},
135
+                    {
136
+                      "value": "blend",
137
+                      "name": gettext("House Blend"),
138
+                      "group": gettext("Coffee")
139
+                    },
140
+                    {
141
+                      "value": "mandheling",
142
+                      "name": gettext("Mandheling"),
143
+                      "group": gettext("Coffee")},
144
+                    {
145
+                      "value": "colombia",
146
+                      "name": gettext("Colombia"),
147
+                      "group": gettext("Coffee")
148
+                    },
149
+                    {
150
+                      "value": "espresso",
151
+                      "name": gettext("Espresso"),
152
+                      "group": gettext("Coffee")
153
+                    },
154
+                    {
155
+                      "value": "earl_gray",
156
+                      "name": gettext("Earl Gray"),
157
+                      "group": gettext("Tea")
158
+                    },
159
+                    {
160
+                      "value": "darjeeling",
161
+                      "name": gettext("Darjeeling"),
162
+                      "group": gettext("Tea")},
163
+                    {
164
+                      "value": "orange_pekoe",
165
+                      "name": gettext("Orange Pekoe"),
166
+                      "group": gettext("Tea")
167
+                    }
168
+                  ]
169
+                },
170
+                {
171
+                  "key": "flavor",
172
+                  "type": "select",
173
+                  "titleMap": [
174
+                    {"value": "", "name": gettext("Choose flavor.")},
175
+                    {"value": "chocolate", "name": gettext("Chocolate")},
176
+                    {"value": "mocha", "name": gettext("Mocha")},
177
+                    {"value": "strawberry", "name": gettext("Strawberry")},
178
+                    {"value": "blueberry", "name": gettext("Blueberry")},
179
+                    {"value": "raspberry", "name": gettext("Raspberry")}
180
+                  ]
181
+                },
182
+                {
183
+                  "key": "topping",
184
+                  "type": "checkboxes",
185
+                  "titleMap": [
186
+                    {"value": "clushed_nuts", "name": gettext("Clushed Nuts")},
187
+                    {"value": "whip_cream", "name": gettext("Whip Cream")},
188
+                    {"value": "mixed_serial", "name": gettext("Mixed Serial")}
189
+                  ]
190
+                }
191
+              ] // items
192
+            } // tab
193
+          ] // tabs
194
+        }
195
+      ]; // form
196
+
197
+      var config = {
198
+        "title": title,
199
+        "submitText": submitText,
200
+        "schema": schema,
201
+        "form": form,
202
+        "model": model
203
+      };
204
+
205
+      return modal.open(config);
206
+    }
207
+
208
+    return workflow;
209
+  }
210
+})();

+ 0
- 0
castellan_ui/test/__init__.py View File


+ 0
- 0
castellan_ui/test/integration_tests/__init__.py View File


+ 37
- 0
castellan_ui/test/settings.py View File

@@ -0,0 +1,37 @@
1
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
2
+#    not use this file except in compliance with the License. You may obtain
3
+#    a copy of the License at
4
+#
5
+#         http://www.apache.org/licenses/LICENSE-2.0
6
+#
7
+#    Unless required by applicable law or agreed to in writing, software
8
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10
+#    License for the specific language governing permissions and limitations
11
+#    under the License.
12
+
13
+# Default to Horizons test settings to avoid any missing keys
14
+from horizon.test.settings import *  # noqa: F403,H303
15
+from openstack_dashboard.test.settings import *  # noqa: F403,H303
16
+
17
+# pop these keys to avoid log warnings about deprecation
18
+# update_dashboards will populate them anyway
19
+HORIZON_CONFIG.pop('dashboards', None)
20
+HORIZON_CONFIG.pop('default_dashboard', None)
21
+
22
+# Update the dashboards with castellan_ui
23
+import castellan_ui.enabled
24
+import openstack_dashboard.enabled
25
+from openstack_dashboard.utils import settings
26
+
27
+settings.update_dashboards(
28
+    [
29
+        castellan_ui.enabled,
30
+        openstack_dashboard.enabled,
31
+    ],
32
+    HORIZON_CONFIG,
33
+    INSTALLED_APPS
34
+)
35
+
36
+# Ensure any duplicate apps are removed after the update_dashboards call
37
+INSTALLED_APPS = list(set(INSTALLED_APPS))

+ 14
- 0
castellan_ui/version.py View File

@@ -0,0 +1,14 @@
1
+#  Licensed under the Apache License, Version 2.0 (the "License"); you may
2
+#  not use this file except in compliance with the License. You may obtain
3
+#  a copy of the License at
4
+#
5
+#       http://www.apache.org/licenses/LICENSE-2.0
6
+#
7
+#  Unless required by applicable law or agreed to in writing, software
8
+#  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9
+#  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10
+#  License for the specific language governing permissions and limitations
11
+#  under the License.
12
+import pbr.version
13
+
14
+version_info = pbr.version.VersionInfo('castellan_ui')

+ 152
- 0
doc/Makefile View File

@@ -0,0 +1,152 @@
1
+# Makefile for Sphinx documentation
2
+
3
+# You can set these variables from the command line.
4
+SPHINXOPTS    =
5
+SPHINXBUILD   = sphinx-build
6
+PAPER         =
7
+BUILDDIR      = build
8
+
9
+# Internal variables.
10
+PAPEROPT_a4     = -D latex_paper_size=a4
11
+PAPEROPT_letter = -D latex_paper_size=letter
12
+ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
13
+# the i18n builder cannot share the environment and doctrees with the others
14
+I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
15
+
16
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
17
+
18
+help:
19
+	@echo "Please use \`make <target>' where <target> is one of"
20
+	@echo "  html       to make standalone HTML files"
21
+	@echo "  dirhtml    to make HTML files named index.html in directories"
22
+	@echo "  singlehtml to make a single large HTML file"
23
+	@echo "  pickle     to make pickle files"
24
+	@echo "  json       to make JSON files"
25
+	@echo "  htmlhelp   to make HTML files and a HTML help project"
26
+	@echo "  qthelp     to make HTML files and a qthelp project"
27
+	@echo "  devhelp    to make HTML files and a Devhelp project"
28
+	@echo "  epub       to make an epub"
29
+	@echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
30
+	@echo "  latexpdf   to make LaTeX files and run them through pdflatex"
31
+	@echo "  text       to make text files"
32
+	@echo "  man        to make manual pages"
33
+	@echo "  texinfo    to make Texinfo files"
34
+	@echo "  info       to make Texinfo files and run them through makeinfo"
35
+	@echo "  gettext    to make PO message catalogs"
36
+	@echo "  changes    to make an overview of all changed/added/deprecated items"
37
+	@echo "  linkcheck  to check all external links for integrity"
38
+	@echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
39
+
40
+clean:
41
+	-rm -rf $(BUILDDIR)/*
42
+
43
+html:
44
+	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
45
+	@echo
46
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
47
+
48
+dirhtml:
49
+	$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
50
+	@echo
51
+	@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
52
+
53
+singlehtml:
54
+	$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
55
+	@echo
56
+	@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
57
+
58
+pickle:
59
+	$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
60
+	@echo
61
+	@echo "Build finished; now you can process the pickle files."
62
+
63
+json:
64
+	$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
65
+	@echo
66
+	@echo "Build finished; now you can process the JSON files."
67
+
68
+htmlhelp:
69
+	$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
70
+	@echo
71
+	@echo "Build finished; now you can run HTML Help Workshop with the" \
72
+	      ".hhp project file in $(BUILDDIR)/htmlhelp."
73
+
74
+qthelp:
75
+	$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
76
+	@echo
77
+	@echo "Build finished; now you can run "qcollectiongenerator" with the" \
78
+	      ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
79
+	@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Castellan-UI.qhcp"
80
+	@echo "To view the help file:"
81
+	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Castellan-UI.qhc"
82
+
83
+devhelp:
84
+	$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
85
+	@echo
86
+	@echo "Build finished."
87
+	@echo "To view the help file:"
88
+	@echo "# mkdir -p $$HOME/.local/share/devhelp/Castellan-UI"
89
+	@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Castellan-UI"
90
+	@echo "# devhelp"
91
+
92
+epub:
93
+	$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
94
+	@echo
95
+	@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
96
+
97
+latex:
98
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
99
+	@echo
100
+	@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
101
+	@echo "Run \`make' in that directory to run these through (pdf)latex" \
102
+	      "(use \`make latexpdf' here to do that automatically)."
103
+
104
+latexpdf:
105
+	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
106
+	@echo "Running LaTeX files through pdflatex..."
107
+	$(MAKE) -C $(BUILDDIR)/latex all-pdf
108
+	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
109
+
110
+text:
111
+	$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
112
+	@echo
113
+	@echo "Build finished. The text files are in $(BUILDDIR)/text."
114
+
115
+man:
116
+	$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
117
+	@echo
118
+	@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
119
+
120
+texinfo:
121
+	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
122
+	@echo
123
+	@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
124
+	@echo "Run \`make' in that directory to run these through makeinfo" \
125
+	      "(use \`make info' here to do that automatically)."
126
+
127
+info:
128
+	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
129
+	@echo "Running Texinfo files through makeinfo..."
130
+	make -C $(BUILDDIR)/texinfo info
131
+	@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
132
+
133
+gettext:
134
+	$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
135
+	@echo
136
+	@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
137
+
138
+changes:
139
+	$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
140
+	@echo
141
+	@echo "The overview file is in $(BUILDDIR)/changes."
142
+
143
+linkcheck:
144
+	$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
145
+	@echo
146
+	@echo "Link check complete; look for any errors in the above output " \
147
+	      "or in $(BUILDDIR)/linkcheck/output.txt."
148
+
149
+doctest:
150
+	$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
151
+	@echo "Testing of doctests in the sources finished, look at the " \
152
+	      "results in $(BUILDDIR)/doctest/output.txt."

+ 443
- 0
doc/source/conf.py View File

@@ -0,0 +1,443 @@
1
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
2
+# not use this file except in compliance with the License. You may obtain
3
+# a copy of the License at
4
+#
5
+#      http://www.apache.org/licenses/LICENSE-2.0
6
+#
7
+# Unless required by applicable law or agreed to in writing, software
8
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10
+# License for the specific language governing permissions and limitations
11
+# under the License.
12
+#
13
+# Horizon documentation build configuration file, created by
14
+# sphinx-quickstart on Thu Oct 27 11:38:59 2011.
15
+#
16
+# This file is execfile()d with the current directory set to its
17
+# containing dir.
18
+#
19
+# Note that not all possible configuration values are present in this
20
+# autogenerated file.
21
+#
22
+# All configuration values have a default; values that are commented out
23
+# serve to show the default.
24
+
25
+from __future__ import print_function
26
+
27
+import os
28
+import sys
29
+
30
+import django
31
+
32
+BASE_DIR = os.path.dirname(os.path.abspath(__file__))
33
+ROOT = os.path.abspath(os.path.join(BASE_DIR, "..", ".."))
34
+
35
+sys.path.insert(0, ROOT)
36
+
37
+# This is required for ReadTheDocs.org, but isn't a bad idea anyway.
38
+os.environ.setdefault('DJANGO_SETTINGS_MODULE',
39
+                      'castellan_ui.test.settings')
40
+
41
+# Starting in Django 1.7, standalone scripts, such as a sphinx build
42
+# require that django.setup() be called first.
43
+# https://docs.djangoproject.com/en/1.8/releases/1.7/#standalone-scripts
44
+django.setup()
45
+
46
+from castellan_ui import version as ui_ver
47
+
48
+
49
+def write_autodoc_index():
50
+
51
+    def find_autodoc_modules(module_name, sourcedir):
52
+        """returns a list of modules in the SOURCE directory."""
53
+        modlist = []
54
+        os.chdir(os.path.join(sourcedir, module_name))
55
+        print("SEARCHING %s" % sourcedir)
56
+        for root, dirs, files in os.walk("."):
57
+            for filename in files:
58
+                if filename == 'tests.py':
59
+                    continue
60
+                if filename.endswith(".py"):
61
+                    # remove the pieces of the root
62
+                    elements = root.split(os.path.sep)
63
+                    # replace the leading "." with the module name
64
+                    elements[0] = module_name
65
+                    # and get the base module name
66
+                    base, extension = os.path.splitext(filename)
67
+                    if not (base == "__init__"):
68
+                        elements.append(base)
69
+                    result = ".".join(elements)
70
+                    # print result
71
+                    modlist.append(result)
72
+        return modlist
73
+
74
+    RSTDIR = os.path.abspath(os.path.join(BASE_DIR, "contributor/api"))
75
+    SRCS = [('castellan_ui', ROOT), ]
76
+
77
+    EXCLUDED_MODULES = ()
78
+    CURRENT_SOURCES = {}
79
+
80
+    if not(os.path.exists(RSTDIR)):
81
+        os.mkdir(RSTDIR)
82
+    CURRENT_SOURCES[RSTDIR] = ['autoindex.rst']
83
+
84
+    INDEXOUT = open(os.path.join(RSTDIR, "autoindex.rst"), "w")
85
+    INDEXOUT.write("""
86
+=================
87
+Source Code Index
88
+=================
89
+
90
+.. contents::
91
+   :depth: 1
92
+   :local:
93
+
94
+""")
95
+
96
+    for modulename, path in SRCS:
97
+        sys.stdout.write("Generating source documentation for %s\n" %
98
+                         modulename)
99
+        INDEXOUT.write("\n%s\n" % modulename.capitalize())
100
+        INDEXOUT.write("%s\n" % ("=" * len(modulename),))
101
+        INDEXOUT.write(".. toctree::\n")
102
+        INDEXOUT.write("   :maxdepth: 1\n")
103
+        INDEXOUT.write("\n")
104
+
105
+        MOD_DIR = os.path.join(RSTDIR, modulename)
106
+        CURRENT_SOURCES[MOD_DIR] = []
107
+        if not(os.path.exists(MOD_DIR)):
108
+            os.mkdir(MOD_DIR)
109
+        for module in find_autodoc_modules(modulename, path):
110
+            if any([module.startswith(exclude) for exclude
111
+                   in EXCLUDED_MODULES]):
112
+                print("Excluded module %s." % module)
113
+                continue
114
+            mod_path = os.path.join(path, *module.split("."))
115
+            generated_file = os.path.join(MOD_DIR, "%s.rst" % module)
116
+
117
+            INDEXOUT.write("   %s/%s\n" % (modulename, module))
118
+
119
+            # Find the __init__.py module if this is a directory
120
+            if os.path.isdir(mod_path):
121
+                source_file = ".".join((os.path.join(mod_path, "__init__"),
122
+                                        "py",))
123
+            else:
124
+                source_file = ".".join((os.path.join(mod_path), "py"))
125
+
126
+            CURRENT_SOURCES[MOD_DIR].append("%s.rst" % module)
127