@iebh/tera-fy 1.4.4 → 1.6.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.
@@ -757,10 +757,15 @@ export default class TeraFyServer {
757
757
  * @param {String|Array<String>} [path] The sub-path within the project state to set, if unspecifed the entire target is used as a target and a save operation is forced
758
758
  * @param {*} value The value to set as the default structure
759
759
  * @param {Object} [options] Additional options to mutate behaviour, see setProjectState() for the full list of supported options
760
+ * @param {Boolean} [options.flush=true] Force a re-read from the server after setting, prevents race conditions with large objects. Calls `setProjectStateFlush()` after applying defaults
760
761
  *
761
762
  * @returns {Promise<*>} A promise which resolves to the eventual input value after defaults have been applied
762
763
  */
763
764
  setProjectStateDefaults(path, value, options) {
765
+ let settings = {
766
+ flush: true,
767
+ ...options,
768
+ };
764
769
  if (!app.service('$projects').active) throw new Error('No active project');
765
770
 
766
771
  let target = app.service('$projects').active;
@@ -771,18 +776,52 @@ export default class TeraFyServer {
771
776
  value,
772
777
  {
773
778
  strategy: 'defaults',
774
- ...options,
779
+ ...settings,
775
780
  },
776
781
  )
782
+ .then(()=> settings.flush && this.setProjectStateFlush())
777
783
  .then(()=> pathTools.get(target, path));
778
784
  } else { // Called as (value) - Populate entire project layout
779
785
  pathTools.defaults(target, path);
786
+ this.debug('INFO', 1, 'setProjectStateDefaults', {
787
+ defaults: path,
788
+ newState: cloneDeep(target),
789
+ });
780
790
  return this.saveProjectState()
791
+ .then(()=> settings.flush && this.setProjectStateFlush())
781
792
  .then(()=> target);
782
793
  }
783
794
  }
784
795
 
785
796
 
797
+ /**
798
+ * Force copying local changes to the server
799
+ * This is only ever needed when saving large quantities of data that need to be immediately available
800
+ *
801
+ * @returns {Promise} A promise which resolves when the operation has completed
802
+ */
803
+ setProjectStateFlush() {
804
+ this.debug('INFO', 1, 'Force project state flush!');
805
+ if (!app.service('$projects').active) throw new Error('No active project');
806
+ return app.service('$projects').active.$touchLocal()
807
+ .then(()=> null)
808
+ }
809
+
810
+
811
+ /**
812
+ * Force refetching the remote project state into local
813
+ *
814
+ * @returns {Promise} A promise which resolves when the operation has completed
815
+ */
816
+ setProjectStateRefresh() {
817
+ this.debug('INFO', 1, 'Force project state refresh!');
818
+ if (!app.service('$projects').active) throw new Error('No active project');
819
+ return app.service('$projects').active.$read({force: true})
820
+ .then(()=> this.debug('INFO', 2, 'Forced project state refresh!', {state: app.service('$projects').active}))
821
+ .then(()=> null)
822
+ }
823
+
824
+
786
825
  /**
787
826
  * Force-Save the currently active project state
788
827
  *
@@ -1192,10 +1231,28 @@ export default class TeraFyServer {
1192
1231
  * @param {String} url The URL to restore on next refresh
1193
1232
  */
1194
1233
  setPageUrl(url) {
1195
- debugger; // FIXME: Untested
1196
- console.info('FIXME: Unsupported setPageUrl(', url, ')');
1234
+ if (!url.startsWith('/')) throw new Error('All pageURLs must be a relative path starting with a slash');
1235
+
1236
+ let $routeMatched = app.service('$route').matched[0];
1237
+ if (!$routeMatched?.name) throw new Error('No active route');
1238
+ if ($routeMatched?.path == '/embed') return this.debug('INFO', 2, 'Ignoring setPageUrl(', url, ') on when in embed mode');
1239
+ if (!$routeMatched?.path.endsWith('/:toolPath(.*)?')) return this.debug('INFO', 2, 'Ignoring setPageUrl(', url, ') - no active tool anyway');
1240
+
1241
+ app.router.push({
1242
+ path: $routeMatched.path.replace(/\/:toolPath\(\.\*\)\?$/, url),
1243
+ });
1197
1244
  }
