@airtable/blocks 1.8.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.
Files changed (55) hide show
  1. package/dist/cjs/models/base.js +16 -5
  2. package/dist/cjs/models/cursor.js +2 -0
  3. package/dist/cjs/models/field.js +146 -27
  4. package/dist/cjs/models/linked_records_query_result.js +1 -1
  5. package/dist/cjs/models/mutation_constants.js +3 -1
  6. package/dist/cjs/models/mutations.js +58 -23
  7. package/dist/cjs/models/table.js +16 -7
  8. package/dist/cjs/private_utils.js +10 -0
  9. package/dist/cjs/sdk.js +1 -1
  10. package/dist/cjs/testing/{mock_airtable_interface.js → abstract_mock_airtable_interface.js} +16 -12
  11. package/dist/cjs/types/mutations.js +1 -0
  12. package/dist/cjs/ui/icon_config.js +4 -2
  13. package/dist/cjs/ui/use_global_config.js +1 -1
  14. package/dist/cjs/unstable_testing_utils.js +2 -2
  15. package/dist/cjs/watchable.js +108 -70
  16. package/dist/types/src/models/base.d.ts +10 -3
  17. package/dist/types/src/models/base.d.ts.map +1 -1
  18. package/dist/types/src/models/cursor.d.ts +2 -0
  19. package/dist/types/src/models/cursor.d.ts.map +1 -1
  20. package/dist/types/src/models/field.d.ts +65 -1
  21. package/dist/types/src/models/field.d.ts.map +1 -1
  22. package/dist/types/src/models/linked_records_query_result.d.ts.map +1 -1
  23. package/dist/types/src/models/mutation_constants.d.ts +1 -0
  24. package/dist/types/src/models/mutation_constants.d.ts.map +1 -1
  25. package/dist/types/src/models/mutations.d.ts.map +1 -1
  26. package/dist/types/src/models/table.d.ts +8 -4
  27. package/dist/types/src/models/table.d.ts.map +1 -1
  28. package/dist/types/src/private_utils.d.ts +6 -0
  29. package/dist/types/src/private_utils.d.ts.map +1 -1
  30. package/dist/types/src/testing/{mock_airtable_interface.d.ts → abstract_mock_airtable_interface.d.ts} +9 -4
  31. package/dist/types/src/testing/abstract_mock_airtable_interface.d.ts.map +1 -0
  32. package/dist/types/src/types/field.d.ts +80 -44
  33. package/dist/types/src/types/field.d.ts.map +1 -1
  34. package/dist/types/src/types/mutations.d.ts +31 -3
  35. package/dist/types/src/types/mutations.d.ts.map +1 -1
  36. package/dist/types/src/ui/icon_config.d.ts +5 -3
  37. package/dist/types/src/ui/icon_config.d.ts.map +1 -1
  38. package/dist/types/src/ui/link.d.ts +1 -1
  39. package/dist/types/src/ui/link.d.ts.map +1 -1
  40. package/dist/types/src/ui/use_global_config.d.ts +1 -1
  41. package/dist/types/src/unstable_testing_utils.d.ts +1 -1
  42. package/dist/types/src/unstable_testing_utils.d.ts.map +1 -1
  43. package/dist/types/src/watchable.d.ts.map +1 -1
  44. package/dist/types/test/airtable_interface_mocks/fixture_data.d.ts +119 -0
  45. package/dist/types/test/airtable_interface_mocks/fixture_data.d.ts.map +1 -0
  46. package/dist/types/test/airtable_interface_mocks/linked_records.d.ts +2 -2
  47. package/dist/types/test/airtable_interface_mocks/linked_records.d.ts.map +1 -1
  48. package/dist/types/test/airtable_interface_mocks/{mock_airtable_interface_internal.d.ts → mock_airtable_interface.d.ts} +9 -8
  49. package/dist/types/test/airtable_interface_mocks/mock_airtable_interface.d.ts.map +1 -0
  50. package/dist/types/test/airtable_interface_mocks/project_tracker.d.ts +2 -2
  51. package/dist/types/test/airtable_interface_mocks/project_tracker.d.ts.map +1 -1
  52. package/package.json +1 -1
  53. package/CHANGELOG.md +0 -455
  54. package/dist/types/src/testing/mock_airtable_interface.d.ts.map +0 -1
  55. package/dist/types/test/airtable_interface_mocks/mock_airtable_interface_internal.d.ts.map +0 -1
