alchemy-form 0.1.5 → 0.1.8

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.
Files changed (48) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/assets/stylesheets/form/alchemy_field_array.scss +4 -0
  3. package/assets/stylesheets/form/alchemy_select.scss +1 -3
  4. package/assets/stylesheets/form/alchemy_toggle.scss +2 -0
  5. package/assets/stylesheets/form/query_builder.scss +185 -0
  6. package/config/routes.js +8 -0
  7. package/controller/form_api_controller.js +43 -4
  8. package/element/20_query_builder_base.js +82 -0
  9. package/element/25_query_builder_data.js +139 -0
  10. package/element/alchemy_field.js +31 -7
  11. package/element/alchemy_select.js +172 -39
  12. package/element/alchemy_select_item.js +9 -0
  13. package/element/alchemy_table.js +172 -26
  14. package/element/query_builder.js +90 -0
  15. package/element/query_builder_entry.js +388 -0
  16. package/element/query_builder_group.js +248 -0
  17. package/element/query_builder_value.js +316 -0
  18. package/element/query_builder_variable.js +103 -0
  19. package/helper/form_actions/00_form_action.js +328 -0
  20. package/helper/form_actions/url_action.js +69 -0
  21. package/helper/query_builder_variable_definition/00_variable_definition.js +371 -0
  22. package/helper/query_builder_variable_definition/boolean_variable_definition.js +24 -0
  23. package/helper/query_builder_variable_definition/list_variable_definition.js +38 -0
  24. package/helper/query_builder_variable_definition/number_variable_definition.js +106 -0
  25. package/helper/query_builder_variable_definition/string_variable_definition.js +46 -0
  26. package/helper_field/query_builder_assignment.js +11 -0
  27. package/helper_field/query_builder_field.js +91 -0
  28. package/helper_field/query_builder_value.js +56 -0
  29. package/helper_field/query_builder_variable.js +56 -0
  30. package/package.json +2 -2
  31. package/view/form/elements/alchemy_field_array.hwk +3 -1
  32. package/view/form/elements/alchemy_field_array_entry.hwk +3 -1
  33. package/view/form/elements/alchemy_select_item.hwk +6 -1
  34. package/view/form/elements/query_builder.hwk +1 -0
  35. package/view/form/elements/query_builder_entry.hwk +33 -0
  36. package/view/form/elements/query_builder_group.hwk +64 -0
  37. package/view/form/elements/query_builder_value.hwk +10 -0
  38. package/view/form/elements/query_builder_variable.hwk +6 -0
  39. package/view/form/inputs/edit/belongs_to.hwk +1 -1
  40. package/view/form/inputs/edit/html.hwk +5 -0
  41. package/view/form/inputs/edit/query_builder.hwk +5 -0
  42. package/view/form/inputs/edit/query_builder_assignment.hwk +6 -0
  43. package/view/form/inputs/edit/query_builder_value.hwk +11 -0
  44. package/view/form/inputs/edit/query_builder_variable.hwk +10 -0
  45. package/view/form/inputs/view/string.hwk +1 -0
  46. package/view/form/inputs/view_inline/string.hwk +1 -0
  47. package/view/form/select/qb_item.hwk +7 -0
  48. package/view/form/wrappers/view_inline/default.hwk +1 -0
package/CHANGELOG.md CHANGED
@@ -1,3 +1,32 @@
1
+ ## 0.1.8 (2022-06-29)
2
+
3
+ * Move the `alchemy-select` pagination checker initializer to a static function
4
+ * Prevent `alchemy-select` from keeping on loading remote data when last few results were empty
5
+ * Fix pagination breaking re-opening of `alchemy-select` dropdown
6
+ * Fix initial value of a `BelongsTo` `alchemy-select` element not loading
7
+ * Fix `alchemy-select` downward-arrow-icon being rendered over value content
8
+ * Use `alchemy-code-input` for HTML fields
9
+ * Allow manually setting a value on `alchemy-field` elements
10
+ * Try to let `Field` instances decide the representation of values in `alchemy-table` elements
11
+ * Don't open the `alchemy-table` contextmenu when clicking on anchors
12
+
13
+ ## 0.1.7 (2022-06-12)
14
+
15
+ * Fix `<alchemy-table>` code typo
16
+ * Fix QueryBuilderGroup value being set incorrectly
17
+ * Add `<alchemy-query-builder-value>` element
18
+ * Add `<alchemy-query-builder-variable>` element
19
+ * Add List variable definition, which can contain other variables
20
+
21
+ ## 0.1.6 (2022-05-31)
22
+
23
+ * Fix `FormApi#related` action searching through multiple fields in an `and` group
24
+ * Use microcopy translations in buttons
25
+ * Add `Action` class for user interaction
26
+ * Add context-menu support to `alchemy-table`
27
+ * Add support for using custom templates for `alchemy-select` options
28
+ * Add QueryBuilder
29
+
1
30
  ## 0.1.5 (2022-03-21)
