ember-tribe 2.6.11 → 2.7.0
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/README.md
CHANGED
|
@@ -66,7 +66,7 @@ The addon automatically configures following essential packages:
|
|
|
66
66
|
|
|
67
67
|
**Ember Addons:** `ember-cli-dotenv`, `ember-cli-sass`, `ember-modifier`, `ember-composable-helpers`, `ember-truth-helpers`, `ember-file-upload` , `ember-power-select`
|
|
68
68
|
|
|
69
|
-
**NPM Packages:** `bootstrap`, `@popperjs/core`, `animate.css`, `video.js`, `swiper`,
|
|
69
|
+
**NPM Packages:** `bootstrap`, `@popperjs/core`, `animate.css`, `video.js`, `swiper`, `howler`, `sortablejs`, `papaparse`
|
|
70
70
|
|
|
71
71
|
**Built-in features that can be used in routes and components**:
|
|
72
72
|
|
|
@@ -94,7 +94,7 @@ app/
|
|
|
94
94
|
├── services/
|
|
95
95
|
├── styles/app.scss
|
|
96
96
|
└── router.js
|
|
97
|
-
|
|
97
|
+
public/
|
|
98
98
|
└── storylang.json
|
|
99
99
|
installer.sh
|
|
100
100
|
```
|
|
@@ -146,7 +146,7 @@ Always begin by understanding your data types, then define the routes that load
|
|
|
146
146
|
**Types**
|
|
147
147
|
|
|
148
148
|
8. **Start by Understanding Your Data**
|
|
149
|
-
|
|
149
|
+
Before writing any code, read the project description and `types.json` to understand the data model. Every architectural decision that follows — which routes to create, which services to build, whether components are even needed — depends on a clear understanding of the underlying types.
|
|
150
150
|
|
|
151
151
|
---
|
|
152
152
|
|
|
@@ -156,7 +156,7 @@ Always begin by understanding your data types, then define the routes that load
|
|
|
156
156
|
Match route names to user mental models. Use consistent, predictable naming conventions so that routes are self-documenting.
|
|
157
157
|
|
|
158
158
|
10. **Routes Are for Fetching, Not Logic**
|
|
159
|
-
|
|
159
|
+
Routes should primarily perform read/fetch operations and pass data down to components or services. Keep JavaScript in routes to a minimum — business logic belongs in components and services, not routes.
|
|
160
160
|
|
|
161
161
|
11. **Route Parameters**
|
|
162
162
|
Keep `get_vars` minimal and meaningful. Load only the data types that each specific route actually needs — avoid over-fetching.
|
|
@@ -217,7 +217,7 @@ Always begin by understanding your data types, then define the routes that load
|
|
|
217
217
|
|
|
218
218
|
### Storylang CLI
|
|
219
219
|
|
|
220
|
-
ember-tribe ships with a command-line tool called `storylang` that synchronises the `
|
|
220
|
+
ember-tribe ships with a command-line tool called `storylang` that synchronises the `public/storylang.json` specification with the actual Ember project files.
|
|
221
221
|
|
|
222
222
|
#### Usage
|
|
223
223
|
|
|
@@ -225,7 +225,7 @@ ember-tribe ships with a command-line tool called `storylang` that synchronises
|
|
|
225
225
|
node storylang
|
|
226
226
|
```
|
|
227
227
|
|
|
228
|
-
Scans the current Ember project and writes/updates `
|
|
228
|
+
Scans the current Ember project and writes/updates `public/storylang.json` from the actual files that exist in the `app/` directory.
|
|
229
229
|
|
|
230
230
|
**Example:**
|
|
231
231
|
|
|
@@ -233,12 +233,12 @@ Scans the current Ember project and writes/updates `config/storylang.json` from
|
|
|
233
233
|
cd /path/to/ember/app
|
|
234
234
|
|
|
235
235
|
node storylang
|
|
236
|
-
# =>
|
|
236
|
+
# => public/storylang.json updated from project files
|
|
237
237
|
```
|
|
238
238
|
|
|
239
239
|
#### Typical Workflow
|
|
240
240
|
|
|
241
|
-
Run `node storylang` periodically to keep `
|
|
241
|
+
Run `node storylang` periodically to keep `public/storylang.json` in sync as the project evolves.
|
|
242
242
|
|
|
243
243
|
---
|
|
244
244
|
|
|
@@ -246,7 +246,7 @@ Run `node storylang` periodically to keep `config/storylang.json` in sync as the
|
|
|
246
246
|
|
|
247
247
|
#### Overview
|
|
248
248
|
|
|
249
|
-
Storylang.json is a structured configuration file used in the ember-tribe ecosystem to define the frontend implementation of your application. It is found at `
|
|
249
|
+
Storylang.json is a structured configuration file used in the ember-tribe ecosystem to define the frontend implementation of your application. It is found at `public/storylang.json`. It works in conjunction with your `types.json` (which defines your data types) to create a complete frontend specification.
|
|
250
250
|
|
|
251
251
|
#### Purpose
|
|
252
252
|
|
|
@@ -270,7 +270,6 @@ The storylang.json file contains seven main sections:
|
|
|
270
270
|
}
|
|
271
271
|
```
|
|
272
272
|
|
|
273
|
-
|
|
274
273
|
#### Section Definitions
|
|
275
274
|
|
|
276
275
|
#### 1. Types
|
|
@@ -284,7 +283,8 @@ The storylang.json file contains seven main sections:
|
|
|
284
283
|
"types": [
|
|
285
284
|
{
|
|
286
285
|
"slug": "type-slug", //type slug as defined in `types.json` blueprint
|
|
287
|
-
"used_in": {
|
|
286
|
+
"used_in": {
|
|
287
|
+
//where this type is used
|
|
288
288
|
"routes": ["route-name"],
|
|
289
289
|
"components": ["component-name"],
|
|
290
290
|
"services": ["service-name"],
|
|
@@ -314,7 +314,10 @@ The storylang.json file contains seven main sections:
|
|
|
314
314
|
"tracked_vars": [{ "<variableName>": "<dataType>" }],
|
|
315
315
|
"get_vars": [{ "<paramName>": "<dataType>" }],
|
|
316
316
|
"getters": ["derived-property-name"],
|
|
317
|
-
"actions": [
|
|
317
|
+
"actions": [
|
|
318
|
+
"frontend-action",
|
|
319
|
+
{ "backend-action": ["custom/path/file.php"] }
|
|
320
|
+
],
|
|
318
321
|
"functions": ["helper-method", "compute-something"],
|
|
319
322
|
"helpers": ["helper1"],
|
|
320
323
|
"services": ["service1"],
|
|
@@ -426,7 +429,10 @@ The storylang.json file contains seven main sections:
|
|
|
426
429
|
"name": "service-name",
|
|
427
430
|
"tracked_vars": [{ "<variableName>": "<dataType>" }],
|
|
428
431
|
"getters": ["derived-property-name"],
|
|
429
|
-
"actions": [
|
|
432
|
+
"actions": [
|
|
433
|
+
"frontend-action",
|
|
434
|
+
{ "backend-action": ["custom/path/file.php"] }
|
|
435
|
+
],
|
|
430
436
|
"functions": ["internal-method"],
|
|
431
437
|
"helpers": ["helper1"],
|
|
432
438
|
"services": ["dependency1", "dependency2"]
|
|
@@ -449,7 +455,11 @@ The storylang.json file contains seven main sections:
|
|
|
449
455
|
"functions": ["build-visualization"],
|
|
450
456
|
"actions": [
|
|
451
457
|
"reset-state",
|
|
452
|
-
{
|
|
458
|
+
{
|
|
459
|
+
"assemble-data-for-visualization": [
|
|
460
|
+
"custom/visualizations/assemble-data.php"
|
|
461
|
+
]
|
|
462
|
+
},
|
|
453
463
|
"updateVisualization"
|
|
454
464
|
],
|
|
455
465
|
"helpers": ["validateConfig", "generatePreview"],
|
|
@@ -476,7 +486,10 @@ The storylang.json file contains seven main sections:
|
|
|
476
486
|
"tracked_vars": [{ "<variableName>": "<dataType>" }],
|
|
477
487
|
"inherited_args": [{ "<argumentName>": "<argType>" }],
|
|
478
488
|
"getters": ["derived-property-name"],
|
|
479
|
-
"actions": [
|
|
489
|
+
"actions": [
|
|
490
|
+
"frontend-action",
|
|
491
|
+
{ "backend-action": ["custom/path/file.php"] }
|
|
492
|
+
],
|
|
480
493
|
"functions": ["internal-method"],
|
|
481
494
|
"helpers": ["helper1", "helper2"],
|
|
482
495
|
"modifiers": ["modifier1"],
|
|
@@ -486,7 +499,6 @@ The storylang.json file contains seven main sections:
|
|
|
486
499
|
}
|
|
487
500
|
```
|
|
488
501
|
|
|
489
|
-
|
|
490
502
|
**Example**:
|
|
491
503
|
|
|
492
504
|
```json
|
|
@@ -502,7 +514,12 @@ The storylang.json file contains seven main sections:
|
|
|
502
514
|
{ "onDelete": "action" }
|
|
503
515
|
],
|
|
504
516
|
"getters": ["trust-score-color", "display-label"],
|
|
505
|
-
"actions": [
|
|
517
|
+
"actions": [
|
|
518
|
+
"toggle-selection",
|
|
519
|
+
"expand-details",
|
|
520
|
+
{ "save-file": ["custom/files/save.php"] },
|
|
521
|
+
{ "delete-file": ["custom/files/delete.php"] }
|
|
522
|
+
],
|
|
506
523
|
"helpers": ["formatDate", "truncateText"],
|
|
507
524
|
"modifiers": ["tooltip"],
|
|
508
525
|
"services": ["store", "router"]
|
|
@@ -681,7 +698,7 @@ When querying records, `modules` and `filter` serve distinct purposes that map d
|
|
|
681
698
|
|
|
682
699
|
**`modules`** applies **AND** logic: every key-value pair in the object must match for a record to be included. Use this when you want to narrow results to records that simultaneously satisfy all of the given conditions — for example, posts that are both `published` and belong to a specific `author_id`.
|
|
683
700
|
|
|
684
|
-
**`filter`** applies **OR** logic: a record is included if it matches
|
|
701
|
+
**`filter`** applies **OR** logic: a record is included if it matches _any_ of the key-value pairs. Use this when you want to broaden results across multiple values of a field — for example, items whose `category` is either `tech` or `design`.
|
|
685
702
|
|
|
686
703
|
The two can be combined in the same query. For instance, to find all published posts that are tagged as either `news` or `feature`:
|
|
687
704
|
|
|
@@ -990,11 +1007,17 @@ import Service from '@ember/service';
|
|
|
990
1007
|
export default class ShoppingCartService extends Service {
|
|
991
1008
|
items = new TrackedArray([]);
|
|
992
1009
|
|
|
993
|
-
add(item) {
|
|
1010
|
+
add(item) {
|
|
1011
|
+
this.items.push(item);
|
|
1012
|
+
}
|
|
994
1013
|
|
|
995
|
-
remove(item) {
|
|
1014
|
+
remove(item) {
|
|
1015
|
+
this.items.splice(this.items.indexOf(item), 1);
|
|
1016
|
+
}
|
|
996
1017
|
|
|
997
|
-
empty() {
|
|
1018
|
+
empty() {
|
|
1019
|
+
this.items.splice(0, this.items.length);
|
|
1020
|
+
}
|
|
998
1021
|
}
|
|
999
1022
|
```
|
|
1000
1023
|
|
|
@@ -1109,16 +1132,16 @@ async uploadFile(file) {
|
|
|
1109
1132
|
Use Ember's built-in `<Input>` component instead of a raw `<input>` tag — it automatically updates bound state via `@value`.
|
|
1110
1133
|
|
|
1111
1134
|
```handlebars
|
|
1112
|
-
<div class=
|
|
1113
|
-
<label for=
|
|
1135
|
+
<div class='mb-3'>
|
|
1136
|
+
<label for='input-name' class='form-label'>Name:</label>
|
|
1114
1137
|
<Input
|
|
1115
|
-
id=
|
|
1116
|
-
class=
|
|
1117
|
-
@type=
|
|
1138
|
+
id='input-name'
|
|
1139
|
+
class='form-control'
|
|
1140
|
+
@type='text'
|
|
1118
1141
|
@value={{this.name}}
|
|
1119
1142
|
disabled={{this.isReadOnly}}
|
|
1120
|
-
maxlength=
|
|
1121
|
-
placeholder=
|
|
1143
|
+
maxlength='50'
|
|
1144
|
+
placeholder='Enter your name'
|
|
1122
1145
|
/>
|
|
1123
1146
|
</div>
|
|
1124
1147
|
```
|
|
@@ -1134,31 +1157,32 @@ export default class ExampleComponent extends Component {
|
|
|
1134
1157
|
```
|
|
1135
1158
|
|
|
1136
1159
|
```handlebars
|
|
1137
|
-
<div class=
|
|
1160
|
+
<div class='form-check mb-3'>
|
|
1138
1161
|
<Input
|
|
1139
|
-
id=
|
|
1140
|
-
class=
|
|
1141
|
-
@type=
|
|
1162
|
+
id='admin-checkbox'
|
|
1163
|
+
class='form-check-input'
|
|
1164
|
+
@type='checkbox'
|
|
1142
1165
|
@checked={{this.isAdmin}}
|
|
1143
|
-
{{on
|
|
1166
|
+
{{on 'input' this.validateRole}}
|
|
1144
1167
|
/>
|
|
1145
|
-
<label for=
|
|
1168
|
+
<label for='admin-checkbox' class='form-check-label'>Is Admin?</label>
|
|
1146
1169
|
</div>
|
|
1147
1170
|
```
|
|
1148
1171
|
|
|
1149
1172
|
```handlebars
|
|
1150
|
-
<div class=
|
|
1151
|
-
<label for=
|
|
1173
|
+
<div class='mb-3'>
|
|
1174
|
+
<label for='user-comment' class='form-label'>Comment:</label>
|
|
1152
1175
|
<Textarea
|
|
1153
|
-
id=
|
|
1154
|
-
class=
|
|
1176
|
+
id='user-comment'
|
|
1177
|
+
class='form-control'
|
|
1155
1178
|
@value={{this.userComment}}
|
|
1156
|
-
rows=
|
|
1179
|
+
rows='6'
|
|
1157
1180
|
/>
|
|
1158
1181
|
</div>
|
|
1159
1182
|
```
|
|
1160
1183
|
|
|
1161
1184
|
**Key rules for `<Input>` and `<Textarea>`:**
|
|
1185
|
+
|
|
1162
1186
|
- `@value`, `@type`, and `@checked` must be passed as **arguments** (with `@`).
|
|
1163
1187
|
- Use the `{{on}}` modifier for event handling (e.g. `{{on "input" this.handler}}`).
|
|
1164
1188
|
- Bootstrap styles `form-control` correctly when `disabled` is present
|
|
@@ -1170,14 +1194,14 @@ export default class ExampleComponent extends Component {
|
|
|
1170
1194
|
**Single select (Bootstrap-compatible wrapper):**
|
|
1171
1195
|
|
|
1172
1196
|
```handlebars
|
|
1173
|
-
<div class=
|
|
1174
|
-
<label class=
|
|
1175
|
-
<div class=
|
|
1197
|
+
<div class='mb-3'>
|
|
1198
|
+
<label class='form-label'>Assign Category:</label>
|
|
1199
|
+
<div class='form-control p-0 border-0'>
|
|
1176
1200
|
<PowerSelect
|
|
1177
1201
|
@options={{this.categories}}
|
|
1178
1202
|
@selected={{this.selectedCategory}}
|
|
1179
1203
|
@onChange={{this.handleCategoryChange}}
|
|
1180
|
-
@placeholder=
|
|
1204
|
+
@placeholder='Select a category'
|
|
1181
1205
|
as |category|
|
|
1182
1206
|
>
|
|
1183
1207
|
{{category.name}}
|
|
@@ -1210,14 +1234,14 @@ export default class ExampleComponent extends Component {
|
|
|
1210
1234
|
**Multi-select variant:**
|
|
1211
1235
|
|
|
1212
1236
|
```handlebars
|
|
1213
|
-
<div class=
|
|
1214
|
-
<label class=
|
|
1215
|
-
<div class=
|
|
1237
|
+
<div class='mb-3'>
|
|
1238
|
+
<label class='form-label'>Assign Tags:</label>
|
|
1239
|
+
<div class='form-control p-0 border-0'>
|
|
1216
1240
|
<PowerSelectMultiple
|
|
1217
1241
|
@options={{this.availableTags}}
|
|
1218
1242
|
@selected={{this.selectedTags}}
|
|
1219
1243
|
@onChange={{this.handleTagsChange}}
|
|
1220
|
-
@placeholder=
|
|
1244
|
+
@placeholder='Select tags'
|
|
1221
1245
|
as |tag|
|
|
1222
1246
|
>
|
|
1223
1247
|
{{tag.label}}
|
|
@@ -1229,15 +1253,15 @@ export default class ExampleComponent extends Component {
|
|
|
1229
1253
|
**Async options loaded from the store:**
|
|
1230
1254
|
|
|
1231
1255
|
```handlebars
|
|
1232
|
-
<div class=
|
|
1233
|
-
<label class=
|
|
1234
|
-
<div class=
|
|
1256
|
+
<div class='mb-3'>
|
|
1257
|
+
<label class='form-label'>Select Project:</label>
|
|
1258
|
+
<div class='form-control p-0 border-0'>
|
|
1235
1259
|
<PowerSelect
|
|
1236
1260
|
@options={{this.projects}}
|
|
1237
1261
|
@selected={{this.selectedProject}}
|
|
1238
1262
|
@onChange={{this.handleProjectChange}}
|
|
1239
|
-
@searchField=
|
|
1240
|
-
@placeholder=
|
|
1263
|
+
@searchField='name'
|
|
1264
|
+
@placeholder='Search projects...'
|
|
1241
1265
|
as |project|
|
|
1242
1266
|
>
|
|
1243
1267
|
{{project.modules.name}}
|
|
@@ -1247,6 +1271,7 @@ export default class ExampleComponent extends Component {
|
|
|
1247
1271
|
```
|
|
1248
1272
|
|
|
1249
1273
|
**Key rules for `<PowerSelect>`:**
|
|
1274
|
+
|
|
1250
1275
|
- `@options`, `@selected`, and `@onChange` are always required arguments.
|
|
1251
1276
|
- Use `@searchField` to specify which object property drives the built-in search filter.
|
|
1252
1277
|
- For multi-select, use `<PowerSelectMultiple>` — the `@onChange` callback receives the full updated array, so assign it directly to your tracked property.
|
|
@@ -1270,4 +1295,4 @@ You can then upload the `dist/` folder to [Junction (open source)](http://localh
|
|
|
1270
1295
|
|
|
1271
1296
|
# License
|
|
1272
1297
|
|
|
1273
|
-
This project is licensed under the [GNU GPL v3 License](LICENSE.md).
|
|
1298
|
+
This project is licensed under the [GNU GPL v3 License](LICENSE.md).
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "<%=
|
|
2
|
+
"name": "<%= dasherizedPackageName %>",
|
|
3
3
|
"version": "0.0.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
|
-
"name": "<%=
|
|
8
|
+
"name": "<%= dasherizedPackageName %>",
|
|
9
9
|
"version": "0.0.0",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ember-tribe",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.0",
|
|
4
4
|
"description": "The default blueprint for using Tribe API and Junction within EmberJS.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ember-addon"
|
|
@@ -83,4 +83,4 @@
|
|
|
83
83
|
"ember-addon": {
|
|
84
84
|
"configPath": "tests/dummy/config"
|
|
85
85
|
}
|
|
86
|
-
}
|
|
86
|
+
}
|