@@ -471,7 +471,8 @@ function (_AbstractModel) {
471
471
  type: field.type
472
472
  }, field.options ? {
473
473
  options: field.options
474
- } : null) : undefined
474
+ } : null) : undefined,
475
+ description: field.description
475
476
  };
476
477
  })
477
478
  });
@@ -505,7 +506,8 @@ function (_AbstractModel) {
505
506
  * Creates a new table.
506
507
  *
507
508
  * Throws an error if the user does not have permission to create a table, if an invalid
508
- * table name is provided, or if invalid fields are provided (invalid name, type or options).
509
+ * table name is provided, or if invalid fields are provided (invalid name, type, options or
510
+ * description).
509
511
  *
510
512
  * Refer to {@link FieldType} for supported field types, the write format for field options, and
511
513
  * other specifics for certain field types.
@@ -522,7 +524,10 @@ function (_AbstractModel) {
522
524
  * table in your app.
523
525
  *
524
526
  * @param name name for the table. must be case-insensitive unique
525
- * @param fields array of fields to create in the table: see below for details.
527
+ * @param fields array of fields to create in the table: see below for an example. `name` and
528
+ * `type` must be specified for all fields, while `options` is only required for fields that
529
+ * have field options. `description` is optional and will be `''` if not specified or if
530
+ * specified as `null`.
526
531
  *
527
532
  * @example
528
533
  * ```js
@@ -530,7 +535,7 @@ function (_AbstractModel) {
530
535
  * const name = 'My new table';
531
536
  * const fields = [
532
537
  * // Name will be the primary field of the table.
533
- * {name: 'Name', type: FieldType.SINGLE_LINE_TEXT},
538
+ * {name: 'Name', type: FieldType.SINGLE_LINE_TEXT, description: 'This is the primary field'},
534
539
  * {name: 'Notes', type: FieldType.RICH_TEXT},
535
540
  * {name: 'Attachments', type: FieldType.MULTIPLE_ATTACHMENTS},
536
541
  * {name: 'Number', type: FieldType.NUMBER, options: {
@@ -566,13 +571,19 @@ function (_AbstractModel) {
566
571
  type: _mutations.MutationTypes.CREATE_SINGLE_TABLE,
567
572
  name,
568
573
  fields: fields.map(field => {
574
+ var _field$description;
575
+
569
576
  return {
570
577
  name: field.name,
571
578
  config: _objectSpread({
572
579
  type: field.type
573
580
  }, field.options ? {
574
581
  options: field.options
575
- } : null)
582
+ } : null),
583
+ // Coerce undefined to null so that only old SDKs pass "undefined" for description
584
+ // '' is permitted, as we already set empty descriptions to '' when editing descriptions
585
+ // from the UI
586
+ description: (_field$description = field.description) !== null && _field$description !== void 0 ? _field$description : null
576
587
  };
577
588
  })
578
589
  }));
@@ -89,6 +89,7 @@ var WatchableCursorKeys = Object.freeze({
89
89
  * return (
90
90
  * <div>
91
91
  * Active table: {cursor.activeTableId}
92
+ * <br />
92
93
  * Active view: {cursor.activeViewId}
93
94
  * </div>
94
95
  * );
@@ -109,6 +110,7 @@ var WatchableCursorKeys = Object.freeze({
109
110
  * return (
110
111
  * <div>
111
112
  * Selected records: {cursor.selectedRecordIds.join(', ')}
113
+ * <br />
112
114
  * Selected fields: {cursor.selectedFieldIds.join(', ')}
113
115
  * </div>
114
116
  * );
@@ -109,7 +109,9 @@ function (_AbstractModel) {
109
109
  (0, _classCallCheck2.default)(this, Field);
110
110
  _this = (0, _possibleConstructorReturn2.default)(this, (0, _getPrototypeOf2.default)(Field).call(this, sdk, fieldId));
111
111
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "_parentTable", void 0);
112
+ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "_cachedFieldTypeConfigOrNull", void 0);
112
113
  _this._parentTable = parentTable;
114
+ _this._cachedFieldTypeConfigOrNull = null;
113
115
  return _this;
114
116
  }
115
117
  /**
@@ -118,6 +120,42 @@ function (_AbstractModel) {
118
120
 
119
121
 
120
122
  (0, _createClass2.default)(Field, [{
123
+ key: "_getCachedConfigFromFieldTypeProvider",
124
+ // We use a cached response from FieldTypeProvider because getting the config can
125
+ // be an expensive operation. In particular when fieldConfigs are extremely large
126
+ // (eg: Select fields with lots of select options)
127
+ value: function _getCachedConfigFromFieldTypeProvider() {
128
+ if (this._cachedFieldTypeConfigOrNull !== null) {
129
+ return this._cachedFieldTypeConfigOrNull;
130
+ }
131
+
132
+ var airtableInterface = this._sdk.__airtableInterface;
133
+ var appInterface = this._sdk.__appInterface;
134
+ this._cachedFieldTypeConfigOrNull = airtableInterface.fieldTypeProvider.getConfig(appInterface, this._data, this.parentTable.__getFieldNamesById());
135
+ return this._cachedFieldTypeConfigOrNull;
136
+ }
137
+ }, {
138
+ key: "_clearCachedConfig",
139
+ value: function _clearCachedConfig() {
140
+ this._cachedFieldTypeConfigOrNull = null;
141
+ }
142
+ /**
143
+ * The type and options of the field to make type narrowing `FieldOptions` easier.
144
+ *
145
+ * @see {@link FieldConfig}
146
+ * @example
147
+ * const fieldConfig = field.config;
148
+ * if (fieldConfig.type === FieldType.SINGLE_SELECT) {
149
+ * return fieldConfig.options.choices;
150
+ * } else if (fieldConfig.type === FieldType.MULTIPLE_LOOKUP_VALUES && fieldConfig.options.isValid) {
151
+ * if (fieldConfig.options.result.type === FieldType.SINGLE_SELECT) {
152
+ * return fieldConfig.options.result.options.choices;
153
+ * }
154
+ * }
155
+ * return DEFAULT_CHOICES;
156
+ */
157
+
158
+ }, {
121
159
  key: "checkPermissionsForUpdateOptions",
122
160
 
123
161
  /**
@@ -125,7 +163,7 @@ function (_AbstractModel) {
125
163
  *
126
164
  * Accepts partial input, in the same format as {@link updateOptionsAsync}.
127
165
  *
128
- * Returns `{hasPermission: true}` if the current user can update the specified record,
166
+ * Returns `{hasPermission: true}` if the current user can update the specified field,
129
167
  * `{hasPermission: false, reasonDisplayString: string}` otherwise. `reasonDisplayString` may be
130
168
  * used to display an error message to the user.
131
169
  *
@@ -241,6 +279,104 @@ function (_AbstractModel) {
241
279
  }
242
280
  }, null, this);
243
281
  }
282
+ /**
283
+ * Checks whether the current user has permission to perform the given description update.
284
+ *
285
+ * Accepts partial input, in the same format as {@link updateDescriptionAsync}.
286
+ *
287
+ * Returns `{hasPermission: true}` if the current user can update the specified field,
288
+ * `{hasPermission: false, reasonDisplayString: string}` otherwise. `reasonDisplayString` may be
289
+ * used to display an error message to the user.
290
+ *
291
+ * @param description new description for the field
292
+ *
293
+ * @example
294
+ * ```js
295
+ * const updateFieldCheckResult = field.checkPermissionsForUpdateDescription();
296
+ *
297
+ * if (!updateFieldCheckResult.hasPermission) {
298
+ * alert(updateFieldCheckResult.reasonDisplayString);
299
+ * }
300
+ * ```
301
+ */
302
+
303
+ }, {
304
+ key: "checkPermissionsForUpdateDescription",
305
+ value: function checkPermissionsForUpdateDescription(description) {
306
+ return this._sdk.__mutations.checkPermissionsForMutation({
307
+ type: _mutations.MutationTypes.UPDATE_SINGLE_FIELD_DESCRIPTION,
308
+ tableId: this.parentTable.id,
309
+ id: this.id,
310
+ description
311
+ });
312
+ }
313
+ /**
314
+ * An alias for `checkPermissionsForUpdateDescription(options).hasPermission`.
315
+ *
316
+ * Checks whether the current user has permission to perform the description update.
317
+ *
318
+ * Accepts partial input, in the same format as {@link updateDescriptionAsync}.
319
+ *
320
+ * @param description new description for the field
321
+ *
322
+ * @example
323
+ * ```js
324
+ * const canUpdateField = field.hasPermissionToUpdateDescription();
325
+ *
326
+ * if (!canUpdateField) {
327
+ * alert('not allowed!');
328
+ * }
329
+ * ```
330
+ */
331
+
332
+ }, {
333
+ key: "hasPermissionToUpdateDescription",
334
+ value: function hasPermissionToUpdateDescription(description) {
335
+ return this.checkPermissionsForUpdateDescription(description).hasPermission;
336
+ }
337
+ /**
338
+ * Updates the description for this field.
339
+ *
340
+ * To remove an existing description, pass `''` as the new description.
341
+ * `null` is also accepted and will be coerced to `''` for consistency with field creation.
342
+ *
343
+ * Throws an error if the user does not have permission to update the field, or if an invalid
344
+ * description is provided.
345
+ *
346
+ * This action is asynchronous. Unlike updates to cell values, updates to field descriptions are
347
+ * **not** applied optimistically locally. You must `await` the returned promise before
348
+ * relying on the change in your app.
349
+ *
350
+ * @param description new description for the field
351
+ *
352
+ * @example
353
+ * ```js
354
+ * await myTextField.updateDescriptionAsync('This is a text field');
355
+ * ```
356
+ */
357
+
358
+ }, {
359
+ key: "updateDescriptionAsync",
360
+ value: function updateDescriptionAsync(description) {
361
+ return _regenerator.default.async(function updateDescriptionAsync$(_context2) {
362
+ while (1) {
363
+ switch (_context2.prev = _context2.next) {
364
+ case 0:
365
+ _context2.next = 2;
366
+ return _regenerator.default.awrap(this._sdk.__mutations.applyMutationAsync({
367
+ type: _mutations.MutationTypes.UPDATE_SINGLE_FIELD_DESCRIPTION,
368
+ tableId: this.parentTable.id,
369
+ id: this.id,
370
+ description
371
+ }));
372
+
373
+ case 2:
374
+ case "end":
375
+ return _context2.stop();
376
+ }
377
+ }
378
+ }, null, this);
379
+ }
244
380
  /**
245
381
  * `true` if this field is computed, `false` otherwise. A field is
246
382
  * "computed" if it's value is not set by user input (e.g. autoNumber, formula,
@@ -329,6 +465,9 @@ function (_AbstractModel) {
329
465
  }, {
330
466
  key: "__triggerOnChangeForDirtyPaths",
331
467
  value: function __triggerOnChangeForDirtyPaths(dirtyPaths) {
468
+ // Always clear the cached config when anything on the field data model changes
469
+ this._clearCachedConfig();
470
+
332
471
  if (dirtyPaths.name) {
333
472
  this._onChange(WatchableFieldKeys.name);
334
473
  }
@@ -402,11 +541,8 @@ function (_AbstractModel) {
402
541
  }, {
403
542
  key: "type",
404
543
  get: function get() {
405
- var airtableInterface = this._sdk.__airtableInterface;
406
- var appInterface = this._sdk.__appInterface;
407
-
408
- var _airtableInterface$fi = airtableInterface.fieldTypeProvider.getConfig(appInterface, this._data, this.parentTable.__getFieldNamesById()),
409
- type = _airtableInterface$fi.type; // We intend to switch from "lookup" to "multipleLookupValues", but need to support both
544
+ var _this$_getCachedConfi = this._getCachedConfigFromFieldTypeProvider(),
545
+ type = _this$_getCachedConfi.type; // We intend to switch from "lookup" to "multipleLookupValues", but need to support both
410
546
  // until the transition is complete. See <https://airtable.quip.com/VxaMAmAfUscs> for more.
411
547
  // @ts-ignore
412
548
 
@@ -437,31 +573,14 @@ function (_AbstractModel) {
437
573
  }, {
438
574
  key: "options",
439
575
  get: function get() {
440
- var airtableInterface = this._sdk.__airtableInterface;
441
- var appInterface = this._sdk.__appInterface;
442
-
443
- var _airtableInterface$fi2 = airtableInterface.fieldTypeProvider.getConfig(appInterface, this._data, this.parentTable.__getFieldNamesById()),
444
- options = _airtableInterface$fi2.options; // TODO(emma): can we remove this cloneDeep?
576
+ var _this$_getCachedConfi2 = this._getCachedConfigFromFieldTypeProvider(),
577
+ options = _this$_getCachedConfi2.options; // TODO: In the next breaking release freeze (inside of the cache) and replace
578
+ // FieldOptions with readonly<FieldOptions>.
579
+ // Today this is required because we re-use the fieldTypeProvider.getConfig response.
445
580
 
446
581
 
447
582
  return options ? (0, _private_utils.cloneDeep)(options) : null;
448
583
  }
449
- /**
450
- * The type and options of the field to make type narrowing `FieldOptions` easier.
451
- *
452
- * @see {@link FieldConfig}
453
- * @example
454
- * const fieldConfig = field.config;
455
- * if (fieldConfig.type === FieldType.SINGLE_SELECT) {
456
- * return fieldConfig.options.choices;
457
- * } else if (fieldConfig.type === FieldType.MULTIPLE_LOOKUP_VALUES && fieldConfig.options.isValid) {
458
- * if (fieldConfig.options.result.type === FieldType.SINGLE_SELECT) {
459
- * return fieldConfig.options.result.options.choices;
460
- * }
461
- * }
462
- * return DEFAULT_CHOICES;
463
- */
464
-
465
584
  }, {
466
585
  key: "config",
467
586
  get: function get() {
@@ -376,7 +376,7 @@ function (_RecordQueryResult) {
376
376
 
377
377
  this._unwatchLinkedQueryResult();
378
378
 
379
- this._sdk.base.__getRecordStore(this._record.parentTable.id).unloadCellValuesInFieldIds([this._field.id]);
379
+ this._originRecordStore.unloadCellValuesInFieldIds([this._field.id]);
380
380
 
381
381
  this._linkedQueryResult.unloadData();
382
382
 
@@ -3,10 +3,12 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.MAX_NUM_FIELDS_PER_TABLE = exports.MAX_TABLE_NAME_LENGTH = exports.MAX_FIELD_NAME_LENGTH = void 0;
6
+ exports.MAX_NUM_FIELDS_PER_TABLE = exports.MAX_TABLE_NAME_LENGTH = exports.MAX_FIELD_DESCRIPTION_LENGTH = exports.MAX_FIELD_NAME_LENGTH = void 0;
7
7
  // Mirrored from clientServerSharedConfigSettings
8
8
  var MAX_FIELD_NAME_LENGTH = 255;
9
9
  exports.MAX_FIELD_NAME_LENGTH = MAX_FIELD_NAME_LENGTH;
10
+ var MAX_FIELD_DESCRIPTION_LENGTH = 20000;
11
+ exports.MAX_FIELD_DESCRIPTION_LENGTH = MAX_FIELD_DESCRIPTION_LENGTH;
10
12
  var MAX_TABLE_NAME_LENGTH = 255;
11
13
  exports.MAX_TABLE_NAME_LENGTH = MAX_TABLE_NAME_LENGTH;
12
14
  var MAX_NUM_FIELDS_PER_TABLE = 500;
@@ -442,7 +442,8 @@ function () {
442
442
  {
443
443
  var _tableId3 = mutation.tableId,
444
444
  name = mutation.name,
445
- config = mutation.config;
445
+ config = mutation.config,
446
+ description = mutation.description;
446
447
 
447
448
  var _table3 = this._base.getTableByIdIfExists(_tableId3);
448
449
 
@@ -475,6 +476,10 @@ function () {
475
476
  throw (0, _error_utils.spawnError)("Can't create field: invalid field config.\n%s", _validationResult2.reason);
476
477
  }
477
478
 
479
+ if (description && description.length > _mutation_constants.MAX_FIELD_DESCRIPTION_LENGTH) {
480
+ throw (0, _error_utils.spawnError)("Can't create field: description exceeds maximum length of %s characters", _mutation_constants.MAX_FIELD_DESCRIPTION_LENGTH);
481
+ }
482
+
478
483
  return;
479
484
  }
480
485
 
@@ -511,6 +516,31 @@ function () {
511
516
  return;
512
517
  }
513
518
 
519
+ case _mutations.MutationTypes.UPDATE_SINGLE_FIELD_DESCRIPTION:
520
+ {
521
+ var _tableId5 = mutation.tableId,
522
+ _id = mutation.id,
523
+ _description = mutation.description;
524
+
525
+ var _table5 = this._base.getTableByIdIfExists(_tableId5);
526
+
527
+ if (!_table5) {
528
+ throw (0, _error_utils.spawnError)("Can't update field: No table with id %s exists", _tableId5);
529
+ }
530
+
531
+ var _field3 = _table5.getFieldByIdIfExists(_id);
532
+
533
+ if (!_field3) {
534
+ throw (0, _error_utils.spawnError)("Can't update field: No field with id %s exists", _id);
535
+ }
536
+
537
+ if (_description && _description.length > _mutation_constants.MAX_FIELD_DESCRIPTION_LENGTH) {
538
+ throw (0, _error_utils.spawnError)("Can't update field: description exceeds maximum length of %s characters", _mutation_constants.MAX_FIELD_DESCRIPTION_LENGTH);
539
+ }
540
+
541
+ return;
542
+ }
543
+
514
544
  case _mutations.MutationTypes.CREATE_SINGLE_TABLE:
515
545
  {
516
546
  var _name = mutation.name,
@@ -545,28 +575,32 @@ function () {
545
575
 
546
576
  try {
547
577
  for (var _iterator4 = fields[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
548
- var _field3 = _step4.value;
578
+ var _field4 = _step4.value;
549
579
 
550
- if (!_field3.name) {
580
+ if (!_field4.name) {
551
581
  throw (0, _error_utils.spawnError)("Can't create table: must provide non-empty name for every field");
552
582
  }
553
583
 
554
- if (_field3.name.length > _mutation_constants.MAX_FIELD_NAME_LENGTH) {
555
- throw (0, _error_utils.spawnError)("Can't create table: field name '%s' exceeds maximum length of %s characters", _field3.name, _mutation_constants.MAX_FIELD_NAME_LENGTH);
584
+ if (_field4.name.length > _mutation_constants.MAX_FIELD_NAME_LENGTH) {
585
+ throw (0, _error_utils.spawnError)("Can't create table: field name '%s' exceeds maximum length of %s characters", _field4.name, _mutation_constants.MAX_FIELD_NAME_LENGTH);
556
586
  }
557
587
 
558
- var lowercaseFieldName = _field3.name.toLowerCase();
588
+ var lowercaseFieldName = _field4.name.toLowerCase();
559
589
 
560
590
  if (lowercaseFieldNames.has(lowercaseFieldName)) {
561
- throw (0, _error_utils.spawnError)("Can't create table: duplicate field name '%s'", _field3.name);
591
+ throw (0, _error_utils.spawnError)("Can't create table: duplicate field name '%s'", _field4.name);
562
592
  }
563
593
 
564
594
  lowercaseFieldNames.add(lowercaseFieldName); // Current config / field data is null since the field doesn't exist.
565
595
 
566
- var _validationResult4 = this._airtableInterface.fieldTypeProvider.validateConfigForUpdate(appInterface, _field3.config, null, null, billingPlanGrouping);
596
+ var _validationResult4 = this._airtableInterface.fieldTypeProvider.validateConfigForUpdate(appInterface, _field4.config, null, null, billingPlanGrouping);
567
597
 
568
598
  if (!_validationResult4.isValid) {
569
- throw (0, _error_utils.spawnError)("Can't create table: invalid field config for field '%s'.\n%s", _field3.name, _validationResult4.reason);
599
+ throw (0, _error_utils.spawnError)("Can't create table: invalid field config for field '%s'.\n%s", _field4.name, _validationResult4.reason);
600
+ }
601
+
602
+ if (_field4.description && _field4.description.length > _mutation_constants.MAX_FIELD_DESCRIPTION_LENGTH) {
603
+ throw (0, _error_utils.spawnError)("Can't create table: description for field '%s' exceeds maximum length of %s characters", _field4.name, _mutation_constants.MAX_FIELD_DESCRIPTION_LENGTH);
570
604
  }
571
605
  }
572
606
  } catch (err) {
@@ -595,7 +629,7 @@ function () {
595
629
 
596
630
  case _mutations.MutationTypes.UPDATE_VIEW_METADATA:
597
631
  {
598
- var _tableId5 = mutation.tableId,
632
+ var _tableId6 = mutation.tableId,
599
633
  viewId = mutation.viewId;
600
634
  var runContext = this._airtableInterface.sdkInitData.runContext;
601
635
 
@@ -603,17 +637,17 @@ function () {
603
637
  throw (0, _error_utils.spawnError)('Setting view metadata is only valid for views');
604
638
  }
605
639
 
606
- if (runContext.viewId !== viewId || runContext.tableId !== _tableId5) {
640
+ if (runContext.viewId !== viewId || runContext.tableId !== _tableId6) {
607
641
  throw (0, _error_utils.spawnError)('Custom views can only set view metadata on themselves');
608
642
  }
609
643
 
610
- var _table5 = this._base.getTableByIdIfExists(_tableId5);
644
+ var _table6 = this._base.getTableByIdIfExists(_tableId6);
611
645
 
612
- if (!_table5) {
613
- throw (0, _error_utils.spawnError)("Can't update metadata: No table with id %s exists", _tableId5);
646
+ if (!_table6) {
647
+ throw (0, _error_utils.spawnError)("Can't update metadata: No table with id %s exists", _tableId6);
614
648
  }
615
649
 
616
- var view = _table5.getViewByIdIfExists(viewId);
650
+ var view = _table6.getViewByIdIfExists(viewId);
617
651
 
618
652
  if (!view) {
619
653
  throw (0, _error_utils.spawnError)("Can't update metadata: No view with id %s exists", viewId);
@@ -671,19 +705,19 @@ function () {
671
705
 
672
706
  case _mutations.MutationTypes.DELETE_MULTIPLE_RECORDS:
673
707
  {
674
- var _tableId6 = mutation.tableId,
708
+ var _tableId7 = mutation.tableId,
675
709
  recordIds = mutation.recordIds;
676
710
 
677
- var _recordStore2 = this._base.__getRecordStore(_tableId6);
711
+ var _recordStore2 = this._base.__getRecordStore(_tableId7);
678
712
 
679
713
  if (!_recordStore2.isRecordMetadataLoaded) {
680
714
  return [];
681
715
  }
682
716
 
683
717
  return [...recordIds.map(recordId => ({
684
- path: ['tablesById', _tableId6, 'recordsById', recordId],
718
+ path: ['tablesById', _tableId7, 'recordsById', recordId],
685
719
  value: undefined
686
- })), ...this._base.getTableById(_tableId6).views.flatMap(view => {
720
+ })), ...this._base.getTableById(_tableId7).views.flatMap(view => {
687
721
  var viewDataStore = _recordStore2.getViewDataStore(view.id);
688
722
 
689
723
  if (!viewDataStore.isDataLoaded) {
@@ -696,10 +730,10 @@ function () {
696
730
 
697
731
  case _mutations.MutationTypes.CREATE_MULTIPLE_RECORDS:
698
732
  {
699
- var _tableId7 = mutation.tableId,
733
+ var _tableId8 = mutation.tableId,
700
734
  _records2 = mutation.records;
701
735
 
702
- var _recordStore3 = this._base.__getRecordStore(_tableId7);
736
+ var _recordStore3 = this._base.__getRecordStore(_tableId8);
703
737
 
704
738
  if (!_recordStore3.isRecordMetadataLoaded) {
705
739
  return [];
@@ -738,7 +772,7 @@ function () {
738
772
  }
739
773
 
740
774
  return {
741
- path: ['tablesById', _tableId7, 'recordsById', record.id],
775
+ path: ['tablesById', _tableId8, 'recordsById', record.id],
742
776
  value: {
743
777
  id: record.id,
744
778
  cellValuesByFieldId: filteredCellValuesByFieldId,
@@ -746,7 +780,7 @@ function () {
746
780
  createdTime: new Date().toJSON()
747
781
  }
748
782
  };
749
- }), ...this._base.getTableById(_tableId7).views.flatMap(view => {
783
+ }), ...this._base.getTableById(_tableId8).views.flatMap(view => {
750
784
  var viewDataStore = _recordStore3.getViewDataStore(view.id);
751
785
 
752
786
  if (!viewDataStore.isDataLoaded) {
@@ -767,6 +801,7 @@ function () {
767
801
 
768
802
  case _mutations.MutationTypes.CREATE_SINGLE_FIELD:
769
803
  case _mutations.MutationTypes.UPDATE_SINGLE_FIELD_CONFIG:
804
+ case _mutations.MutationTypes.UPDATE_SINGLE_FIELD_DESCRIPTION:
770
805
  case _mutations.MutationTypes.UPDATE_VIEW_METADATA:
771
806
  case _mutations.MutationTypes.CREATE_SINGLE_TABLE:
772
807
  {
@@ -1735,6 +1735,7 @@ function (_AbstractModel) {
1735
1735
  * @param name name for the field. must be case-insensitive unique for the table
1736
1736
  * @param type type for the field
1737
1737
  * @param options options for the field. omit for fields without writable options
1738
+ * @param description description for the field. omit to leave blank
1738
1739
  *
1739
1740
  * @example
1740
1741
  * ```js
@@ -1748,7 +1749,7 @@ function (_AbstractModel) {
1748
1749
 
1749
1750
  }, {
1750
1751
  key: "checkPermissionsForCreateField",
1751
- value: function checkPermissionsForCreateField(name, type, options) {
1752
+ value: function checkPermissionsForCreateField(name, type, options, description) {
1752
1753
  return this._sdk.__mutations.checkPermissionsForMutation({
1753
1754
  type: _mutations.MutationTypes.CREATE_SINGLE_FIELD,
1754
1755
  tableId: this.id,
@@ -1759,11 +1760,12 @@ function (_AbstractModel) {
1759
1760
  type: type
1760
1761
  }, options ? {
1761
1762
  options
1762
- } : null) : undefined
1763
+ } : null) : undefined,
1764
+ description
1763
1765
  });
1764
1766
  }
1765
1767
  /**
1766
- * An alias for `checkPermissionsForCreateField(name, type, options).hasPermission`.
1768
+ * An alias for `checkPermissionsForCreateField(name, type, options, description).hasPermission`.
1767
1769
  *
1768
1770
  * Checks whether the current user has permission to create a field in this table.
1769
1771
  *
@@ -1772,6 +1774,7 @@ function (_AbstractModel) {
1772
1774
  * @param name name for the field. must be case-insensitive unique for the table
1773
1775
  * @param type type for the field
1774
1776
  * @param options options for the field. omit for fields without writable options
1777
+ * @param description description for the field. omit to leave blank
1775
1778
  *
1776
1779
  * @example
1777
1780
  * ```js
@@ -1785,8 +1788,8 @@ function (_AbstractModel) {
1785
1788
 
1786
1789
  }, {
1787
1790
  key: "hasPermissionToCreateField",
1788
- value: function hasPermissionToCreateField(name, type, options) {
1789
- return this.checkPermissionsForCreateField(name, type, options).hasPermission;
1791
+ value: function hasPermissionToCreateField(name, type, options, description) {
1792
+ return this.checkPermissionsForCreateField(name, type, options, description).hasPermission;
1790
1793
  }
1791
1794
  /**
1792
1795
  * Creates a new field.
@@ -1807,6 +1810,8 @@ function (_AbstractModel) {
1807
1810
  * @param name name for the field. must be case-insensitive unique
1808
1811
  * @param type type for the field
1809
1812
  * @param options options for the field. omit for fields without writable options
1813
+ * @param description description for the field. is optional and will be `''` if not specified
1814
+ * or if specified as `null`.
1810
1815
  *
1811
1816
  * @example
1812
1817
  * ```js
@@ -1841,7 +1846,7 @@ function (_AbstractModel) {
1841
1846
 
1842
1847
  }, {
1843
1848
  key: "createFieldAsync",
1844
- value: function createFieldAsync(name, type, options) {
1849
+ value: function createFieldAsync(name, type, options, description) {
1845
1850
  var fieldId;
1846
1851
  return _regenerator.default.async(function createFieldAsync$(_context9) {
1847
1852
  while (1) {
@@ -1858,7 +1863,11 @@ function (_AbstractModel) {
1858
1863
  type: type
1859
1864
  }, options ? {
1860
1865
  options
1861
- } : null)
1866
+ } : null),
1867
+ // Coerce undefined to null so that only old SDKs pass "undefined" for description
1868
+ // '' is permitted, as we already set empty descriptions to '' when editing descriptions
1869
+ // from the UI
1870
+ description: description !== null && description !== void 0 ? description : null
1862
1871
  }));
1863
1872
 
1864
1873
  case 3:
@@ -50,6 +50,7 @@ exports.compact = compact;
50
50
  exports.clamp = clamp;
51
51
  exports.flattenDeep = flattenDeep;
52
52
  exports.keyBy = keyBy;
53
+ exports.getId = getId;
53
54
  exports.uniqBy = uniqBy;
54
55
  exports.getLocallyUniqueId = getLocallyUniqueId;
55
56
  exports.getValueAtOwnPath = getValueAtOwnPath;
@@ -411,6 +412,15 @@ function keyBy(array, getKey) {
411
412
  */
412
413
 
413
414
 
415
+ function getId(_ref) {
416
+ var id = _ref.id;
417
+ return id;
418
+ }
419
+ /**
420
+ * @hidden
421
+ */
422
+
423
+
414
424
  function uniqBy(array, getKey) {
415
425
  var usedKeys = new Set();
416
426
  var result = [];
package/dist/cjs/sdk.js CHANGED
@@ -330,4 +330,4 @@ function () {
330
330
  }();
331
331
 
332
332
  exports.default = BlockSdk;
333
- (0, _defineProperty2.default)(BlockSdk, "VERSION", "1.8.0");
333
+ (0, _defineProperty2.default)(BlockSdk, "VERSION", "1.10.0");