2
31
 
3
32
  * Print `alchemy-select-item` contents as text, not html
@@ -10,4 +10,8 @@ alchemy-field-array-entry {
10
10
  align-content: center;
11
11
  padding-left: 0.5rem;
12
12
  }
13
+
14
+ .button .remove > * {
15
+ writing-mode: vertical-rl;
16
+ }
13
17
  }
@@ -102,7 +102,6 @@ alchemy-select {
102
102
  font-family: inherit;
103
103
  font-size: 13px;
104
104
  line-height: 18px;
105
- -webkit-font-smoothing: inherit;
106
105
  display: inline-block !important;
107
106
  padding: 0 !important;
108
107
  min-height: 0 !important;
@@ -113,11 +112,10 @@ alchemy-select {
113
112
  border: 0 none !important;
114
113
  background: none !important;
115
114
  line-height: inherit !important;
116
- -webkit-user-select: auto !important;
117
- -webkit-box-shadow: none !important;
118
115
  box-shadow: none !important;
119
116
  outline: none !important;
120
117
  flex: 0 1 auto;
118
+ margin-right: 20px !important;
121
119
  }
122
120
 
123
121
  .dropdown {
@@ -34,6 +34,7 @@ alchemy-toggle {
34
34
  height: 36px;
35
35
  flex: 0 0 134px;
36
36
  border-radius: 4px;
37
+ min-width: 134px;
37
38
 
38
39
  transition: background-color 0.3s cubic-bezier(0, 1, 0.5, 1);
39
40
  background: #848484;
@@ -43,6 +44,7 @@ alchemy-toggle {
43
44
  &:after {
44
45
  text-transform: uppercase;
45
46
  text-align: center;
47
+ box-sizing: inherit;
46
48
  }
47
49
 
48
50
  &:before {
@@ -0,0 +1,185 @@
1
+ :root {
2
+ --qb-border-color: #d3d3d3;
3
+ --qb-btn-background-color: #fafafa;
4
+ --qb-text-color: #3e3e3e;
5
+
6
+ --qb-btn-primary: #286090;
7
+ --qb-btn-primary-border: #204d74;
8
+ --qb-btn-primary-text-color: #fafafa;
9
+
10
+ --qb-btn-active: #3da50e;
11
+ --qb-btn-active-text: #fff;
12
+ --qb-btn-border-color: #d3d3d3;
13
+ }
14
+
15
+ alchemy-query-builder {
16
+ display: block;
17
+ border-color: var(--qb-border-color);
18
+ padding: 1rem;
19
+ position: relative;
20
+ }
21
+
22
+ alchemy-query-builder-group {
23
+ display: block;
24
+ padding: 10px;
25
+ padding-bottom: 6px;
26
+ background-color: rgba(250,240,210,.5);
27
+ border: 1px solid #dcc896;
28
+ position: relative;
29
+
30
+
31
+ margin: 4px 0;
32
+ padding: 5px;
33
+ border: 1px solid #eee;
34
+ border-radius: 3px;
35
+
36
+ .qb-group-header {
37
+ margin-bottom: 10px;
38
+ }
39
+
40
+ .qb-group-actions {
41
+ float: right;
42
+ }
43
+
44
+ .qb-group-body {
45
+ .qb-rules-list {
46
+ display: flex;
47
+ flex-flow: column;
48
+ gap: 1rem;
49
+ padding: 0 0 0 15px;
50
+
51
+ & > :first-child::before {
52
+ top: -11px;
53
+ height: calc(50% + 14px);
54
+ }
55
+
56
+ & > :last-child::before {
57
+ border-radius: 0 0 0 4px;
58
+ }
59
+
60
+ & > ::after {
61
+ top: 50%;
62
+ border-width: 0 0 0 2px;
63
+ }
64
+
65
+ & >:last-child::after {
66
+ display: none;
67
+ }
68
+
69
+ > ::before {
70
+ top: -2px;
71
+ border-width: 0 0 2px 2px;
72
+ }
73
+
74
+ > ::before,
75
+ > ::after {
76
+ content: '';
77
+ position: absolute;
78
+ left: -10px;
79
+ width: 10px;
80
+ height: calc(50% + 4px);
81
+ border-color: #ccc;
82
+ border-style: solid;
83
+ }
84
+ }
85
+ }
86
+ }
87
+
88
+ alchemy-query-builder-value {
89
+ min-width: 10rem;
90
+ }
91
+
92
+ alchemy-query-builder-entry {
93
+ min-width: 40rem;
94
+ }
95
+
96
+ alchemy-query-builder-value,
97
+ alchemy-query-builder-entry {
98
+ display: flex;
99
+ gap: 0.7rem;
100
+
101
+ alchemy-select {
102
+ min-width: 11rem;
103
+ }
104
+
105
+ .qb-delete-wrapper {
106
+ flex: 1;
107
+ text-align: right;
108
+ }
109
+
110
+ .qb-value-wrapper {
111
+ display: flex;
112
+ gap: 0.3rem;
113
+ }
114
+
115
+ .qb-value-input {
116
+ height: 100%;
117
+ color: black;
118
+ padding: 0 0.5rem;
119
+ }
120
+ }
121
+
122
+ .qb-group-invert,
123
+ .qb-button-group,
124
+ .qb-group-type {
125
+ display: inline-flex;
126
+ box-shadow: 0 1px 1px -2px rgba(0,0,0,.2),0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12);
127
+ user-select: none;
128
+
129
+ > input {
130
+ height: 1px;
131
+ width: 1px;
132
+ opacity: 0;
133
+ position: absolute;
134
+ margin: 0 0 0 -1px;
135
+ }
136
+
137
+ > input + label {
138
+ opacity: 0.7;
139
+ }
140
+
141
+ > input:checked + label {
142
+ background-color: var(--qb-btn-active);
143
+ border-color: var(--qb-btn-active);
144
+ color: var(--qb-btn-active-text);
145
+ opacity: 1;
146
+ }
147
+ }
148
+
149
+ .qb-primary {
150
+ --qb-btn-background-color: var(--qb-btn-primary);
151
+ --qb-text-color: var(--qb-btn-primary-text-color);
152
+ --qb-btn-border-color: var(--qb-btn-primary-border);
153
+ }
154
+
155
+ button.qb-btn {
156
+ border-color: var(--qb-btn-border-color);
157
+ }
158
+
159
+ .qb-btn {
160
+ background-color: var(--qb-btn-background-color);
161
+ color: var(--qb-text-color);
162
+ transition: box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1);
163
+ border-radius: 2px;
164
+ cursor: pointer;
165
+ display: inline-block;
166
+ font-weight: bold;
167
+ text-align: center;
168
+ padding: 2px 12px 1px;
169
+ }
170
+
171
+ .qb-select-item {
172
+ display: flex;
173
+ flex-flow: column;
174
+ padding-right: 1rem;
175
+
176
+ .option-title {
177
+ font-weight: bold;
178
+ font-size: 1rem;
179
+ white-space: nowrap;
180
+ }
181
+
182
+ .option-description {
183
+ min-width: 10rem;
184
+ }
185
+ }
package/config/routes.js CHANGED
@@ -2,4 +2,12 @@ Router.add({
2
2
  name : 'FormApi#related',
3
3
  methods : 'post',
4
4
  paths : '/api/form/data/related',
5
+ policy : 'logged_in',
6
+ });
7
+
8
+ Router.add({
9
+ name : 'FormApi#queryBuilderData',
10
+ methods : 'post',
11
+ paths : '/api/form/data/qbdata',
12
+ policy : 'logged_in',
5
13
  });
@@ -17,19 +17,23 @@ const FormApi = Function.inherits('Alchemy.Controller', 'FormApi');
17
17
  *
18
18
  * @author Jelle De Loecker <jelle@elevenways.be>
19
19
  * @since 0.1.0
20
- * @version 0.1.5
20
+ * @version 0.1.8
21
21
  *
22
22
  * @param {Conduit} conduit
23
23
  */
24
24
  FormApi.setAction(async function related(conduit) {
25
25
 
26
- const body = conduit.body;
26
+ const body = conduit.body || {},
27
+ config = body.config || {};
27
28
 
28
29
  const model = this.getModel(body.assoc_model);
29
30
  let crit = model.find();
30
31
  crit.limit(50);
32
+ crit.setOption('scenario', 'related_data');
31
33
 
32
- if (body.config && body.config.search) {
34
+ if (config.value) {
35
+ crit.where(model.primary_key).equals(config.value);
36
+ } else if (config.search) {
33
37
  let display_fields = Array.cast(model.displayField);
34
38
 
35
39
  let or = crit.or();
@@ -40,10 +44,14 @@ FormApi.setAction(async function related(conduit) {
40
44
  continue;
41
45
  }
42
46
 
43
- crit.where(field).equals(rx);
47
+ or.where(field).equals(rx);
44
48
  }
45
49
  }
46
50
 
51
+ if (config.page) {
52
+ crit.page(config.page);
53
+ }
54
+
47
55
  let records = await model.find('all', crit);
48
56
 
49
57
  let result = {
@@ -53,3 +61,34 @@ FormApi.setAction(async function related(conduit) {
53
61
 
54
62
  conduit.end(result);
55
63
  });
64
+
65
+
66
+ /**
67
+ * The related action
68
+ *
69
+ * @author Jelle De Loecker <jelle@elevenways.be>
70
+ * @since 0.1.6
71
+ * @version 0.1.6
72
+ *
73
+ * @param {Conduit} conduit
74
+ */
75
+ FormApi.setAction(async function queryBuilderData(conduit) {
76
+
77
+ const body = conduit.body;
78
+ const config = body.config || {};
79
+ let result;
80
+
81
+ if (body && body.model) {
82
+ const model = this.getModel(body.model);
83
+
84
+ if (body.$pk) {
85
+ const doc = await model.findByPk(body.$pk);
86
+
87
+ if (doc) {
88
+ result = await doc.loadQueryBuilderData(config);
89
+ }
90
+ }
91
+ }
92
+
93
+ conduit.end(result);
94
+ });
@@ -0,0 +1,82 @@
1
+ /**
2
+ * The base abstract query builder custom element
3
+ *
4
+ * @author Jelle De Loecker <jelle@elevenways.be>
5
+ * @since 0.1.6
6
+ * @version 0.1.6
7
+ */
8
+ const QueryBuilderBase = Function.inherits('Alchemy.Element.Form.Base', 'QueryBuilderBase');
9
+
10
+ /**
11
+ * Don't register this as a custom element,
12
+ * but don't let child classes inherit this
13
+ *
14
+ * @author Jelle De Loecker <jelle@elevenways.be>
15
+ * @since 0.1.6
16
+ * @version 0.1.6
17
+ */
18
+ QueryBuilderBase.setStatic('is_abstract_class', true, false);
19
+
20
+ /**
21
+ * The stylesheet to load for this element
22
+ *
23
+ * @author Jelle De Loecker <jelle@elevenways.be>
24
+ * @since 0.1.6
25
+ * @version 0.1.6
26
+ */
27
+ QueryBuilderBase.setStylesheetFile('form/query_builder');
28
+
29
+ /**
30
+ * Get the dataprovider
31
+ *
32
+ * @author Jelle De Loecker <jelle@elevenways.be>
33
+ * @since 0.1.6
34
+ * @version 0.1.6
35
+ */
36
+ QueryBuilderBase.enforceProperty(function dataprovider(new_value) {
37
+
38
+ if (new_value == null) {
39
+ if (this.assigned_data.dataprovider) {
40
+ new_value = this.assigned_data.dataprovider;
41
+ } else if (this.root_query_builder && this.root_query_builder.dataprovider) {
42
+ new_value = this.root_query_builder.dataprovider;
43
+ }
44
+ } else {
45
+ this.assigned_data.dataprovider = new_value;
46
+ }
47
+
48
+ return new_value;
49
+ });
50
+
51
+ /**
52
+ * Getter for the rules list element
53
+ *
54
+ * @author Jelle De Loecker <jelle@elevenways.be>
55
+ * @since 0.1.6
56
+ * @version 0.1.6
57
+ */
58
+ QueryBuilderBase.setProperty(function root_query_builder() {
59
+ return this.queryParents('alchemy-query-builder');
60
+ });
61
+
62
+ /**
63
+ * Get the value type of the given input
64
+ *
65
+ * @author Jelle De Loecker <jelle@elevenways.be>
66
+ * @since 0.1.6
67
+ * @version 0.1.6
68
+ *
69
+ * @param {HTMLElement}
70
+ *
71
+ * @return {String}
72
+ */
73
+ QueryBuilderBase.setMethod(function getValueType(element) {
74
+
75
+ if (!element) {
76
+ return null;
77
+ }
78
+
79
+ let result = element.value_type || element.type;
80
+
81
+ return result;
82
+ });
@@ -0,0 +1,139 @@
1
+ /**
2
+ * The base abstract query builder custom element
3
+ *
4
+ * @author Jelle De Loecker <jelle@elevenways.be>
5
+ * @since 0.1.7
6
+ * @version 0.1.7
7
+ */
8
+ const QueryBuilderData = Function.inherits('Alchemy.Element.Form.QueryBuilderBase', 'QueryBuilderData');
9
+
10
+ /**
11
+ * Don't register this as a custom element,
12
+ * but don't let child classes inherit this
13
+ *
14
+ * @author Jelle De Loecker <jelle@elevenways.be>
15
+ * @since 0.1.7
16
+ * @version 0.1.7
17
+ */
18
+ QueryBuilderData.setStatic('is_abstract_class', true, false);
19
+
20
+ /**
21
+ * Check a filter
22
+ *
23
+ * @author Jelle De Loecker <jelle@elevenways.be>
24
+ * @since 0.1.6
25
+ * @version 0.1.7
26
+ */
27
+ QueryBuilderData.setMethod(function checkFilterType(filter_type, entry) {
28
+
29
+ if (!entry) {
30
+ return false;
31
+ }
32
+
33
+ let whitelist = this[filter_type];
34
+
35
+ if (!whitelist) {
36
+ return true;
37
+ }
38
+
39
+ let type = entry.type_name || entry.type || entry.id || entry.name;
40
+
41
+ if (!type) {
42
+ return false;
43
+ }
44
+
45
+ let entries = whitelist.split(',');
46
+
47
+ return entries.indexOf(type) > -1;
48
+ });
49
+
50
+ /**
51
+ * Load data for a specific element
52
+ *
53
+ * @author Jelle De Loecker <jelle@elevenways.be>
54
+ * @since 0.1.6
55
+ * @version 0.1.6
56
+ */
57
+ QueryBuilderData.setMethod(async function loadData(config, element) {
58
+
59
+ if (!element) {
60
+ return;
61
+ }
62
+
63
+ if (!config) {
64
+ config = {};
65
+ }
66
+
67
+ let filter_type,
68
+ result = [],
69
+ items;
70
+
71
+ if (element.classList.contains('qb-source-type')) {
72
+ items = await this.loadSourceTypeData(config);
73
+ filter_type = 'source-types';
74
+ } else if (element.classList.contains('qb-value-variable') || element.classList.contains('qb-variable')) {
75
+ items = await this.loadVariableData(config);
76
+ filter_type = 'variable-types';
77
+ }
78
+
79
+ if (items && items.length) {
80
+
81
+ let entry;
82
+
83
+ for (entry of items) {
84
+ if (!entry) {
85
+ continue;
86
+ }
87
+
88
+ if (filter_type && !this.checkFilterType(filter_type, entry)) {
89
+ continue;
90
+ }
91
+
92
+ result.push(entry);
93
+ }
94
+ }
95
+
96
+ return {
97
+ items: result,
98
+ };
99
+ });
100
+
101
+ /**
102
+ * Load variable data
103
+ *
104
+ * @author Jelle De Loecker <jelle@elevenways.be>
105
+ * @since 0.1.6
106
+ * @version 0.1.7
107
+ */
108
+ QueryBuilderData.setMethod(async function loadVariableData(config) {
109
+
110
+ let dataprovider = this.dataprovider;
111
+
112
+ if (!config) {
113
+ config = {};
114
+ }
115
+
116
+ config.source_type = 'variable';
117
+
118
+ let variables = [];
119
+
120
+ if (dataprovider) {
121
+ variables = await dataprovider.loadData(config, this);
122
+ }
123
+
124
+ let result = [];
125
+
126
+ if (variables && variables.length) {
127
+ let entry;
128
+
129
+ for (entry of variables) {
130
+ if (entry) {
131
+ result.push(entry);
132
+ }
133
+ }
134
+ }
135
+
136
+ console.log('Got loadvariable data:', result);
137
+
138
+ return result;
139
+ });
@@ -133,7 +133,7 @@ Field.enforceProperty(function alchemy_field_schema(new_value, old_value) {
133
133
  *
134
134
  * @author Jelle De Loecker <jelle@elevenways.be>
135
135
  * @since 0.1.0
136
- * @version 0.1.4
136
+ * @version 0.1.8
137
137
  */
138
138
  Field.enforceProperty(function config(new_value, old_value) {
139
139
 
@@ -148,7 +148,7 @@ Field.enforceProperty(function config(new_value, old_value) {
148
148
 
149
149
  if (new_value && new_value.constructor && new_value.constructor.type_name) {
150
150
  this.field_type = new_value.constructor.type_name;
151
- } else {
151
+ } else if (new_value) {
152
152
  this.field_type = null;
153
153
  }
154
154
 
@@ -493,10 +493,14 @@ Field.setProperty(function wrapper_files() {
493
493
  *
494
494
  * @author Jelle De Loecker <jelle@elevenways.be>
495
495
  * @since 0.1.0
496
- * @version 0.1.4
496
+ * @version 0.1.8
497
497
  */
498
498
  Field.setProperty(function original_value() {
499
499
 
500
+ if (this.assigned_data.original_value != null) {
501
+ return this.assigned_data.original_value;
502
+ }
503
+
500
504
  let alchemy_field_schema = this.alchemy_field_schema,
501
505
  path = this.field_path_in_current_schema;
502
506
 
@@ -517,6 +521,8 @@ Field.setProperty(function original_value() {
517
521
  if (form && form.document) {
518
522
  return Object.path(form.document, path);
519
523
  }
524
+ }, function setOriginalValue(value) {
525
+ return this.assigned_data.original_value = value;
520
526
  });
521
527
 
522
528
  /**
@@ -551,7 +557,7 @@ Field.setProperty(function value_element() {
551
557
  *
552
558
  * @author Jelle De Loecker <jelle@elevenways.be>
553
559
  * @since 0.1.0
554
- * @version 0.1.3
560
+ * @version 0.1.8
555
561
  */
556
562
  Field.setProperty(function value() {
557
563
 
@@ -569,8 +575,9 @@ Field.setProperty(function value() {
569
575
 
570
576
  if (element) {
571
577
  element.value = value;
578
+ } else if (this.original_value == null) {
579
+ this.original_value = value;
572
580
  }
573
-
574
581
  });
575
582
 
576
583
  /**
@@ -708,16 +715,33 @@ Field.setMethod(function retained() {
708
715
  *
709
716
  * @author Jelle De Loecker <jelle@elevenways.be>
710
717
  * @since 0.1.0
711
- * @version 0.1.0
718
+ * @version 0.1.6
712
719
  *
713
720
  * @param {Object} config
714
721
  * @param {HTMLElement} element
715
722
  */
716
- Field.setMethod(function loadData(config, element) {
723
+ Field.setMethod(async function loadData(config, element) {
717
724
 
718
725
  let field = this.config;
719
726
 
720
727
  if (field) {
728
+
729
+ let result;
730
+
731
+ if (typeof field.loadData == 'function') {
732
+
733
+ try {
734
+ result = await field.loadData(config, element);
735
+ } catch (err) {
736
+ // Ignore
737
+ console.error('Error loading field data:', err);
738
+ }
739
+
740
+ if (result) {
741
+ return result;
742
+ }
743
+ }
744
+
721
745
  return this.hawkejs_helpers.Alchemy.getResource({
722
746
  name : 'FormApi#related',
723
747
  post : true,