├── .gitignore
├── README.md
├── composer.json
├── src
├── Module.php
├── assets
│ ├── BackendAsset.php
│ ├── BackendJsAsset.php
│ ├── ModalAsset.php
│ ├── ToolbarAsset.php
│ ├── backend-js
│ │ └── is-framed.js
│ ├── backend
│ │ ├── fonts
│ │ │ ├── glyphicons-halflings-regular.eot
│ │ │ ├── glyphicons-halflings-regular.svg
│ │ │ ├── glyphicons-halflings-regular.ttf
│ │ │ ├── glyphicons-halflings-regular.woff
│ │ │ └── glyphicons-halflings-regular.woff2
│ │ └── less
│ │ │ ├── backend.less
│ │ │ └── json-editor.less
│ ├── modal
│ │ ├── js
│ │ │ └── modal.js
│ │ └── less
│ │ │ └── widget.less
│ └── toolbar
│ │ ├── js
│ │ ├── check-frame.js
│ │ └── widget.js
│ │ └── less
│ │ └── widget.less
├── controllers
│ ├── CacheController.php
│ ├── ConfigController.php
│ ├── DefaultController.php
│ └── RbacController.php
├── interfaces
│ └── ContextMenuItemsInterface.php
├── migrations
│ ├── m160926_160610_settings.php
│ └── m181207_200300_settings.php
├── views
│ ├── config
│ │ ├── _controller.php
│ │ ├── _module.php
│ │ └── view.php
│ ├── default
│ │ └── index.php
│ ├── layouts
│ │ ├── _control-sidebar.php
│ │ ├── _sidebar.php
│ │ ├── box.php
│ │ ├── login.php
│ │ └── main.php
│ └── rbac
│ │ ├── index.twig
│ │ └── show-auth.php
└── widgets
│ ├── Modal.php
│ ├── Toolbar.php
│ └── views
│ ├── modal.twig
│ └── toolbar.twig
└── tests
├── .env
├── Dockerfile
├── docker-compose.yml
└── project
├── composer.json
├── composer.lock
└── config
└── test.php
/.gitignore:
--------------------------------------------------------------------------------
1 | tests/project/vendor
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Backend module for Yii 2.0 Framework
2 | ====================================
3 |
4 | [](https://packagist.org/packages/dmstr/yii2-backend-module)
5 | [](https://packagist.org/packages/dmstr/yii2-backend-module)
6 | [](https://packagist.org/packages/dmstr/yii2-backend-module)
7 |
8 |
9 | ### AdminLTE Dashboard
10 |
11 | 
12 |
13 | Installation
14 | ------------
15 |
16 | The preferred way to install this extension is through [composer](http://getcomposer.org/download/).
17 |
18 | ```
19 | composer require dmstr/yii2-backend-module
20 | ```
21 |
22 | - Requires `loveorigami/yii2-notification-wrapper`
23 |
24 | Usage
25 | -----
26 |
27 | Add module to application configuration
28 |
29 | ```
30 | 'backend' => [
31 | 'class' => 'dmstr\modules\backend\Module',
32 | 'layout' => '@backend/views/layouts/main',
33 | ],
34 | ```
35 |
36 | ### Minimalistic Login view from AdminLTE 2
37 |
38 | ```
39 | 'modules' => [
40 | 'user' => [
41 | 'controllerMap' => [
42 | 'security' => [
43 | 'class' => Da\User\Controller\SecurityController::class,
44 | 'layout' => '@backend/views/layouts/login'
45 | ],
46 | 'recovery' => [
47 | 'class' => Da\User\Controller\RecoveryController::class,
48 | 'layout' => '@backend/views/layouts/login'
49 | ],
50 | 'registration' => [
51 | 'class' => Da\User\Controller\RegistrationController::class,
52 | 'layout' => '@backend/views/layouts/login'
53 | ]
54 | ]
55 | ]
56 | ]
57 | ```
58 |
59 | ### Params
60 |
61 | - `context.menuItems` menu items to be shown, i.e. used by `dmstr/yii2-prototype-module`
62 |
63 | ### Settings
64 |
65 | *from `settings` module*
66 |
67 | - `backend.adminlte.skin` default `black-light`
68 | - `backend.adminlte.sidebar` default `sidebar-mini`
69 | - `backend.adminlte.navBarIcon` default `heart`
70 | - `frontend.backendWidget` default `modal`
71 | - `frontend.backendButtonsInModal` (experimental)
72 |
73 |
74 | ---
75 |
76 | ####  Built by [dmstr](http://diemeisterei.de)
77 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dmstr/yii2-backend-module",
3 | "description": "Admin Dashboard",
4 | "type": "yii2-extension",
5 | "keywords": ["yii2","extension"],
6 | "license": "BSD-3-Clause",
7 | "authors": [
8 | {
9 | "name": "Tobias Munk",
10 | "email": "tobias@diemeisterei.de"
11 | }
12 | ],
13 | "require": {
14 | "yiisoft/yii2": "2.*",
15 | "bower-asset/jquery-growl": "^1.3",
16 | "bower-asset/noty": "^2.3",
17 | "dmstr/yii2-cookie-button": "~0.2 || ^1.0.0",
18 | "dmstr/yii2-helpers": "~0.4 || ^1.0.1",
19 | "dmstr/yii2-web": "~0.3 || ^0.4.0 || ^1.0.0",
20 | "dmstr/yii2-adminlte-asset": "^2.5.0",
21 | "insolita/yii2-adminlte-widgets": "^1.1.4",
22 | "loveorigami/yii2-notification-wrapper": "^6.3",
23 | "rmrevin/yii2-fontawesome": "^2.17"
24 | },
25 | "suggest": {
26 | "codemix/yii2-localeurls": "Extended URL manager",
27 | "dmstr/yii2-pages-module": "Menu manager",
28 | "dmstr/yii2-prototype-module": "Content prototyping",
29 | "dmstr/lajax-yii2-translate-manager-addons": "Translating"
30 | },
31 | "autoload": {
32 | "psr-4": {
33 | "dmstr\\modules\\backend\\": "src"
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/Module.php:
--------------------------------------------------------------------------------
1 |
21 | */
22 | class Module extends \yii\base\Module
23 | {
24 | use AccessBehaviorTrait;
25 |
26 | /**
27 | * @var array Names of (auto-detected) modules which should not be show on dashboard
28 | */
29 | public $modulesDashboardBlacklist = [];
30 |
31 | public $rbacDiagramExcludeRoles = ['Master'];
32 |
33 | /**
34 | * @param $label
35 | *
36 | * @return mixed
37 | */
38 | public static function colorHash($label)
39 | {
40 | $colors = [
41 | InfoBox::TYPE_NAVY,
42 | InfoBox::TYPE_LBLUE,
43 | InfoBox::TYPE_BLUE,
44 | InfoBox::TYPE_AQUA,
45 | InfoBox::TYPE_PURPLE,
46 | InfoBox::TYPE_MAR,
47 | InfoBox::TYPE_TEAL,
48 | InfoBox::TYPE_OLIVE,
49 | ];
50 | /*$brightColors = [
51 | InfoBox::TYPE_RED,
52 | InfoBox::TYPE_GREEN,
53 | InfoBox::TYPE_YEL,
54 | InfoBox::TYPE_LIME,
55 | InfoBox::TYPE_ORANGE,
56 | InfoBox::TYPE_FUS,
57 | #InfoBox::TYPE_BLACK,
58 | #InfoBox::TYPE_GRAY,
59 | ];*/
60 |
61 | srand(crc32($label));
62 | $rand = array_rand($colors);
63 | return $colors[$rand];
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/src/assets/BackendAsset.php:
--------------------------------------------------------------------------------
1 | View::POS_BEGIN
27 | ];
28 | }
29 |
--------------------------------------------------------------------------------
/src/assets/ModalAsset.php:
--------------------------------------------------------------------------------
1 |
20 | */
21 | class ModalAsset extends AssetBundle
22 | {
23 | public $sourcePath = '@vendor/dmstr/yii2-backend-module/src/assets/modal';
24 |
25 | public $js = ['js/modal.js'];
26 |
27 | public $css = ['less/widget.less'];
28 |
29 | public $depends = [
30 | JqueryAsset::class,
31 | \rmrevin\yii\fontawesome\AssetBundle::class
32 | ];
33 | }
--------------------------------------------------------------------------------
/src/assets/ToolbarAsset.php:
--------------------------------------------------------------------------------
1 |
20 | */
21 | class ToolbarAsset extends AssetBundle
22 | {
23 | public $sourcePath = '@vendor/dmstr/yii2-backend-module/src/assets/toolbar';
24 |
25 | public $js = ['js/widget.js'];
26 |
27 | public $css = ['less/widget.less'];
28 |
29 | public $depends = [
30 | JqueryAsset::class,
31 | \rmrevin\yii\fontawesome\AssetBundle::class
32 | ];
33 | }
--------------------------------------------------------------------------------
/src/assets/backend-js/is-framed.js:
--------------------------------------------------------------------------------
1 | if (top.location != location) {
2 | document.body.className += ' ' + 'framed';
3 | } else {
4 | document.body.className += ' ' + 'unframed';
5 | }
6 |
--------------------------------------------------------------------------------
/src/assets/backend/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmstr/yii2-backend-module/7008e4748905253e8fd0fc3e6e2b8b92db58dd45/src/assets/backend/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/src/assets/backend/fonts/glyphicons-halflings-regular.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
--------------------------------------------------------------------------------
/src/assets/backend/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmstr/yii2-backend-module/7008e4748905253e8fd0fc3e6e2b8b92db58dd45/src/assets/backend/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/src/assets/backend/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmstr/yii2-backend-module/7008e4748905253e8fd0fc3e6e2b8b92db58dd45/src/assets/backend/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/src/assets/backend/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dmstr/yii2-backend-module/7008e4748905253e8fd0fc3e6e2b8b92db58dd45/src/assets/backend/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/src/assets/backend/less/backend.less:
--------------------------------------------------------------------------------
1 | @bowerAssetPath: '../../../vendor/bower-asset';
2 |
3 | @import (reference) "@{bowerAssetPath}/bootstrap/less/bootstrap.less";
4 | @import "json-editor";
5 |
6 | html,
7 | body {
8 | height: 100%;
9 | }
10 |
11 | BODY.framed {
12 | .dashboard-menu, .context-items-menu, .languages-menu, .sitemap-menu {
13 | display: none;
14 | }
15 | }
16 |
17 | BODY.unframed {
18 | .expand-menu {
19 | display: none;
20 | }
21 | }
22 |
23 | header {
24 | .logo {
25 | .title {
26 | .hidden-md;
27 | }
28 | }
29 | }
30 |
31 | .wrap {
32 | min-height: 100%;
33 | height: auto;
34 | margin: 0 auto -60px;
35 | padding: 0 0 60px;
36 | }
37 |
38 | .wrap > .container {
39 | padding: 70px 15px 20px;
40 | }
41 |
42 | .footer {
43 | height: 60px;
44 | background-color: #f5f5f5;
45 | border-top: 1px solid #ddd;
46 | padding-top: 20px;
47 | }
48 |
49 | .main-header {
50 | nav {
51 | .sidebar-toggle {
52 | padding: 10px;
53 | margin: 4px;
54 | }
55 | }
56 | }
57 |
58 | .user-menu .dropdown-toggle span {
59 | @media (max-width: 768px) {
60 | display: none;
61 | }
62 | }
63 |
64 | .control-sidebar {
65 | a.active {
66 | color: white;
67 | }
68 | }
69 |
70 | section.content-header, section.content {
71 | @media (max-width: 768px) {
72 | padding-left: 10px;
73 | padding-right: 10px;
74 | }
75 | }
76 |
77 | section.content {
78 | .grid-view {
79 | @media (max-width: 768px) {
80 | border: 0px solid #fff !important;
81 | }
82 | .table-responsive;
83 | table {
84 | //.table-condensed;
85 |
86 | th {
87 | &.action-column {
88 | min-width: 150px;
89 | width: 1%;
90 | }
91 | white-space: nowrap;
92 | }
93 |
94 | a {
95 | &[data-pjax="0"] {
96 | .btn;
97 | border: 1px solid;
98 | &:hover {
99 | //.btn-primary;
100 | }
101 | }
102 | &[data-method="post"],
103 | &[data-method="POST"] {
104 | .btn;
105 | border: 1px solid;
106 | //.text-danger;
107 | &:hover {
108 | //.btn-danger;
109 | }
110 | }
111 |
112 | }
113 | }
114 |
115 | }
116 | }
117 |
118 | .table-responsive {
119 | @media (max-width: 768px) {
120 | border: 0px solid #fff !important;
121 | }
122 |
123 | }
124 |
125 | .detail-view {
126 | TH {
127 | width: 1%;
128 | white-space: nowrap;
129 | }
130 | TD {
131 | PRE {
132 | overflow: auto;
133 | word-wrap: normal;
134 | white-space: pre-wrap;
135 | }
136 | }
137 | }
138 |
139 | div.alert p {
140 | max-height: 200px;
141 | max-width: 100%;
142 | overflow: auto;
143 | }
144 |
145 | .not-set {
146 | color: #c55;
147 | font-style: italic;
148 | }
149 |
150 | a {
151 | &:focus,
152 | &:hover {
153 | text-decoration: none;
154 | }
155 | }
156 |
157 | /** fix for select2 **/
158 | .select2-container {
159 | .select2-selection--single {
160 | .select2-selection__rendered {
161 | margin-top: 0;
162 | }
163 | }
164 | }
165 |
166 | /* add sorting icons to gridview sort links */
167 | a.asc:after, a.desc:after {
168 | position: relative;
169 | top: 1px;
170 | display: inline-block;
171 | font-family: 'Glyphicons Halflings';
172 | font-style: normal;
173 | font-weight: normal;
174 | line-height: 1;
175 | padding-left: 5px;
176 | }
177 |
178 | a.asc:after {
179 | content: /*"\e113"*/ "\e151";
180 | }
181 |
182 | a.desc:after {
183 | content: /*"\e114"*/ "\e152";
184 | }
185 |
186 | .sort-numerical a.asc:after {
187 | content: "\e153";
188 | }
189 |
190 | .sort-numerical a.desc:after {
191 | content: "\e154";
192 | }
193 |
194 | .sort-ordinal a.asc:after {
195 | content: "\e155";
196 | }
197 |
198 | .sort-ordinal a.desc:after {
199 | content: "\e156";
200 | }
201 |
202 | .jumbotron {
203 | text-align: center;
204 | background-color: transparent;
205 | }
206 |
207 | .jumbotron .btn {
208 | font-size: 21px;
209 | padding: 14px 24px;
210 | }
211 |
212 | .hint-block {
213 | display: block;
214 | margin-top: 5px;
215 | color: #999;
216 | }
217 |
218 | .error-summary {
219 | color: #a94442;
220 | background: #fdf7f7;
221 | border-left: 3px solid #eed3d7;
222 | padding: 10px 20px;
223 | margin: 0 0 15px 0;
224 | }
225 |
226 | // Fix for cursor position bug (WebKit)
227 | // see https://github.com/ajaxorg/ace/issues/1078#issuecomment-12839690 and http://stackoverflow.com/a/20932217/291573
228 | .ace_editor {
229 | font-family: monospace !important;
230 | font-size: 16px !important;
231 | }
232 |
233 | .info-box {
234 | A {
235 | color: white;
236 | }
237 | }
238 |
239 | .giiant-crud {
240 | .crud-navigation {
241 | margin: 1em 0;
242 | }
243 |
244 | .form-control, .select2-selection, .selectize-input {
245 | border-radius: 0px;
246 | }
247 |
248 | .well-sm {
249 | padding: 5px;
250 | border: none;
251 | box-shadow: none;
252 | //border-radius: @border-radius-small;
253 | }
254 |
255 | }
256 |
257 | .docs {
258 | .toc {
259 | h1 {
260 | .lead;
261 | margin-top: 0.5em;
262 | }
263 | h2 {
264 | font-size: 1em;
265 | font-weight: bold;
266 | margin-top: 1em;
267 | }
268 | ul {
269 | .list-group;
270 | margin-bottom: 0.5em;
271 | }
272 | & > ul > li {
273 | .list-group-item;
274 | }
275 | ul li ul li {
276 | margin-left: 1em;
277 | }
278 | }
279 | .file-content {
280 | font-size: 1.2em;
281 | line-height: 1.6em;
282 | blockquote {
283 | background: lighten(@gray-lighter, 3%);
284 | }
285 | }
286 | }
287 |
288 | .login-box {
289 | width: auto;
290 | }
291 |
292 | .login-box-body {
293 | background: none;
294 | }
295 |
296 | div[class^="col-"]>.btn-app {
297 | margin: 0 0 10px 0;
298 | }
299 |
--------------------------------------------------------------------------------
/src/assets/backend/less/json-editor.less:
--------------------------------------------------------------------------------
1 | // json-editor well padding
2 | .well-small {
3 | .well-sm;
4 | }
5 |
6 | // json-editor Bootstrap 3 fix
7 | div[id$="-container"] div[data-schemaid] {
8 | .form-group {
9 | margin-right: 0px;
10 | margin-left: 0px;
11 | }
12 |
13 | h3 {
14 | font-size: 1em;
15 | margin-top: 0.5em;
16 | }
17 | }
18 |
19 | div[data-schematype="object"] {
20 | .well;
21 | .well-small;
22 | }
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/assets/modal/js/modal.js:
--------------------------------------------------------------------------------
1 | // assign keyboard-action for modal and view mode
2 | // - only when focus is on
, to avoid unwanted keyboard actions
3 |
4 | $(document).on("keypress", function (e) {
5 | if ($(document.activeElement).is('body') && e.originalEvent.repeat !== true) {
6 | // open menu (m)
7 | if (e.charCode === 109) {
8 | $('#phd-info-button a').click();
9 | }
10 | // toggle view-mode (v)
11 | if (e.charCode === 118) {
12 | $('#app-frontend-view-mode-button').click();
13 | }
14 | // toggle button (h)
15 | if (e.charCode === 104) {
16 | $('#phd-info-button').toggle();
17 | }
18 | }
19 | });
20 |
--------------------------------------------------------------------------------
/src/assets/modal/less/widget.less:
--------------------------------------------------------------------------------
1 | #phd-info-button {
2 | position: fixed;
3 | top: 0;
4 | left: 0;
5 | opacity: 0.5;
6 | }
7 |
8 | #phd-info-modal,#phd-info-button {
9 | z-index: 1200; // so it ist above bootstrap modals
10 | }
11 |
--------------------------------------------------------------------------------
/src/assets/toolbar/js/check-frame.js:
--------------------------------------------------------------------------------
1 | function breakoutOfFrame()
2 | {
3 | // see https://www.thesitewizard.com/archive/framebreak.shtml
4 | // for an explanation of this script and how to use it on your
5 | // own website
6 | if (top.location != location) {
7 | top.location.href = document.location.href ;
8 | } else {
9 | document.body.className += ' ' + 'home';
10 | }
11 | }
12 |
13 | breakoutOfFrame();
--------------------------------------------------------------------------------
/src/assets/toolbar/js/widget.js:
--------------------------------------------------------------------------------
1 | function toggleSidebar() {
2 | $("#sidebar-wrapper").toggleClass("active");
3 | }
4 |
5 | $(document).ready(function () {
6 |
7 | var initialRequest = true;
8 | $('#sidebar-wrapper iframe').on('load', function () {
9 | console.log('iframe load');
10 | if (!initialRequest) {
11 | $('#sidebar-wrapper').addClass('active');
12 | $('#sidebar-wrapper').addClass('show-iframe');
13 | }
14 | initialRequest = false;
15 | });
16 |
17 | $('.hide-iframe')
18 | .on('mouseover', function () {
19 | $('#sidebar-wrapper').addClass('hide-iframe');
20 | })
21 | .on('mouseout', function () {
22 | $('#sidebar-wrapper').removeClass('hide-iframe');
23 | $('#sidebar-wrapper').removeClass('show-iframe');
24 | })
25 |
26 | console.log('Done');
27 | });
28 |
--------------------------------------------------------------------------------
/src/assets/toolbar/less/widget.less:
--------------------------------------------------------------------------------
1 | #sidebar-wrapper {
2 |
3 | #sidebar-toggle {
4 | position: absolute;
5 | top: 0;
6 | right: -50px;
7 | width: 50px;
8 | opacity: 0.85;
9 | &:hover {
10 | opacity: 1;
11 | }
12 | }
13 |
14 | position: fixed;
15 | top: 0;
16 | z-index: 1100;
17 | width: 80vw;
18 | max-width: 80%;
19 | margin-left: -80vw;
20 |
21 | transition-property: margin-left;
22 | transition-duration: 0.3s;
23 | transition-timing-function: ease-in-out;
24 |
25 | nav {
26 | margin-bottom: 0;
27 | }
28 |
29 | iframe {
30 | border: 0 solid white;
31 |
32 | background: #ccc;
33 | height: 100vh;
34 | width: 100%;
35 | }
36 |
37 | .sidebar-panel {
38 | height: 100vh;
39 | overflow: auto;
40 | opacity: 0.1;
41 |
42 | transition-property: opacity;
43 | transition-duration: 0.5s;
44 | transition-timing-function: ease-in-out;
45 | }
46 |
47 | &.active {
48 | margin-left: 0;
49 | }
50 | &:hover {
51 | .sidebar-panel {
52 | opacity: 1;
53 | }
54 | }
55 |
56 | &.show-iframe {
57 | .sidebar-panel {
58 | opacity: 1;
59 | }
60 | }
61 | &.hide-iframe {
62 | .sidebar-panel {
63 | opacity: 0;
64 | }
65 | }
66 |
67 | }
--------------------------------------------------------------------------------
/src/controllers/CacheController.php:
--------------------------------------------------------------------------------
1 | cache->flush()) {
29 | \Yii::$app->session->addFlash('success', Yii::t('backend-module','Cache cleared'));
30 | } else {
31 | \Yii::$app->session->addFlash('error', Yii::t('backend-module','Cannot clear cache'));
32 | }
33 | return $this->redirect(['default/index']);
34 | }
35 | }
--------------------------------------------------------------------------------
/src/controllers/ConfigController.php:
--------------------------------------------------------------------------------
1 | $loadedModules]);
23 | $loadedModulesDataProvider->pagination->pageSize = 100;
24 |
25 | $components = Yii::$app->getComponents();
26 | ksort($components);
27 | $modules = Yii::$app->getModules();
28 | ksort($modules);
29 | $env = $_ENV;
30 | ksort($env);
31 |
32 |
33 | return $this->render(
34 | 'view',
35 | [
36 | 'params' => Yii::$app->params,
37 | 'components' => $components,
38 | 'modules' => $modules,
39 | 'env' => $env,
40 | 'loadedModulesDataProvider' => $loadedModulesDataProvider,
41 | ]
42 | );
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/controllers/DefaultController.php:
--------------------------------------------------------------------------------
1 | hasModule('pages')) {
29 | // no `use` statement, since module is optional
30 | $items = \dmstr\modules\pages\models\Tree::getMenuItems('backend', true);
31 | } else {
32 | $items = [];
33 | }
34 |
35 | return $this->render('index', ['items' => $items]);
36 | }
37 |
38 |
39 |
40 | /**
41 | * @param array $item \dmstr\modules\pages\models\Tree::getMenuItems()
42 | *
43 | * @return string
44 | * @throws \Exception
45 | */
46 | public function renderDashboardMenu($item = [])
47 | {
48 | $menuItems = '';
49 |
50 | if (!isset($item['items'])) {
51 | return $menuItems;
52 | }
53 |
54 | foreach ($item['items'] as $subItem) {
55 | if ($subItem['visible'] && $subItem['url'] && $subItem['url'] !== '#') {
56 | $colorSelect = ArrayHelper::getValue($item, 'icon');
57 | $menuItems .= '';
58 | $infoBoxHtml = InfoBox::widget(
59 | [
60 | 'text' => '
'.$subItem['label'].' ',
61 | 'boxBg' => Module::colorHash($colorSelect[2] ?? 0),
62 | 'icon' => (isset($subItem['icon']) && !empty($subItem['icon']))
63 | ? Menu::$iconClassPrefix.$subItem['icon']
64 | : 'fa fa-circle-o',
65 | ]);
66 | $menuItems .= Html::a($infoBoxHtml, $subItem['url']);
67 | $menuItems .= '';
68 | }
69 |
70 | if (!empty($subItem['items'])) {
71 | $menuItems .= $this->renderDashboardMenu($subItem);
72 | }
73 | }
74 |
75 | return $menuItems;
76 | }
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/src/controllers/RbacController.php:
--------------------------------------------------------------------------------
1 | _manager = \Yii::$app->authManager;
21 |
22 | }
23 |
24 | /**
25 | * @return string
26 | */
27 | public function actionAssignments()
28 | {
29 | $allPermissions = Yii::$app->authManager->getPermissions();
30 | $allRoles = Yii::$app->authManager->getRoles();
31 | $userPermissions = [];
32 | $userRoles = [];
33 |
34 | foreach ($allPermissions AS $item) {
35 | if (Yii::$app->user->can($item->name)) {
36 | $userPermissions[] = [
37 | 'description' => $item->description,
38 | 'name' => $item->name,
39 | ];
40 | }
41 | }
42 | foreach ($allRoles AS $item) {
43 | if (Yii::$app->user->can($item->name)) {
44 | $userRoles[] = [
45 | 'description' => $item->description,
46 | 'name' => $item->name,
47 | ];
48 | }
49 | }
50 |
51 | return $this->render('show-auth',
52 | [
53 | 'permissions' => new ArrayDataProvider([
54 | 'allModels' => $userPermissions,
55 | 'pagination' => [
56 | 'pageSize' => 100,
57 | ],
58 | ]),
59 | 'roles' => new ArrayDataProvider([
60 | 'allModels' => $userRoles,
61 | 'pagination' => [
62 | 'pageSize' => 100,
63 | ],
64 | ]),
65 | ]);
66 | }
67 |
68 | public function actionDiagram()
69 | {
70 | $this->renderDiagram();
71 |
72 | $mmd = file_get_contents(\Yii::getAlias($this->_mmdFile));
73 | return $this->render('index.twig', ['mmd' => $mmd]);
74 | }
75 |
76 |
77 | private function renderDiagram()
78 | {
79 |
80 | $mermaid = 'flowchart LR' . PHP_EOL . PHP_EOL;
81 |
82 | $assignmentsMmd = '';
83 | $permissionMmd = '';
84 |
85 | $rolesMmd = $this->renderRoles();
86 | $permissionMmd .= $this->renderPermissions();
87 |
88 | foreach ($this->_manager->getRoles() as $role) {
89 | $assignmentsMmd .= $this->renderAssignments($role);
90 | }
91 | $assignmentsMmd .= PHP_EOL . PHP_EOL;
92 | foreach ($this->_manager->getPermissions() as $permission) {
93 | $assignmentsMmd .= $this->renderAssignments($permission);
94 | }
95 |
96 | #$mermaid .= $this->renderAsSubgraph('roles',$rolesMmd) . PHP_EOL;
97 | $mermaid .= $rolesMmd . PHP_EOL;
98 | #$mermaid .= $permissionMmd . PHP_EOL;
99 | $mermaid .= $permissionMmd . PHP_EOL;
100 | $mermaid .= $assignmentsMmd . PHP_EOL;
101 |
102 | $filename = \Yii::getAlias($this->_mmdFile);
103 | FileHelper::createDirectory(dirname($filename));
104 | file_put_contents($filename, $mermaid);
105 |
106 | }
107 |
108 | private function renderRoles()
109 | {
110 | $roles = $this->_manager->getRoles();
111 | $rolesMmd = '';
112 | $assignmentsMmd = '';
113 |
114 | $_gs = [];
115 |
116 | foreach ($roles as $role) {
117 | #var_dump($this->module->rbacDiagramExcludeRoles);exit;
118 | if (in_array($role->name, $this->module->rbacDiagramExcludeRoles)) continue;
119 |
120 | $group = $role->ruleName ?? '__NONE__';
121 | $group = '__NONE__';
122 |
123 | if ($role->ruleName) {
124 | $_gs[$group][] = $this->renderItem($role) . PHP_EOL;
125 | $arrow = '-.->';
126 | } else {
127 | $_gs[$group][] = $this->renderItem($role) . PHP_EOL;
128 | $arrow = '-->';
129 | }
130 |
131 | #$assignmentsMmd .= $this->renderAssignments($role);
132 |
133 | }
134 |
135 | foreach ($_gs as $groupName => $g) {
136 | $groupMmd = implode("\n", $g);
137 | if ($groupName !== '__NONE__') {
138 | $rolesMmd .= $this->renderAsSubgraph($groupName, $groupMmd);
139 | } else {
140 | $rolesMmd .= $groupMmd;
141 | }
142 | #$rolesMmd .= $groupMmd;
143 | }
144 |
145 |
146 | return $rolesMmd . $assignmentsMmd;
147 | }
148 |
149 | private function renderAssignments($item)
150 | {
151 | if (in_array($item->name, $this->module->rbacDiagramExcludeRoles, true)) {
152 | return;
153 | }
154 |
155 | $assignmentsMmd = '';
156 | foreach ($this->_manager->getChildren($item->name) as $child) {
157 | $arrow = ($item->ruleName) ? '-.->' : '-->';
158 | $assignmentsMmd .= $this->renderItem($item, true) . $arrow . $this->renderItem($child, true) . PHP_EOL;
159 | }
160 | return $assignmentsMmd;
161 | }
162 |
163 | private function renderPermissions()
164 | {
165 | $permissionGroups = [];
166 | $permissionMmd = '' . PHP_EOL;
167 | foreach ($this->_manager->getPermissions() as $permission) {
168 | $group = explode('_', $permission->name)[0];
169 | $group = explode('.', $group)[0];
170 | $group = explode('-', $group)[0];
171 | $permissionGroups[$group][] = $this->renderItem($permission) . PHP_EOL;
172 | }
173 |
174 | foreach ($permissionGroups as $group => $items) {
175 | $g = '';
176 | foreach ($items as $line) {
177 | $g .= $line;
178 | }
179 | $permissionMmd .= $this->renderAsSubgraph("__$group", $g);
180 | }
181 | return $permissionMmd;
182 | }
183 |
184 | private function renderAsSubgraph($name, $diagram)
185 | {
186 | $subgraph = 'subgraph ' . $name . PHP_EOL;
187 | $subgraph .= $diagram . PHP_EOL;
188 | $subgraph .= 'end' . PHP_EOL;
189 |
190 | return $subgraph;
191 | }
192 |
193 | private function renderItem($item, $compact = false)
194 | {
195 | if ($compact) {
196 | $node = md5($item->name);
197 | } else {
198 | $symbols = ($item->type == 1) ? ["(",")"] : ["[","]"];
199 | $node = md5($item->name) . $symbols[0]. '"' . $item->name . ' ' . $item->description . '"'.$symbols[1];
200 |
201 | $node .= ';' . PHP_EOL;
202 | $routePart = $item->type == 1 ? 'role' : 'permission';
203 | $node .= 'click ' . md5($item->name) . ' "/user/' . $routePart . '/update?name=' . $item->name . '" "TT";';
204 | }
205 | return $node;
206 | }
207 | }
208 |
--------------------------------------------------------------------------------
/src/interfaces/ContextMenuItemsInterface.php:
--------------------------------------------------------------------------------
1 |
17 | */
18 | interface ContextMenuItemsInterface
19 | {
20 | /**
21 | * This methods should return array list of menu items
22 | *
23 | * Example:
24 | *
25 | * [
26 | * [
27 | * 'label' => 'Link label',
28 | * 'url' => ['/']
29 | * ]
30 | * ]
31 | *
32 | * Classes which use this interface should also trigger the `registerMenuItems` preferred in the `init` method
33 | *
34 | * Example:
35 | *
36 | * public function init()
37 | * {
38 | * \Yii::$app->trigger('registerMenuItems', new Event(['sender' => $this]));
39 | * parent::init();
40 | * }
41 | *
42 | * Heads up: You may want to add a if statement around the trigger if it should only be triggered on certain conditions.
43 | *
44 | * @return array
45 | */
46 | public function getMenuItems();
47 | }
--------------------------------------------------------------------------------
/src/migrations/m160926_160610_settings.php:
--------------------------------------------------------------------------------
1 | settings instanceof \pheme\settings\components\Settings) {
10 | Yii::$app->settings->set('skin', 'black-light', 'backend.adminlte');
11 | }
12 |
13 | }
14 |
15 | public function down()
16 | {
17 | if (Yii::$app->settings instanceof \pheme\settings\components\Settings) {
18 | Yii::$app->settings->delete('skin', 'backend.adminlte');
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/migrations/m181207_200300_settings.php:
--------------------------------------------------------------------------------
1 | settings instanceof \pheme\settings\components\Settings) {
10 | Yii::$app->settings->getOrSet('backendWidget', 'modal', 'frontend', 'string');
11 |
12 | }
13 |
14 | }
15 |
16 | public function down()
17 | {
18 | if (Yii::$app->settings instanceof \pheme\settings\components\Settings) {
19 | Yii::$app->settings->delete('backendWidget', 'frontend');
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/views/config/_controller.php:
--------------------------------------------------------------------------------
1 | id) {
11 | $controller = Yii::$app->createController($model['name']);
12 | } else {
13 | $controller = Yii::$app->createController($model['module'].'/'.$model['name']);
14 | }
15 |
16 | ?>
17 |
18 |
22 |
23 |
24 | = $controller[0]->id ?>
25 |
26 |
27 |
28 | = Html::a($model['route'], $model['route']) ?>
29 |
30 | ';
33 | }
34 | ?>
35 |
36 |
37 |
38 |
39 |
40 | {moduleName}', [
41 | 'moduleName' => $model['name']
42 | ])?>
43 |
44 |
45 |
--------------------------------------------------------------------------------
/src/views/config/_module.php:
--------------------------------------------------------------------------------
1 |
14 |
15 | beginBlock('routes') ?>
16 |
17 | Metadata::getModuleControllers($key),
21 | ]
22 | );
23 | ?>
24 |
25 | = ListView::widget(
26 | [
27 | 'dataProvider' => $controllerDataProvider,
28 | 'layout' => "{items}\n{pager}",
29 | 'itemView' => '_controller',
30 | ]
31 | )
32 | ?>
33 |
34 | endBlock() ?>
35 |
36 |
37 | $key.' '.(isset($model) && is_object($model) ? 'loaded ' : ''),
39 | 'collapse' => false,
40 | 'collapse_remember' => false,
41 | 'type' => Box::TYPE_INFO
42 | ]) ?>
43 | = $this->blocks['routes'] ?>
44 |
45 |
46 |
--------------------------------------------------------------------------------
/src/views/config/view.php:
--------------------------------------------------------------------------------
1 | params['breadcrumbs'][] = ['label' => Yii::t('backend-module', 'Configuration')];
21 | $this->title = Yii::t('backend-module', 'Configuration');
22 | ?>
23 |
24 |
25 |
26 | beginBlock('controllers') ?>
27 |
28 |
29 | = $this->render('_module', ['key' => null]) ?>
30 |
31 |
32 | = ListView::widget(
33 | [
34 | 'dataProvider' => $loadedModulesDataProvider,
35 | 'itemView' => '_module',
36 | 'layout' => '{summary}{pager}
{items}
'
37 | ]
38 | )
39 | ?>
40 | endBlock('controllers') ?>
41 |
42 |
43 |
44 |
45 | beginBlock('params') ?>
46 | $element): ?>
47 |
48 |
49 | = $name ?>
50 |
51 |
52 |
53 | = Json::encode($element, JSON_PRETTY_PRINT) ?>
54 |
55 |
56 |
57 |
58 | endBlock('params') ?>
59 |
60 |
61 | beginBlock('components') ?>
62 | $element): ?>
63 |
64 |
65 | = $name ?>
66 |
67 |
68 |
69 | = Json::encode($element, JSON_PRETTY_PRINT) ?>
70 |
71 |
72 |
73 |
74 | endBlock('components') ?>
75 |
76 | beginBlock('modules') ?>
77 | $element): ?>
78 | $name,
80 | 'collapse' => true,
81 | 'collapse_remember' => false,
82 | ]) ?>
83 |
84 |
85 |
86 | = $name ?>
87 |
88 |
89 |
90 | = VarDumper::dumpAsString($element, 2, true) ?>
91 |
92 |
93 |
94 |
95 |
96 |
97 | endBlock('modules') ?>
98 |
99 |
100 | beginBlock('env') ?>
101 |
102 | = VarDumper::dumpAsString($env) ?>
103 |
104 | endBlock('env') ?>
105 |
106 |
107 |
108 |
109 | = Tabs::widget([
110 | 'items' => [
111 | [
112 | 'label' => Yii::t('backend-module', 'Params'),
113 | 'content' => $this->blocks['params'],
114 | ],
115 | [
116 | 'label' => Yii::t('backend-module', 'Components'),
117 | 'content' => $this->blocks['components'],
118 | ],
119 | [
120 | 'label' => Yii::t('backend-module', 'Modules'),
121 | 'content' => $this->blocks['modules'],
122 | ],
123 | [
124 | 'label' => Yii::t('backend-module', 'Controllers'),
125 | 'content' => $this->blocks['controllers'],
126 | ],
127 | [
128 | 'label' => Yii::t('backend-module', 'Environment'),
129 | 'content' => $this->blocks['env'],
130 | ],
131 | ],
132 | ]) ?>
133 |
134 |
--------------------------------------------------------------------------------
/src/views/default/index.php:
--------------------------------------------------------------------------------
1 | params['breadcrumbs'][] = ['label' => Yii::t('backend-module', 'Dashboard')];
10 | $this->title = Yii::t('backend-module', 'Dashboard');
11 | ?>
12 |
13 | =Yii::t('backend-module', 'Backend')?>
14 |
15 |
16 |
17 | user->can('Admin')): ?>
18 |
19 |
20 |
21 |
22 |
23 |
24 | = getenv('APP_NAME') ?>
25 |
26 |
27 |
28 | =Yii::t('backend-module', 'Application ID')?>
29 |
30 |
31 |
32 |
33 |
34 |
35 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | user->identityClass, 'find')
49 | && method_exists(\Yii::$app->user->identityClass::find(), 'count')) {
50 | echo \Yii::$app->user->identityClass::find()->count();
51 | } else {
52 | echo '-';
53 | }
54 | ?>
55 |
56 |
57 |
58 | =Yii::t('backend-module', 'Users')?>
59 |
60 |
61 |
62 |
63 |
64 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | = count(\Yii::$app->getModules()) ?>
77 |
78 |
79 |
80 | =Yii::t('backend-module', 'Modules')?>
81 |
82 |
83 |
84 |
85 |
86 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 | = YII_ENV ?>
100 |
101 |
102 |
103 | = defined('PROJECT_VERSION') ? PROJECT_VERSION : '-' ?>
104 |
105 |
106 |
107 |
108 |
109 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 | =Yii::t('backend-module', 'Diagram')?>
122 |
123 |
124 | =Yii::t('backend-module', 'RBAC Hierarchy')?>
125 |
126 |
127 |
128 |
129 |
130 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 | =Yii::t('backend-module', 'Auth')?>
143 |
144 |
145 |
146 | =Yii::t('backend-module', 'Roles & Permissions')?>
147 |
148 |
149 |
150 |
151 |
152 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 | =Yii::t('backend-module', 'Cache')?>
165 |
166 |
167 |
168 | =Yii::t('backend-module', 'Flush')?>
169 |
170 |
171 |
172 |
173 |
174 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 | context->renderDashboardMenu(['items' => $items]);
187 | ?>
188 |
189 |
190 |
191 |
--------------------------------------------------------------------------------
/src/views/layouts/_control-sidebar.php:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 | getModule('backend');
13 | foreach (\dmstr\helpers\Metadata::getModules() as $name => $module) {
14 | if (in_array($name, $backendModule->modulesDashboardBlacklist,true)) {
15 | continue;
16 | }
17 |
18 | $role = $name;
19 |
20 | $defaultItem = [
21 | 'icon' => 'fa fa-cube',
22 | 'label' => $name,
23 | 'url' => ['/' . $name],
24 | 'visible' => Yii::$app->user->can($role),
25 | 'items' => [],
26 | ];
27 |
28 | $developerMenuItems[] = $defaultItem;
29 | }
30 |
31 | if (Yii::$app->hasModule('pages')) {
32 | $rootItems = \dmstr\modules\pages\models\Tree::getMenuItems('root');
33 | } else {
34 | $rootItems = [];
35 | }
36 |
37 | if (Yii::$app->urlManager->hasProperty('languages')) {
38 | $languages = Yii::$app->urlManager->languages;
39 | } else {
40 | $languages = explode(',', getenv('APP_LANGUAGES'));
41 | }
42 |
43 | ?>
44 |
45 |
160 |
--------------------------------------------------------------------------------
/src/views/layouts/_sidebar.php:
--------------------------------------------------------------------------------
1 | hasModule('pages')) {
11 | $menuItems = \dmstr\modules\pages\models\Tree::getMenuItems('backend', true);
12 | } else {
13 | $menuItems = [];
14 | }
15 |
16 | ?>
17 |
18 |
19 | ['class' => 'sidebar-menu tree', 'data-widget' => 'tree'],
23 | 'encodeLabels' => false,
24 | 'items' => ArrayHelper::merge(
25 | ['items' => ['label' => Yii::t('backend-module', 'Backend navigation') , 'options' => ['class' => 'header']]],
26 | $menuItems
27 | ),
28 | ]
29 | );
30 | ?>
31 |
--------------------------------------------------------------------------------
/src/views/layouts/box.php:
--------------------------------------------------------------------------------
1 |
13 |
14 | beginContent('@vendor/dmstr/yii2-backend-module/src/views/layouts/main.php'); ?>
15 |
16 |
17 |
18 | = $content ?>
19 |
20 |
21 |
22 |
23 | endContent(); ?>
--------------------------------------------------------------------------------
/src/views/layouts/login.php:
--------------------------------------------------------------------------------
1 |
10 |
11 | beginPage() ?>
12 |
13 |
14 |
15 |
16 | = Html::csrfMetaTags() ?>
17 | = Html::encode($this->title) . ' - ' . Yii::$app->name ?>
18 |
19 |
20 | head() ?>
21 |
22 |
23 |
24 | beginBody() ?>
25 |
26 |
29 |
30 |
31 |
32 |
33 | = \dmstr\widgets\Alert::widget(['closeButton'=>false]) ?>
34 |
35 |
36 |
37 | = $content ?>
38 |
39 |
40 |
41 |
42 |
43 |
44 | endBody() ?>
45 |
46 |
47 | endPage() ?>
48 |
49 |
--------------------------------------------------------------------------------
/src/views/layouts/main.php:
--------------------------------------------------------------------------------
1 | has('settings')) {
28 | $adminLteSkin = Yii::$app->settings->get('skin', 'backend.adminlte') ?: 'black-light';
29 | $navBarIcon = Yii::$app->settings->get('navBarIcon', 'backend.adminlte') ?: FA::_HEART;
30 | $sidebarClass = Yii::$app->settings->get('sidebar', 'backend.adminlte', 'sidebar-mini ');
31 | $growlLocation = Yii::$app->settings->getOrSet('growl.location', 'br', 'backend', 'string');
32 | }
33 |
34 | // prepare assets
35 | BackendAsset::register($this);
36 | BackendJsAsset::register($this);
37 | $js = <<registerJs($js);
46 |
47 | ?>
48 |
49 | beginPage() ?>
50 |
51 |
52 |
53 |
54 | = Html::csrfMetaTags() ?>
55 | = Html::encode($this->title) . ' - ' . Yii::$app->name ?>
56 |
57 |
58 | head() ?>
59 |
60 |
61 |
64 | beginBody() ?>
65 |
66 |
67 | hasModule('prototype')) {
71 | try {
72 | $this->beginBlock('twig-main-top');
73 | echo TwigWidget::widget([
74 | 'position' => 'main-top',
75 | 'registerMenuItems' => true,
76 | 'queryParam' => false,
77 | 'renderEmpty' => false,
78 | ]);
79 | $this->endBlock('twig-main-top');
80 | } catch (InvalidCallException $e) {
81 | $this->blocks['twig-main-top'] = 'X';
82 | Yii::$app->session->addFlash('error', $e->getMessage());
83 | }
84 |
85 | try {
86 | $this->beginBlock('twig-main-bottom');
87 | echo TwigWidget::widget([
88 | 'position' => 'main-bottom',
89 | 'registerMenuItems' => true,
90 | 'queryParam' => false,
91 | 'renderEmpty' => false,
92 | ]);
93 | $this->endBlock('twig-main-bottom');
94 | } catch (InvalidCallException $e) {
95 | $this->blocks['twig-main-bottom'] = 'X';
96 | Yii::$app->session->addFlash('error', $e->getMessage());
97 | }
98 |
99 | try {
100 | $this->beginBlock('extra-content');
101 | echo TwigWidget::widget([
102 | 'key' => 'backend.extra.content',
103 | 'position' => 'bottom',
104 | 'registerMenuItems' => true,
105 | 'queryParam' => false,
106 | 'renderEmpty' => false,
107 | ]);
108 | $this->endBlock('extra-content');
109 | } catch (InvalidCallException $e) {
110 | $this->blocks['extra-content'] = '';
111 | Yii::$app->session->addFlash('error', $e->getMessage());
112 | }
113 | } else {
114 | $this->blocks['twig-main-top'] = '';
115 | $this->blocks['twig-main-bottom'] = '';
116 | $this->blocks['extra-content'] = '';
117 | }
118 | ?>
119 |
120 |
121 |
122 |
123 |
124 |
125 | = FA::icon($navBarIcon) ?>
126 | = getenv('APP_TITLE') ?>
127 |
128 |
129 |
130 |
131 | = CookieButton::widget([
132 | 'label' => '',
133 | 'options' => [
134 | 'class' => 'sidebar-toggle',
135 | 'data-toggle' => 'push-menu',
136 | 'role' => 'button',
137 | ],
138 | 'cookieName' => 'dmstr-backend_pin-navigation',
139 | 'cookieValue' => 'on',
140 | 'cookieOptions' => [
141 | 'path' => '/',
142 | 'http' => true,
143 | 'expires' => 7,
144 | ],
145 | ]) ?>
146 |
147 |
148 |
204 |
205 |
206 |
207 |
214 |
215 |
216 |
217 |
218 |
231 |
232 |
233 |
234 |
235 | = Wrapper::widget([
236 | 'layerClass' => Growl::class,
237 | 'options' => [
238 | 'dismissQueue' => true,
239 | 'location' => $growlLocation,
240 | 'timeout' => 4000,
241 | ],
242 | ]) ?>
243 | = $this->blocks['twig-main-top'] ?>
244 | = $content ?>
245 | = $this->blocks['twig-main-bottom'] ?>
246 |
247 |
248 |
249 |
250 | = $this->blocks['extra-content'] ?>
251 |
252 |
253 |
{appName}-{projectVersion} build with {phdLink} {appVersion}',
255 | [
256 | 'appName' => getenv('APP_NAME'),
257 | 'appVersion' => APP_VERSION,
258 | 'projectVersion' => PROJECT_VERSION,
259 | 'phdLink' => 'phd '
260 | ]) ?>
261 |
262 | = $this->render('_control-sidebar') ?>
263 |
264 |
265 |
266 | endBody() ?>
267 |
268 |
269 | endPage() ?>
270 |
--------------------------------------------------------------------------------
/src/views/rbac/index.twig:
--------------------------------------------------------------------------------
1 | {# register_asset_bundle('dmstr/web/MermaidAsset') #}
2 |
3 |
4 |
5 |
6 |
9 |
10 | {{ mmd }}
11 |
12 |
13 |
14 | {#
15 | Debug
16 |
17 | {{ mmd }}
18 |
19 | #}
20 |
--------------------------------------------------------------------------------
/src/views/rbac/show-auth.php:
--------------------------------------------------------------------------------
1 | title = Yii::t('backend-module', 'Authorizations');
7 |
8 | ?>
9 |
10 |
11 | 'Roles']);
13 | echo GridView::widget([
14 | 'dataProvider' => $roles,
15 |
16 | ]);
17 | Box::end();
18 | ?>
19 |
20 |
21 |
22 | 'Permissions']);
24 | echo GridView::widget([
25 | 'dataProvider' => $permissions
26 | ]);
27 | Box::end();
28 | ?>
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/widgets/Modal.php:
--------------------------------------------------------------------------------
1 | registerAssets();
18 | parent::init();
19 | }
20 |
21 | /**
22 | * @return string
23 | */
24 | public function run()
25 | {
26 |
27 | $data['name'] = Yii::$app->name;
28 | $data['appVersion'] = defined('APP_VERSION') ? APP_VERSION : '-';
29 | $data['projectVersion'] = defined('PROJECT_VERSION') ? PROJECT_VERSION : '-';
30 | $data['virtualHost'] = getenv('VIRTUAL_HOST');
31 | $data['hostname'] = getenv('HOSTNAME') ?: 'local';
32 |
33 | return $this->render('modal.twig', $data);
34 | }
35 |
36 | public function registerAssets()
37 | {
38 | ModalAsset::register($this->view);
39 | }
40 | }
--------------------------------------------------------------------------------
/src/widgets/Toolbar.php:
--------------------------------------------------------------------------------
1 | registerAssets();
31 | parent::init();
32 | }
33 |
34 | /**
35 | * @return string
36 | */
37 | public function run()
38 | {
39 | return $this->render('toolbar.twig', ['useIframe' => $this->useIframe]);
40 | }
41 |
42 | public function registerAssets()
43 | {
44 | $file = \Yii::$app->assetManager->publish(dirname(__DIR__) . '/assets/toolbar/js/check-frame.js');
45 | $this->view->registerJsFile($file[1], ['position' => View::POS_BEGIN]);
46 | ToolbarAsset::register($this->view);
47 | }
48 | }
--------------------------------------------------------------------------------
/src/widgets/views/modal.twig:
--------------------------------------------------------------------------------
1 | {{ use ('dmstr/cookiebutton') }}
2 | {{ use ('yii/widgets') }}
3 | {{ use ('rmrevin/yii/fontawesome/FA') }}
4 | {{ use ('dmstr/lajax/translatemanager/widgets/ToggleTranslateLink') }}
5 |
6 |
7 | {% if not app.user.isGuest %}
8 | {% set backendItems = Tree.getMenuItems('backend', true, {'target': app.params['backend.iframe.name']} ) ?: [] %}
9 |
10 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
× Close
80 |
81 | {% if app.settings.get('backendButtonsInModal', 'frontend') and not app.user.isGuest %}
82 |
83 | {{ Html.a(
84 | FA.icon(FA._ARROW_CIRCLE_LEFT),
85 | Url.to(['/backend']),
86 | {
87 | 'target': app.params['backend.iframe.name'],
88 | 'class': 'btn btn-default btn-primary',
89 | 'title': 'Application backend'
90 | }
91 | ) | raw }}
92 |
93 | {% if (app.user.can('frontend.toggle-view-mode')) %}
94 | {{ cookie_button_widget(
95 | {
96 | 'id': 'app-frontend-view-mode-button',
97 | 'label': FA.icon(FA._EYE_SLASH),
98 | 'encodeLabel': false,
99 | 'cookieName': 'app-frontend-view-mode',
100 | 'cookieValue': 'on',
101 | 'cookieOptions': {
102 | 'path': '/',
103 | 'http': true,
104 | 'expires': 7
105 | },
106 | 'options': {
107 | 'class': 'btn btn-default',
108 | 'title': 'Toggle frontend view-mode (v)'
109 | }
110 | }
111 | ) }}
112 | {% endif %}
113 |
114 | {% endif %}
115 |
116 |
117 |
{{ app.name }}
118 |
119 | {{ constant('YII_ENV') }}
120 | {% if constant('YII_DEBUG') %}
121 | debug
122 | {% endif %}
123 |
124 |
125 |
126 |
127 | {% if (app.user.can('backend_default_index')) %}
128 |
129 |
130 |
Backend
131 | {{ nav_widget({'items': backendItems, 'encodeLabels': false}) }}
132 |
133 |
134 |
Context
135 | {{ nav_widget({'items': app.params['context.menuItems'], 'encodeLabels': false,}) }}
136 |
137 |
138 | {% endif %}
139 |
140 |
Info
141 |
142 |
143 | Name
144 | {{ name }}
145 |
146 |
147 | App Version
148 | {{ appVersion }}
149 |
150 |
151 | Project Version
152 | {{ projectVersion }}
153 |
154 | {% if virtualHost %}
155 |
156 | Virtual Host
157 | {{ virtualHost }}
158 |
159 | {% endif %}
160 |
161 | Hostname
162 | {{ hostname }}
163 |
164 |
165 |
166 |
167 |
168 |
169 | Built with {{ Html.a('phd', 'https://phd.dmstr.io',{'target': '_blank'}) | raw }}
170 | from {{ Html.a('dmstr', 'https://www.diemeisterei.de',{'target': '_blank'}) | raw }}
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 | {% endif %}
183 |
--------------------------------------------------------------------------------
/src/widgets/views/toolbar.twig:
--------------------------------------------------------------------------------
1 | {{ use ('yii/widgets') }}
2 | {{ use ('pheme/settings/models/Setting') }}
3 | {{ use ('yii/helpers/Url') }}
4 | {{ use ('dmstr/modules/prototype/widgets/TwigWidget') }}
5 | {{ use ('dmstr/cookiebutton/CookieButton') }}
6 | {{ use ('rmrevin/yii/fontawesome/FA') }}
7 | {{ use ('dmstr/lajax/translatemanager/widgets/ToggleTranslateLink') }}
8 |
9 | {% if not app.user.isGuest %}
10 | {% set backendItems = Tree.getMenuItems('backend', true, {'target': app.params['backend.iframe.name']} ) %}
11 |
12 |
14 |
15 |
111 |
112 |
119 |
120 | {% endif %}
--------------------------------------------------------------------------------
/tests/.env:
--------------------------------------------------------------------------------
1 | COMPOSE_PROJECT_NAME=test-yii2-backend-module
2 |
--------------------------------------------------------------------------------
/tests/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM dmstr/yii2-app:0.6.2
2 |
3 | # Install npm and lessc
4 | RUN curl -sL https://deb.nodesource.com/setup_8.x | bash - \
5 | && apt-get install -y npm \
6 | && npm install -g less
7 | ENV PATH /app:/repo/tests/project/vendor/bin:/usr/lib/node_modules/less/bin:$PATH
8 |
9 | ENV COMPOSER=/repo/tests/project/composer.json
10 |
11 | # Clean vendor from base image
12 | RUN rm -rf /app/vendor
13 | RUN ln -s /repo/tests/project/vendor /app/vendor
--------------------------------------------------------------------------------
/tests/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '2'
2 | services:
3 |
4 | php:
5 | build:
6 | dockerfile: Dockerfile
7 | context: .
8 | working_dir: /repo/tests
9 | ports:
10 | - 80
11 | environment:
12 | - YII_ENV=test
13 | - YII_DEBUG=1
14 | - APP_CONFIG_FILE=/repo/tests/project/config/test.php
15 | volumes:
16 | # mount this repository read-only
17 | - ./..:/repo:ro
18 | # mount tests
19 | - ./:/repo/tests
20 | # composer cache
21 | - ~/.composer-docker/cache:/root/.composer/cache:delegated
22 | networks:
23 | default:
24 | aliases:
25 | - web
--------------------------------------------------------------------------------
/tests/project/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "repositories": [
3 | {
4 | "type": "vcs",
5 | "url": "file:///repo"
6 | },
7 | {
8 | "type": "composer",
9 | "url": "https://asset-packagist.org"
10 | }
11 | ],
12 | "require": {
13 | "wikimedia/composer-merge-plugin": "~1.4"
14 | },
15 | "extra": {
16 | "merge-plugin": {
17 | "require": [
18 | "/app/composer.json",
19 | "/repo/composer.json"
20 | ]
21 | }
22 | },
23 | "config": {
24 | "fxp-asset": {
25 | "installer-paths": {
26 | "npm-asset-library": "vendor/npm",
27 | "bower-asset-library": "vendor/bower"
28 | },
29 | "vcs-driver-options": {
30 | "github-no-api": true
31 | },
32 | "git-skip-update": "2 days",
33 | "pattern-skip-version": "(-build|-patch)",
34 | "optimize-with-installed-packages": false
35 | }
36 | }
37 | }
--------------------------------------------------------------------------------
/tests/project/config/test.php:
--------------------------------------------------------------------------------
1 | [
8 | 'backend' => '/repo/src',
9 | 'vendor/dmstr/yii2-backend-module' => '/repo'
10 | ],
11 | 'components' => [
12 | 'assetManager' => [
13 | 'converter' => [
14 | 'class' => 'yii\web\AssetConverter',
15 | 'commands' => [
16 | 'less' => ['css', 'lessc {from} {to} --no-color --modify-var="bowerAssetPath=/app/vendor/bower-asset"'],
17 | ],
18 | ],
19 | ],
20 | 'user' => [
21 | 'class' => 'dmstr\web\User',
22 | 'identityClass' => 'app\components\AdminIdentity',
23 | #'rootUsers' => ['admin']
24 | ],
25 | ],
26 | 'modules' => [
27 | 'backend' => [
28 | 'class' => 'dmstr\modules\backend\Module',
29 | 'layout' => '@backend/views/layouts/main',
30 | ]
31 | ],
32 | ];
--------------------------------------------------------------------------------