@iebh/tera-fy 1.12.0 → 1.13.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.
@@ -27,6 +27,7 @@ export default class TeraFy {
27
27
  * @property {Array<String>} List of sandbox allowables for the embedded if in embed mode
28
28
  * @property {Number} handshakeInterval Interval in milliseconds when sanning for a handshake
29
29
  * @property {Number} handshakeTimeout Interval in milliseconds for when to give up trying to handshake
30
+ * @property {Array<String|Array<String>>} [debugPaths] List of paths (in either dotted or array notation) to enter debugging mode if a change is detected in dev mode e.g. `{debugPaths: ['foo.bar.baz']}`. This really slows down state writes so should only be used for debugging
30
31
  */
31
32
  settings = {
32
33
  devMode: true,
@@ -50,6 +51,7 @@ export default class TeraFy {
50
51
  ],
51
52
  handshakeInterval: 1000, // ~1s
52
53
  handshakeTimeout: 10000, // ~10s
54
+ debugPaths: null, // Transformed into a Array<String> (in Lodash dotted notation) on init()
53
55
  };
54
56
 
55
57
 
@@ -108,7 +110,7 @@ export default class TeraFy {
108
110
  'setProjectStateRefresh',
109
111
  'saveProjectState',
110
112
  'replaceProjectState',
111
- 'applyProjectStatePatch',
113
+ // 'applyProjectStatePatch', - Handled below (applies behaviour to watch for `settings.debugPaths`)
112
114
  // For bindProjectState() - See individual plugins
113
115
 
114
116
  // Project files
@@ -134,7 +136,10 @@ export default class TeraFy {
134
136
 
135
137
  // UI
136
138
  'uiAlert',
139
+ 'uiConfirm',
137
140
  'uiProgress',
141
+ 'uiPrompt',
142
+ 'uiTrhow',
138
143
  'uiSplat',
139
144
  'uiWindow',
140
145
  ];
@@ -299,6 +304,26 @@ export default class TeraFy {
299
304
  }
300
305
 
301
306
 
307
+ applyProjectStatePatch(patch) {
308
+ if (this.settings.devMode && this.settings.debugPaths) {
309
+ if (!Array.isArray(this.settings.debugPaths)) throw new Error('teraFyClient.settings.debugPaths should be either null or an Array<String>');
310
+
311
+ let watchedPaths = patch
312
+ .filter(patch => this.settings.debugPaths.some(debugPath =>
313
+ patch.path.join('.').slice(0, debugPath.length) == debugPath
314
+ ))
315
+ .map(patch => patch.path.join('.'));
316
+
317
+ if (watchedPaths.length > 0) {
318
+ console.info('Detected writes to', watchedPaths, '- entering debugging mode');
319
+ debugger;
320
+ }
321
+ }
322
+
323
+ return this.rpc('applyProjectStatePatch', patch);
324
+ }
325
+
326
+
302
327
  /**
303
328
  * Client function which accepts a patch from the server and applies it to local project state
304
329
  * The patch should follow the [JSPatch](http://jsonpatch.com) standard
@@ -340,7 +365,20 @@ export default class TeraFy {
340
365
 
341
366
  const context = this;
342
367
  return this.init.promise = Promise.resolve()
343
- .then(()=> this.debug('INFO', 4, '[0/6] Init using server', this.settings.siteUrl))
368
+ .then(()=> this.debug('INFO', 4, '[0/6] Init', this.settings.siteUrl))
369
+ .then(()=> { // Init various options for optimized access
370
+ if (!this.settings.devMode) return; // Not in dev mode
371
+ this.settings.debugPaths =
372
+ !this.settings.debugPaths ? null // Falsy - disable
373
+ : Array.isArray(this.settings.debugPaths) ? this.settings.debugPaths.map(path =>
374
+ Array.isArray(path) ? path.join('.') // Transform arrays into dotted notation
375
+ : typeof path == 'string' ? path // Assume already in dotted notation
376
+ : (()=> { throw new Error('Unknown path type - should be an array or string in dotted notation') })()
377
+ )
378
+ : (()=> { throw new Error('Unknown terafyClient.settings.debugPaths type') })()
379
+
380
+ this.debug('INFO', 0, 'Watching state paths', this.settings.debugPaths);
381
+ })
344
382
  .then(()=> this.detectMode())
345
383
  .then(mode => {
346
384
  this.debug('INFO', 4, '[1/6] Setting client mode to', mode);
@@ -480,7 +518,10 @@ export default class TeraFy {
480
518
  let handshakeCount = 0;
481
519
  let handshakeTimer;
482
520
 
483
- let handshakeTimeout = setTimeout(()=> reject('TIMEOUT'), settings.handshakeTimeout);
521
+ let handshakeTimeout = setTimeout(()=> {
522
+ clearTimeout(handshakeTimer);
523
+ reject('TIMEOUT');
524
+ }, settings.handshakeTimeout);
484
525
 
485
526
  const tryHandshake = ()=> {
486
527
  this.debug('INFO', 4, 'Trying handshake', ++handshakeCount);
@@ -524,8 +565,8 @@ export default class TeraFy {
524
565
  'height: 150px;',
525
566
  'background: transparent;',
526
567
 
527
- // Minimize / deminimize functionality {{{
528
- '&.minimized.dev-mode {',
568
+ // Minimize / de-minimize functionality {{{
569
+ 'body:not(.tera-fy-focus) &.minimized.dev-mode {',
529
570
  'background: var(--TERA-accent) !important;',
530
571
  'opacity: 0.5;',
531
572
  'right: 0px;',
@@ -560,7 +601,7 @@ export default class TeraFy {
560
601
  '}',
561
602
  '}',
562
603
 
563
- '&:not(.minimized) {',
604
+ 'body:not(.tera-fy-focus) &:not(.minimized) {',
564
605
  '&::before {',
565
606
  'display: flex;',
566
607
  'align-items: center;',
@@ -1266,6 +1307,20 @@ export default class TeraFy {
1266
1307
  */
1267
1308
 
1268
1309
 
1310
+ /**
1311
+ * Present a simple ok/cancel dialog to the user
1312
+ *
1313
+ * @function uiConfirm
1314
+ * @param {String} text The text to display
1315
+ *
1316
+ * @param {Object} [options] Additional options to mutate behaviour
1317
+ * @param {String} [options.title='TERA'] The title of the confirmation box
1318
+ * @param {Boolean} [options.isHtml=false] If falsy the text is rendered as plain-text otherwise it will be assumed as HTML content
1319
+ *
1320
+ * @returns {Promise} A promise which resolves with `Promise.resolve('OK')` or rejects with `Promise.reject('CANCEL')`
1321
+ */
1322
+
1323
+
1269
1324
  /**
1270
1325
  * Display, update or dispose of windows for long running tasks
1271
1326
  * All options are cumulative - i.e. they are merged with other options previously provided
@@ -1284,6 +1339,31 @@ export default class TeraFy {
1284
1339
  */
1285
1340
 
1286
1341
 
1342
+ /**
1343
+ * Prompt the user for an input, responding with a Promisable value
1344
+ *
1345
+ * @function uiPrompt
1346
+ * @param {Object} [options] Additional options to mutate behaviour
1347
+ * @param {String} [options.value] Current or default value to display pre-filled
1348
+ * @param {String} [options.title='Input required'] The dialog title to display
1349
+ * @param {String} [options.body] Optional additional body text
1350
+ * @param {Boolean} [options.bodyHtml=false] If truthy, treat the body as HTML
1351
+ * @param {String} [options.placeholder] Optional placeholder text
1352
+ *
1353
+ * @returns {Promise<*>} Either the eventual user value or a throw with `Promise.reject('CANCEL')`
1354
+ */
1355
+
1356
+
1357
+ /**
1358
+ * Catch an error using the TERA error handler
1359
+ *
1360
+ * @function uiThrow
1361
+ * @param {Error|Object|String} error Error to handle, generally an Error object but can be a POJO or a scalar string
1362
+ *
1363
+ * @returns {Void} This function is fatal
1364
+ */
1365
+
1366
+
1287
1367
  /**
1288
1368
  * Open a popup window containing a new site
1289
1369
  *
@@ -1427,7 +1427,7 @@ export default class TeraFyServer {
1427
1427
  }
1428
1428
  // }}}
1429
1429
 
1430
- // UI - uiAlert(), uiProgress(), uiWindow(), uiSplat() {{{
1430
+ // UI - uiAlert(), uiConfirm(), uiProgress(), uiPrompt(), uiThrow(), uiWindow(), uiSplat() {{{
1431
1431
  /**
1432
1432
  * Display simple text within TERA
1433
1433
  *
@@ -1462,6 +1462,48 @@ export default class TeraFyServer {
1462
1462
  }
1463
1463
 
1464
1464
 
1465
+ /**
1466
+ * Present a simple ok/cancel dialog to the user
1467
+ *
1468
+ * @param {String} text The text to display
1469
+ *
1470
+ * @param {Object} [options] Additional options to mutate behaviour
1471
+ * @param {String} [options.title='TERA'] The title of the confirmation box
1472
+ * @param {Boolean} [options.isHtml=false] If falsy the text is rendered as plain-text otherwise it will be assumed as HTML content
1473
+ *
1474
+ * @returns {Promise} A promise which resolves with `Promise.resolve('OK')` or rejects with `Promise.reject('CANCEL')`
1475
+ */
1476
+ uiConfirm(text, options) {
1477
+ let settings = {
1478
+ title: 'TERA',
1479
+ isHtml: false,
1480
+ ...options,
1481
+ };
1482
+
1483
+ return this.requestFocus(()=>
1484
+ app.service('$prompt').dialog({
1485
+ title: settings.title,
1486
+ body: text,
1487
+ isHtml: settings.isHtml,
1488
+ buttons: [
1489
+ {
1490
+ title: 'OK',
1491
+ class: 'btn btn-success',
1492
+ click: 'resolve',
1493
+ },
1494
+ {
1495
+ title: 'Cancel',
1496
+ class: 'btn btn-danger',
1497
+ click: 'reject',
1498
+ },
1499
+ ],
1500
+ })
1501
+ .then(()=> 'OK')
1502
+ .catch(()=> Promise.reject('CANCEL'))
1503
+ );
1504
+ }
1505
+
1506
+
1465
1507
  /**
1466
1508
  * Display, update or dispose of windows for long running tasks
1467
1509
  * All options are cumulative - i.e. they are merged with other options previously provided
@@ -1517,6 +1559,60 @@ export default class TeraFyServer {
1517
1559
  uiProgressPromise;
1518
1560
 
1519
1561
 
1562
+ /**
1563
+ * Prompt the user for an input, responding with a Promisable value
1564
+ *
1565
+ * @param {Object} [options] Additional options to mutate behaviour
1566
+ * @param {String} [options.value] Current or default value to display pre-filled
1567
+ * @param {String} [options.title='Input required'] The dialog title to display
1568
+ * @param {String} [options.body] Optional additional body text
1569
+ * @param {Boolean} [options.bodyHtml=false] If truthy, treat the body as HTML
1570
+ * @param {String} [options.placeholder] Optional placeholder text
1571
+ *
1572
+ * @returns {Promise<*>} Either the eventual user value or a throw with `Promise.reject('CANCEL')`
1573
+ */
1574
+ uiPrompt(options) {
1575
+ let settings = {
1576
+ title: 'Input required',
1577
+ value: '',
1578
+ body: '',
1579
+ bodyHtml: false,
1580
+ placeholder: '',
1581
+ ...options,
1582
+ };
1583
+
1584
+ return this.requestFocus(()=>
1585
+ app.service('$prompt').dialog({
1586
+ title: settings.title,
1587
+ closable: true,
1588
+ component: 'UiPrompt',
1589
+ componentProps: {
1590
+ body: settings.body,
1591
+ bodyHtml: settings.bodyHtml,
1592
+ placeholder: settings.placeholder,
1593
+ value: settings.valuie,
1594
+ },
1595
+ buttons: ['ok', 'cancel'],
1596
+ })
1597
+ )
1598
+ .then(answer => answer || Promise.reject('CANCEL'))
1599
+ }
1600
+
1601
+
1602
+ /**
1603
+ * Catch an error using the TERA error handler
1604
+ *
1605
+ * @param {Error|Object|String} error Error to handle, generally an Error object but can be a POJO or a scalar string
1606
+ *
1607
+ * @returns {Void} This function is fatal
1608
+ */
1609
+ uiThrow(error) {
1610
+ return this.requestFocus(()=>
1611
+ app.service('$errors').catch(error)
1612
+ );
1613
+ }
1614
+
1615
+
1520
1616
  /**
1521
1617
  * Open a popup window containing a new site
1522
1618
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iebh/tera-fy",
3
- "version": "1.12.0",
3
+ "version": "1.13.0",
4
4
  "description": "TERA website worker",
5
5
  "scripts": {
6
6
  "dev": "esbuild --platform=browser --format=esm --bundle lib/terafy.client.js --outfile=dist/terafy.js --minify --serve --servedir=.",
@@ -70,20 +70,21 @@
70
70
  },
71
71
  "dependencies": {
72
72
  "detect-port": "^1.6.1",
73
- "filesize": "^10.1.1",
73
+ "filesize": "^10.1.4",
74
74
  "http-proxy": "^1.18.1",
75
75
  "just-diff": "^6.0.2",
76
76
  "lodash-es": "^4.17.21",
77
77
  "mitt": "^3.0.1",
78
- "nanoid": "^5.0.2",
79
- "release-it": "^17.4.0"
78
+ "nanoid": "^5.0.7",
79
+ "release-it": "^17.5.0"
80
80
  },
81
81
  "devDependencies": {
82
- "@momsfriendlydevco/eslint-config": "^1.0.7",
82
+ "@momsfriendlydevco/eslint-config": "^2.0.1",
83
83
  "@release-it/conventional-changelog": "^8.0.1",
84
84
  "concurrently": "^8.2.2",
85
- "documentation": "^14.0.2",
86
- "esbuild": "^0.19.5"
85
+ "documentation": "^14.0.3",
86
+ "esbuild": "^0.23.0",
87
+ "eslint": "^9.6.0"
87
88
  },
88
89
  "peerDependencies": {
89
90
  "vue": "^3.0.0"
@@ -93,17 +94,6 @@
93
94
  "just-diff-apply": "^5.5.0",
94
95
  "vue": "^3.3.7"
95
96
  },
96
- "eslintConfig": {
97
- "extends": "@momsfriendlydevco",
98
- "env": {
99
- "es6": true,
100
- "node": true
101
- },
102
- "parserOptions": {
103
- "ecmaVersion": 13,
104
- "sourceType": "module"
105
- }
106
- },
107
97
  "release-it": {
108
98
  "git": {
109
99
  "addUntrackedFiles": false,