alchemy-chimera 1.0.1 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,18 @@
1
+ ## 1.0.4 (2022-05-31)
2
+
3
+ * Add delete page
4
+
5
+ ## 1.0.3 (2022-03-16)
6
+
7
+ * Make table filtering case insensitive
8
+
9
+ ## 1.0.2 (2022-02-20)
10
+
11
+ * Improve editor styling
12
+ * Put editor errors in the Widget context
13
+ * Add TOC to editor
14
+ * Make sidebar sticky
15
+
1
16
  ## 1.0.1 (2022-01-28)
2
17
 
3
18
  * Allow setting a simple menu sidebar in the config
File without changes
@@ -10,6 +10,7 @@ body {
10
10
  --text-color: #475466;
11
11
  --main-bg-color: #ebedf0;
12
12
  --main-border-color: #dadee0;
13
+
13
14
  --button-bg-color: #F4F5F9;
14
15
  --button-bg-hover-color: #e7e9f2;
15
16
  --button-text-color: #3699FF;
@@ -31,20 +32,95 @@ body {
31
32
  }
32
33
 
33
34
  .btn {
35
+ //--button-bg-color: var(--context-background-color, --button-bg-color);
36
+ --local-text-color: var(--context-color, var(--button-text-color));
37
+ --local-border-color: var(--context-border-color, var(--button-border-color));
38
+
34
39
  background-color: var(--button-bg-color);
40
+ color: var(--local-text-color);
41
+ border: 1px solid;
42
+ border-color: var(--local-border-color);
43
+
35
44
  text-decoration: none;
36
- color: var(--button-text-color);
37
45
  line-height: 2rem;
38
46
  min-width: 10rem;
39
47
  text-align: center;
40
48
  border-radius: 2px;
41
49
  font-weight: 500;
42
50
  cursor: pointer;
43
- border: 1px solid;
51
+ padding: 0.4rem 0.7rem;
52
+
53
+ display: inline-flex;
54
+ align-items: center;
55
+ justify-content: center;
56
+ gap: 0.2rem;
44
57
 
45
58
  &:hover {
46
59
  background-color: var(--button-bg-hover-color);
60
+ //filter: brightness(1.05);
47
61
  }
62
+
63
+ al-ico {
64
+ margin-right: 4px;
65
+ }
66
+ }
67
+
68
+ .primary {
69
+ --context-color: #084298;
70
+ --context-background-color: #cfe2ff;
71
+ --context-border-color: #b6d4fe;
72
+ }
73
+
74
+ .secondary {
75
+ --context-color: #41464b;
76
+ --context-background-color: #e2e3e5;
77
+ --context-border-color: #d3d6d8;
78
+ }
79
+
80
+ .success {
81
+ --context-color: #0f5132;
82
+ --context-background-color: #d1e7dd;
83
+ --context-border-color: #badbcc;
84
+ }
85
+
86
+ .danger,
87
+ .error {
88
+ --context-color: #842029;
89
+ --context-background-color: #f8d7da;
90
+ --context-border-color: #f5c2c7;
91
+ }
92
+
93
+ .warning {
94
+ --context-color: #664d03;
95
+ --context-background-color: #fff3cd;
96
+ --context-border-color: #ffecb5;
97
+ }
98
+
99
+ .info {
100
+ --context-color: #055160;
101
+ --context-background-color: #cff4fc;
102
+ --context-border-color: #b6effb;
103
+ }
104
+
105
+ .light {
106
+ --context-color: #636464;
107
+ --context-background-color: #fefefe;
108
+ --context-border-color: #fdfdfe;
109
+ }
110
+
111
+ .dark {
112
+ --context-color: #141619;
113
+ --context-background-color: #d3d3d4;
114
+ --context-border-color: #bcbebf;
115
+ }
116
+
117
+ .alert-box {
118
+ color: var(--context-color);
119
+ background-color: var(--context-background-color);
120
+ border: 1px solid;
121
+ border-color: var(--context-border-color);
122
+ padding: 1rem;
123
+ margin: 1rem 0 1rem;
48
124
  }
49
125
 
50
126
  .chimera-sidebar {
@@ -52,11 +128,16 @@ body {
52
128
  flex: 0 0 14rem;
53
129
  display: flex;
54
130
  flex-flow: column;
131
+
132
+ .sidebar-widgets {
133
+ position: sticky;
134
+ top: 1rem;
135
+ }
55
136
  }
56
137
 
57
138
  .chimera-content {
58
139
  background-color: var(--main-bg-color);
59
- flex: 1 0;
140
+ flex: 10 0;
60
141
  display: flex;
61
142
  flex-flow: column;
62
143
 
@@ -92,6 +173,14 @@ body {
92
173
  .chimera-main {
93
174
  flex: 1;
94
175
  padding: 0.5rem;
176
+ display: flex;
177
+ flex-flow: column;
178
+
179
+ &[data-he-template="chimera/widgets"] {
180
+ h1 {
181
+ padding-top: 0;
182
+ }
183
+ }
95
184
  }
96
185
 
97
186
  .main-widgets {
@@ -182,11 +271,21 @@ alchemy-table .aft-column-filters input {
182
271
  width: 100%;
183
272
  }
184
273
 
274
+ alchemy-form {
275
+ .error-area:not(:empty) {
276
+ @extend .error, .alert-box;
277
+ margin-top: 0;
278
+ }
279
+ }
280
+
185
281
  alchemy-field {
186
282
  border: 1px solid var(--color-box-border);
187
283
  background-color: white;
188
284
  border-radius: 4px;
189
285
 
286
+ // In case something goes wrong:
287
+ min-height: 1rem;
288
+
190
289
  alchemy-label {
191
290
  padding-left: 1rem;
192
291
  line-height: 3rem;
@@ -203,7 +302,7 @@ alchemy-field {
203
302
  display: flex;
204
303
 
205
304
  button {
206
- flex: 1;
305
+ flex: 10;
207
306
  font-size: 16px;
208
307
  font-weight: 500;
209
308
  color: var(--button-text-color);
@@ -232,9 +331,10 @@ alchemy-field {
232
331
  .field {
233
332
  display: flex;
234
333
  padding: 1rem;
334
+ flex: 10;
235
335
 
236
336
  > * {
237
- flex: 1;
337
+ flex: 10;
238
338
  }
239
339
 
240
340
  > alchemy-widget {
@@ -243,17 +343,107 @@ alchemy-field {
243
343
  }
244
344
  }
245
345
 
246
- .field input[type="text"],
247
- .field input[type="number"],
248
- .field input[type="color"] {
249
- @extend .chimera-input-field;
250
- height: 3rem;
346
+ .field {
347
+ input[type="text"],
348
+ input[type="number"],
349
+ input[type="color"],
350
+ input[type="datetime-local"],
351
+ input[type="password"] {
352
+ @extend .chimera-input-field;
353
+ height: 3rem;
354
+ }
355
+
356
+ textarea {
357
+ @extend .chimera-input-field;
358
+ min-height: 5rem;
359
+ padding: 1rem;
360
+ }
361
+
362
+ input[type="color"] {
363
+ background-color: transparent;
364
+ border: none;
365
+ padding: 0;
366
+ }
367
+ }
368
+ }
369
+
370
+ alchemy-field-array {
371
+ .add-entry {
372
+ @extend .btn;
373
+ margin: 1rem 0 0 1rem;
374
+ }
375
+
376
+ button.remove {
377
+ @extend .btn;
378
+ @extend .danger;
379
+ min-width: 6rem;
380
+ margin: 0 1rem 1rem 0;
381
+ }
382
+
383
+ .entries {
384
+ margin-top: 0.5rem;
385
+ }
386
+
387
+ alchemy-field-array-entry:not(:last-of-type) {
388
+ //border-bottom: 1px solid gray;
389
+ position: relative;
390
+
391
+ &::after {
392
+ display: block;
393
+ content: " ";
394
+ background-color: lightgray;
395
+ position: absolute;
396
+ bottom: 0;
397
+ height: 1px;
398
+ left: 50%;
399
+ transform: translateX(-50%);
400
+ width: 80%;
401
+ }
402
+ }
403
+
404
+ alchemy-field-array-entry:not(:first-of-type) {
405
+ margin-top: 1rem;
406
+ }
407
+ }
408
+
409
+ .chimera-editor-widgets {
410
+
411
+ alchemy-widgets-column.toc-col {
412
+ flex: 2 2;
413
+ }
414
+
415
+ table-of-contents[elements-selector="alchemy-field"] {
416
+ align-self: start;
417
+ top: 2rem;
418
+ position: sticky;
419
+
420
+ ol {
421
+ list-style: none;
422
+ margin: 0 0 0 2rem;
423
+ padding: 0;
424
+
425
+ li {
426
+ a {
427
+ display: block;
428
+ line-height: 2rem;
429
+ border-bottom: 1px solid #aaa;
430
+ text-decoration: none;
431
+ opacity: 0.5;
432
+ color: #0070e4;
433
+ }
434
+ }
435
+
436
+ li a.visible {
437
+ opacity: 1;
438
+ }
439
+ }
251
440
  }
441
+ }
252
442
 
253
- .field input[type="color"] {
254
- background-color: transparent;
443
+ alchemy-field-schema {
444
+ alchemy-field {
255
445
  border: none;
256
- padding: 0;
446
+ margin-bottom: 1rem;
257
447
  }
258
448
  }
259
449
 
@@ -270,4 +460,18 @@ alchemy-field {
270
460
  background-color: var(--button-bg-hover-color);
271
461
  }
272
462
  }
463
+ }
464
+
465
+ .chimera-confirm-page {
466
+ flex: 1;
467
+ justify-content: center;
468
+ display: flex;
469
+ align-items: center;
470
+ flex-flow: column;
471
+ flex-direction: column;
472
+
473
+ .action-buttons {
474
+ display: flex;
475
+ gap: 1rem;
476
+ }
273
477
  }
package/config/routes.js CHANGED
@@ -35,6 +35,14 @@ chimera_section.add({
35
35
  breadcrumb : 'chimera.editor.{model}.edit.{pk}'
36
36
  });
37
37
 
38
+ // Editor trash action
39
+ chimera_section.add({
40
+ name : 'Chimera.Editor#trash',
41
+ methods : ['get', 'post'],
42
+ paths : '/editor/{model}/trash/{pk}',
43
+ breadcrumb : 'chimera.editor.{model}.trash.{pk}'
44
+ });
45
+
38
46
  // Editor data action
39
47
  chimera_section.add({
40
48
  name : 'Chimera.Editor#records',
File without changes
@@ -69,7 +69,7 @@ Editor.setAction(function index(conduit, model_name) {
69
69
  *
70
70
  * @author Jelle De Loecker <jelle@elevenways.be>
71
71
  * @since 0.1.0
72
- * @version 1.0.1
72
+ * @version 1.0.2
73
73
  *
74
74
  * @param {Conduit} conduit
75
75
  * @param {String} model_name
@@ -97,10 +97,8 @@ Editor.setAction(async function add(conduit, model_name) {
97
97
 
98
98
  return conduit.redirect(url);
99
99
  } catch (err) {
100
- // @TODO: set this in the context somehow?
101
- this.set('record_violations', err);
102
-
103
100
  this.set('context_variables', {
101
+ form_violations : err,
104
102
  record : record
105
103
  });
106
104
  }
@@ -125,7 +123,7 @@ Editor.setAction(async function add(conduit, model_name) {
125
123
  *
126
124
  * @author Jelle De Loecker <jelle@elevenways.be>
127
125
  * @since 0.1.0
128
- * @version 1.0.1
126
+ * @version 1.0.2
129
127
  *
130
128
  * @param {Conduit} conduit
131
129
  * @param {String} model_name
@@ -140,9 +138,9 @@ Editor.setAction(async function edit(conduit, model_name, pk_val) {
140
138
  let record = await model.findByPk(pk_val);
141
139
  let message_type = conduit.param('message');
142
140
 
143
- this.set('context_variables', {
144
- record : record
145
- });
141
+ let context_variables = {
142
+ record,
143
+ };
146
144
 
147
145
  if (conduit.method == 'post') {
148
146
 
@@ -152,11 +150,12 @@ Editor.setAction(async function edit(conduit, model_name, pk_val) {
152
150
  await record.save();
153
151
  message_type = 'saved';
154
152
  } catch (err) {
155
- // @TODO: set this in the context somehow?
156
- this.set('record_violations', err);
153
+ context_variables.form_violations = err;
157
154
  }
158
155
  }
159
156
 
157
+ this.set('context_variables', context_variables);
158
+
160
159
  let widget_config = model.chimera.getWidgetConfig('edit', conduit);
161
160
 
162
161
  if (!widget_config.class_names) {
@@ -179,12 +178,52 @@ Editor.setAction(async function edit(conduit, model_name, pk_val) {
179
178
  this.render('chimera/widgets');
180
179
  });
181
180
 
181
+ /**
182
+ * The trash action
183
+ *
184
+ * @author Jelle De Loecker <jelle@elevenways.be>
185
+ * @since 1.0.4
186
+ * @version 1.0.4
187
+ *
188
+ * @param {Conduit} conduit
189
+ * @param {String} model_name
190
+ * @param {String} pk_val
191
+ */
192
+ Editor.setAction(async function trash(conduit, model_name, pk_val) {
193
+
194
+ let model = this.getModel(model_name);
195
+
196
+ model.translateItems = false;
197
+
198
+ let record = await model.findByPk(pk_val);
199
+
200
+ if (!record) {
201
+ return conduit.notFound();
202
+ }
203
+
204
+ let index_url = alchemy.routeUrl('Chimera.Editor#index', {
205
+ model : model_name
206
+ });
207
+
208
+ if (conduit.method == 'post') {
209
+ await record.remove();
210
+ conduit.redirect(index_url);
211
+ return;
212
+ }
213
+
214
+ let referer = conduit.headers.referer || index_url;
215
+
216
+ this.set('back_url', referer);
217
+ this.set('record', record);
218
+ this.render('chimera/editor/trash');
219
+ });
220
+
182
221
  /**
183
222
  * The records API action
184
223
  *
185
224
  * @author Jelle De Loecker <jelle@elevenways.be>
186
225
  * @since 1.0.0
187
- * @version 1.0.0
226
+ * @version 1.0.4
188
227
  *
189
228
  * @param {Conduit} conduit
190
229
  * @param {String} model_name
@@ -230,7 +269,7 @@ Editor.setAction(async function records(conduit, model_name) {
230
269
  continue;
231
270
  }
232
271
 
233
- val = RegExp.interpretWildcard('*' + val + '*');
272
+ val = RegExp.interpretWildcard('*' + val + '*', 'i');
234
273
  crit.where(key).equals(val);
235
274
  }
236
275
  }
@@ -242,15 +281,29 @@ Editor.setAction(async function records(conduit, model_name) {
242
281
 
243
282
  for (record of records) {
244
283
 
245
- record.$hold.actions = [
246
- {
247
- name : 'edit',
248
- icon : 'edit',
249
- url : alchemy.routeUrl('Chimera.Editor#edit', {
284
+ let edit_action = new Classes.Alchemy.Form.Action.Url({
285
+ name : 'edit',
286
+ icon : 'edit',
287
+ placement : ['row', 'context'],
288
+ url : alchemy.routeUrl('Chimera.Editor#edit', {
289
+ model : model_name,
290
+ pk : record.$pk,
291
+ })
292
+ });
293
+
294
+ let trash_action = new Classes.Alchemy.Form.Action.Url({
295
+ name : 'trash',
296
+ icon : 'trash',
297
+ placement : ['context'],
298
+ url : alchemy.routeUrl('Chimera.Editor#trash', {
250
299
  model : model_name,
251
300
  pk : record.$pk,
252
301
  })
253
- }
302
+ });
303
+
304
+ record.$hold.actions = [
305
+ edit_action,
306
+ trash_action,
254
307
  ];
255
308
  }
256
309
 
File without changes
@@ -65,7 +65,7 @@ Config.setMethod(function getFieldSet(name) {
65
65
  *
66
66
  * @author Jelle De Loecker <jelle@elevenways.be>
67
67
  * @since 1.0.0
68
- * @version 1.0.0
68
+ * @version 1.0.2
69
69
  *
70
70
  * @param {String} action
71
71
  * @param {Conduit} conduit
@@ -118,12 +118,43 @@ Config.setMethod(function getWidgetConfig(action, conduit) {
118
118
  "level": 1,
119
119
  "content": this.ModelClass.title + ' edit',
120
120
  }
121
- }, {
122
- "type": "alchemy_form",
123
- "config": {
124
- model : this.ModelClass.type_name,
125
- view_type : 'edit',
126
- widgets : field_widgets
121
+ },
122
+ {
123
+ type: "row",
124
+ config: {
125
+ widgets: [
126
+ {
127
+ type: "column",
128
+ config: {
129
+ widgets: [
130
+ {
131
+ "type": "alchemy_form",
132
+ "config": {
133
+ model : this.ModelClass.type_name,
134
+ view_type : 'edit',
135
+ widgets : field_widgets
136
+ }
137
+ }
138
+ ]
139
+ }
140
+ },
141
+ {
142
+ type: 'column',
143
+ config: {
144
+ wrapper_class_names: 'toc-col',
145
+ widgets: [
146
+ {
147
+ type: "table_of_contents",
148
+ config: {
149
+ parent_selector: 'alchemy-widgets-row',
150
+ elements_selector: 'alchemy-field',
151
+ title_selector: 'alchemy-label'
152
+ }
153
+ }
154
+ ]
155
+ }
156
+ }
157
+ ]
127
158
  }
128
159
  }
129
160
  ]
package/model/model.js CHANGED
File without changes
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "alchemy-chimera",
3
3
  "description": "Chimera plugin for Alchemy MVC",
4
- "version": "1.0.1",
4
+ "version": "1.0.4",
5
5
  "author": "Jelle De Loecker <jelle@elevenways.be>",
6
6
  "keywords": [
7
7
  "alchemy",
@@ -12,9 +12,8 @@
12
12
  "repository": "11ways/alchemy-chimera",
13
13
  "peerDependencies": {
14
14
  "alchemy-acl" : "~0.7.0",
15
- "alchemy-menu" : "~0.6.0",
16
- "alchemymvc" : "~1.1.0",
17
- "alchemy-widget": "~0.1.0"
15
+ "alchemymvc" : "~1.2.1",
16
+ "alchemy-widget": "~0.1.2"
18
17
  },
19
18
  "license": "MIT",
20
19
  "engines": {
File without changes
File without changes
@@ -0,0 +1,34 @@
1
+ {% include "layouts/chimera_basics" %}
2
+
3
+ {% block "main" %}
4
+ <div class="chimera-confirm-page">
5
+ <h1>{%t "confirm-delete-title" %}</h1>
6
+
7
+ <p>
8
+ {%t "confirm-delete-text" model=record.$model_name title=record.getDisplayFieldValue() %}
9
+ </p>
10
+
11
+ <br>
12
+
13
+ <form class="action-buttons">
14
+ <a class="btn" href={% back_url %}>
15
+ {%t "cancel" %}
16
+ </a>
17
+ <button class="btn danger">
18
+ <al-ico type="trash" class="fas fa-trash"></al-ico>
19
+ {%t "delete" %}
20
+ </button>
21
+ </form>
22
+ </div>
23
+ {% /block %}
24
+
25
+ {% block "page-actions" %}
26
+ <a
27
+ !Route="Chimera.Editor#add"
28
+ #model={% model_name %}
29
+ class="btn"
30
+ >
31
+ <al-ico type="plus"></al-ico>
32
+ {%t "new" model=model_name %}
33
+ </a>
34
+ {% /block %}
File without changes
File without changes
File without changes
File without changes
File without changes