@iebh/tera-fy 1.9.0 → 1.10.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.
@@ -5,6 +5,7 @@ import {nanoid} from 'nanoid';
5
5
  import pathTools from '#utils/pathTools';
6
6
  import promiseDefer from '#utils/pDefer';
7
7
  import Reflib from '@iebh/reflib';
8
+ import {reactive} from 'vue';
8
9
 
9
10
  /**
10
11
  * Server-side functions available to the Tera-Fy client library
@@ -335,8 +336,8 @@ export default class TeraFyServer {
335
336
  * @param {Number} verbosity The desired server verbosity level
336
337
  */
337
338
  setServerVerbosity(verbosity) {
338
- this.settinigs.verbosity = +verbosity;
339
- this.debug('INFO', 1, 'Server verbosity set to', this.settinigs.verbosity);
339
+ this.settings.verbosity = +verbosity;
340
+ this.debug('INFO', 1, 'Server verbosity set to', this.settings.verbosity);
340
341
  }
341
342
  // }}}
342
343
 
@@ -1042,6 +1043,28 @@ export default class TeraFyServer {
1042
1043
  }
1043
1044
 
1044
1045
 
1046
+ /**
1047
+ * Fetch the raw contents of a file by its ID
1048
+ *
1049
+ * @param {String} [id] File ID to retrieve the contents of
1050
+ * @param {Object} [options] Additioanl options to mutate behaviour
1051
+ * @param {'blob'|'json'} [options.format='blob'] The format to retrieve the file in. If `json` the raw output is run via JSON.parse() first
1052
+ *
1053
+ * @returns {*} The file contents in the requested format
1054
+ */
1055
+ getProjectFileContents(id, options) {
1056
+ let settings = {
1057
+ format: 'blob',
1058
+ ...options,
1059
+ };
1060
+
1061
+ return app.service('$supabase').fileGet(app.service('$projects').decodeFilePath(id), {
1062
+ json: settings.format == 'json',
1063
+ toast: false,
1064
+ });
1065
+ }
1066
+
1067
+
1045
1068
  /**
1046
1069
  * Create a new file
1047
1070
  * This creates an empty file which can then be written to
@@ -1086,15 +1109,60 @@ export default class TeraFyServer {
1086
1109
  /**
1087
1110
  * Replace a project files contents
1088
1111
  *
1089
- * @param {String} id File to overwrite
1112
+ * @param {String} [id] File ID to save back to, if omitted a file will be prompted for
1090
1113
  * @param {File|Blob|FormData|Object|Array} contents The new file contents
1114
+ * @param {Object} [options] Additional options to mutate behaviour
1115
+ * @param {String} [options.id] Alternate method to specify the file ID to save as, if omitted one will be prompted for
1116
+ * @param {Boolean} [options.autoRequire=true] Run `requireProject()` automatically before continuing
1117
+ * @param {String|Array<String>} [options.hint] Hint(s) to store against the library. Generally corresponds to the current operation being performed - e.g. 'deduped'
1118
+ * @param {String} [options.filename] Suggested filename if `id` is unspecified
1119
+ * @param {String} [options.title='Save citation library'] Dialog title if `id` is unspecified and a prompt is necessary
1120
+ * @param {Object} [options.meta] Optional meta data to merge into the file data
1121
+ *
1091
1122
  * @returns {Promise} A promise which will resolve when the write operation has completed
1092
1123
  */