1198
1245
 
1246
+
1247
+ /**
1248
+ * Set the active page title
1249
+ * This is usually called by a tool nested within the tera-tools.com embed
1250
+ *
1251
+ * @param {String} [title] The current page title. Set to a falsy value to revert back to the default page title
1252
+ */
1253
+ setPageTitle(title) {
1254
+ app.root.setPageTitle(title);
1255
+ }
1199
1256
  // }}}
1200
1257
 
1201
1258
  // Init - constructor(), init() {{{
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iebh/tera-fy",
3
- "version": "1.4.4",
3
+ "version": "1.6.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=.",
@@ -12,7 +12,7 @@
12
12
  "build:docs:markdown": "documentation build lib/terafy.client.js lib/projectFile.js --format md --markdown-toc --output api.md",
13
13
  "lint": "eslint lib plugins utils widgets",
14
14
  "release": "release-it",
15
- "watch": "nodemon --watch lib --exec npm run build"
15
+ "watch": "nodemon --watch lib --watch plugins --exec npm run build"
16
16
  },
17
17
  "type": "module",
18
18
  "imports": {
@@ -109,7 +109,10 @@
109
109
  },
110
110
  "hooks": {
111
111
  "before:init": "git reset HEAD -- api.md docs/ dist/",
112
- "after:bump": "npm run build && git add api.md docs/ dist/"
112
+ "before:bump": [
113
+ "npm run build",
114
+ "git add api.md docs/ dist/"
115
+ ]
113
116
  },
114
117
  "plugins": {
115
118
  "@release-it/conventional-changelog": {
package/plugins/vue2.js CHANGED
@@ -1,4 +1,4 @@
1
- import {cloneDeep} from 'lodash-es';
1
+ import {cloneDeep, isPlainObject} from 'lodash-es';
2
2
  import TeraFyPluginBase from './base.js';
3
3
 
4
4
  /**
@@ -93,6 +93,7 @@ export default class TeraFyPluginVue2 extends TeraFyPluginBase {
93
93
  if (settings.read) {
94
94
  this.events.on(`update:projects/${stateObservable.id}`, newState => {
95
95
  skipUpdate++; // Skip next update as we're updating our own state anyway
96
+ this.debug('INFO', 5, 'Update Vue2 Remote->Local', {new: newState, old: stateObservable});
96
97
  this.merge(stateObservable, newState);
97
98
  });
98
99
  }
@@ -114,6 +115,7 @@ export default class TeraFyPluginVue2 extends TeraFyPluginBase {
114
115
  return;
115
116
  }
116
117
 
118
+ this.debug('INFO', 5, 'Update Vue2 Local->Remote', {new: newVal, old: oldVal});
117
119
  this.createProjectStatePatch(newVal, oldVal);
118
120
  oldVal = cloneDeep(snapshot);
119
121
  },
@@ -140,9 +142,9 @@ export default class TeraFyPluginVue2 extends TeraFyPluginBase {
140
142
  payload.forEach(pl =>
141
143
  Object.keys(pl)
142
144
  .forEach(k => {
143
- if (typeof pl[k] == 'object') { // Setting sub-objects - need to recurse these in Vue2
145
+ if (isPlainObject(pl[k])) { // Setting sub-objects - we need to recurse these in Vue2 in case a sub-key gets glued on
144
146
  if (!(k in target)) // Destination to merge doesn't exist yet - create it
145
- this.Vue.set(target, k, Array.isArray(pl[k]) ? [] : {});
147
+ this.Vue.set(target, k, {});
146
148
 
147
149
  this.merge(target[k], pl[k]);
148
150
  } else {