1093
- setProjectFile(id, contents) {
1094
- return app.service('$supabase').fileSet(app.service('$projects').decodeFilePath(id), contents, {
1095
- overwrite: true,
1096
- toast: false,
1097
- });
1124
+ setProjectFile(id, contents, options) {
1125
+ // Argument mangling {{{
1126
+ // TODO: Horrible kludge to detect ID is "not a JSON blob"
1127
+ if (typeof id == 'string' && !id.startsWith('{') && contents && options) { // Called as `(id, contents, options)`
1128
+ // Pass
1129
+ } else if (typeof id != 'string' && !options) { // Called as `(contents, options)`
1130
+ [id, contents, options] = [null, id, contents];
1131
+ } else {
1132
+ throw new Error('Unknown function signature. Requires (id:String?, contents:*, options:Object?)');
1133
+ }
1134
+ // }}}
1135
+
1136
+ let settings = {
1137
+ id,
1138
+ autoRequire: true,
1139
+ hint: null,
1140
+ filename: null,
1141
+ title: 'Save file',
1142
+ meta: null,
1143
+ ...options,
1144
+ };
1145
+
1146
+ return Promise.resolve()
1147
+ .then(()=> settings.autoRequire && this.requireProject())
1148
+ .then(()=> {
1149
+ if (settings.id) return; // We already have a file ID specified - skip
1150
+
1151
+ // Prompt for a save filename
1152
+ return this.selectProjectFile({
1153
+ title: settings.title,
1154
+ save: true,
1155
+ hint: settings.hint,
1156
+ saveFilename: settings.filename,
1157
+ autoRequire: false, // Handled above anyway
1158
+ })
1159
+ .then(file => settings.id = file.id)
1160
+ })
1161
+ .then(()=> app.service('$supabase').fileSet(app.service('$projects').decodeFilePath(settings.id), contents, {
1162
+ overwrite: true,
1163
+ toast: false,
1164
+ }))
1165
+ .then(()=> null)
1098
1166
  }
1099
1167
  // }}}
1100
1168
 
@@ -1235,7 +1303,7 @@ export default class TeraFyServer {
1235
1303
 
1236
1304
  // Prompt for a save filename
1237
1305
  return this.selectProjectFile({
1238
- title: 'Save citation library',
1306
+ title: settings.title,
1239
1307
  save: true,
1240
1308
  hint: settings.hint,
1241
1309
  saveFilename: settings.filename,
@@ -1284,6 +1352,7 @@ export default class TeraFyServer {
1284
1352
  overwrite: true,
1285
1353
  mode: 'encoded',
1286
1354
  }))
1355
+ .then(()=> null)
1287
1356
  }
1288
1357
 
1289
1358
  // }}}
@@ -1397,54 +1466,52 @@ export default class TeraFyServer {
1397
1466
  *
1398
1467
  * @param {Object|Boolean} [options] Additional options to mutate behaviour, if boolean false `{close: true}` is assumed
1399
1468
  * @param {String} [options.title='TERA'] Window title, can only be set on the initial call
1400
- * @param {String} [options.body=''] Window body text, can only be set on the initial call
1401
- * @param {Boolean} [options.bodyHtml=false] Treat body text as HTML
1469
+ * @param {String} [options.body=''] Window body text
1470
+ * @param {Boolean} [options.bodyHtml=false] If truthy, treat the body as HTML
1402
1471
  * @param {Boolean} [options.close=false] Close the existing dialog, if true the dialog is disposed and options reset
1403
- *
1404
- * @FIXME None of the below have been implemented yet
1405
- * @param {String} [options.text] The text of the task being conducted
1406
- * @param {Number} [options.progress] The current progress of the task being conducted, this is assumed to be a value less than `maxProgress`
1407
- * @param {Number} [options.maxProgress] The maximum value that the progress can be
1472
+ * @param {Number} [options.progress] The current progress of the task being conducted, this is assumed to be a value less than `progressMax`
1473
+ * @param {Number} [options.progressMax] The maximum value that the progress can be
1408
1474
  *
1409
1475
  * @returns {Promise} A promise which resolves when the dialog has been updated
1410
1476
  */
1411
1477
  uiProgress(options) {
1412
- if (options === false) { // Close existing ui progress window
1413
- uiProgressOptions.close = true;
1414
- } else if (!this.uiProgressOptions) { // New uiProgress window
1415
- this.uiProgressOptions = {
1478
+ if (options === false) options = {close: true}; // Shorthand to close existing ui progress window
1479
+
1480
+ if (this.uiProgressOptions === null) { // New uiProgress window
1481
+ this.uiProgressOptions = reactive({
1416
1482
  title: 'TERA',
1417
1483
  body: '',
1418
1484
  bodyHtml: false,
1419
1485
  close: false,
1486
+ progress: 0,
1487
+ progressMax: 0,
1420
1488
  ...options,
1421
- };
1489
+ });
1422
1490
  } else { // Merge options with existing uiProgress window
1423
1491
  Object.assign(this.uiProgressOptions, options);
1424
1492
  }
1425
-
1426
- console.log('FIXME: UI PROGRESS - is unfinished', {options: this.uiProgressOptions});
1427
-
1428
- if (!this.uiProgressPromise && !this.uiProgressOptions.close) { // Not created the dialog yet
1429
- this.uiProgressPromise = this.requestFocus(()=>
1430
- app.service('$prompt').dialog({
1431
- title: this.uiProgressOptions.title,
1432
- body: this.uiProgressOptions.body,
1433
- isHtml: this.uiProgressOptions.bodyHtml,
1434
- })
1435
- );
1436
- return Promise.resolve();
1437
- } else if (!this.uiProgressOptions.close) { // Asked to close the dialog
1493
+ if (this.uiProgressOptions.close) { // Asked to close the dialog
1438
1494
  return Promise.resolve()
1439
1495
  .then(()=> this.uiProgressPromise && app.service('$prompt').close(true)) // Close the dialog if its open
1440
1496
  .then(()=> { // Release state
1441
1497
  this.uiProgressOptions = {};
1442
1498
  this.uiProgressPromise = null;
1443
1499
  })
1500
+ } else if (!this.uiProgressPromise) { // Not created the dialog yet
1501
+ this.uiProgressPromise = this.requestFocus(()=>
1502
+ app.service('$prompt').dialog({
1503
+ title: this.uiProgressOptions.title,
1504
+ component: 'uiProgress',
1505
+ componentProps: this.uiProgressOptions,
1506
+ closeable: false,
1507
+ keyboard: false,
1508
+ })
1509
+ );
1510
+ return Promise.resolve();
1444
1511
  }
1445
1512
  }
1446
1513
 
1447
- uiProgressOptions;
1514
+ uiProgressOptions = null;
1448
1515
  uiProgressPromise;
1449
1516
 
1450
1517
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iebh/tera-fy",
3
- "version": "1.9.0",
3
+ "version": "1.10.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=.",
@@ -85,6 +85,9 @@
85
85
  "documentation": "^14.0.2",
86
86
  "esbuild": "^0.19.5"
87
87
  },
88
+ "peerDependencies": {
89
+ "vue": "^3.0.0"
90
+ },
88
91
  "optionalDependencies": {
89
92
  "@iebh/reflib": "^2.2.2",
90
93
  "just-diff-apply": "^5.5.0",