001package com.box.sdk; 002 003import java.net.URL; 004import java.util.ArrayList; 005import java.util.List; 006 007import com.eclipsesource.json.JsonArray; 008import com.eclipsesource.json.JsonObject; 009import com.eclipsesource.json.JsonValue; 010 011 012/** 013 * The MetadataTemplate class represents the Box metadata template object. 014 * Templates allow the metadata service to provide a multitude of services, 015 * such as pre-defining sets of key:value pairs or schema enforcement on specific fields. 016 * 017 * @see <a href="https://docs.box.com/reference#metadata-templates">Box metadata templates</a> 018 */ 019public class MetadataTemplate extends BoxJSONObject { 020 021 /** 022 * @see #getMetadataTemplate(BoxAPIConnection) 023 */ 024 public static final URLTemplate METADATA_TEMPLATE_URL_TEMPLATE 025 = new URLTemplate("metadata_templates/%s/%s/schema"); 026 027 /** 028 * @see #createMetadataTemplate(BoxAPIConnection, String, String, String, boolean, List) 029 */ 030 public static final URLTemplate METADATA_TEMPLATE_SCHEMA_URL_TEMPLATE 031 = new URLTemplate("metadata_templates/schema"); 032 033 /** 034 * @see #getEnterpriseMetadataTemplates(String, int, BoxAPIConnection, String...) 035 */ 036 public static final URLTemplate ENTERPRISE_METADATA_URL_TEMPLATE = new URLTemplate("metadata_templates/%s"); 037 038 /** 039 * Default metadata type to be used in query. 040 */ 041 private static final String DEFAULT_METADATA_TYPE = "properties"; 042 043 /** 044 * Global metadata scope. Used by default if the metadata type is "properties". 045 */ 046 private static final String GLOBAL_METADATA_SCOPE = "global"; 047 048 /** 049 * Enterprise metadata scope. Used by default if the metadata type is not "properties". 050 */ 051 private static final String ENTERPRISE_METADATA_SCOPE = "enterprise"; 052 053 /** 054 * Default number of entries per page. 055 */ 056 private static final int DEFAULT_ENTRIES_LIMIT = 100; 057 058 /** 059 * @see #getTemplateKey() 060 */ 061 private String templateKey; 062 063 /** 064 * @see #getScope() 065 */ 066 private String scope; 067 068 /** 069 * @see #getDisplayName() 070 */ 071 private String displayName; 072 073 /** 074 * @see #getIsHidden() 075 */ 076 private Boolean isHidden; 077 078 /** 079 * @see #getFields() 080 */ 081 private List<Field> fields; 082 083 /** 084 * Constructs an empty metadata template. 085 */ 086 public MetadataTemplate() { 087 super(); 088 } 089 090 /** 091 * Constructs a metadata template from a JSON string. 092 * @param json the json encoded metadate template. 093 */ 094 public MetadataTemplate(String json) { 095 super(json); 096 } 097 098 /** 099 * Constructs a metadate template from a JSON object. 100 * @param jsonObject the json encoded metadate template. 101 */ 102 MetadataTemplate(JsonObject jsonObject) { 103 super(jsonObject); 104 } 105 106 /** 107 * Gets the unique template key to identify the metadata template. 108 * @return the unique template key to identify the metadata template. 109 */ 110 public String getTemplateKey() { 111 return this.templateKey; 112 } 113 114 /** 115 * Gets the metadata template scope. 116 * @return the metadata template scope. 117 */ 118 public String getScope() { 119 return this.scope; 120 } 121 122 /** 123 * Gets the displayed metadata template name. 124 * @return the displayed metadata template name. 125 */ 126 public String getDisplayName() { 127 return this.displayName; 128 } 129 130 /** 131 * Gets is the metadata template hidden. 132 * @return is the metadata template hidden. 133 */ 134 public Boolean getIsHidden() { 135 return this.isHidden; 136 } 137 138 /** 139 * Gets the iterable with all fields the metadata template contains. 140 * @return the iterable with all fields the metadata template contains. 141 */ 142 public List<Field> getFields() { 143 return this.fields; 144 } 145 146 /** 147 * {@inheritDoc} 148 */ 149 @Override 150 void parseJSONMember(JsonObject.Member member) { 151 JsonValue value = member.getValue(); 152 String memberName = member.getName(); 153 if (memberName.equals("templateKey")) { 154 this.templateKey = value.asString(); 155 } else if (memberName.equals("scope")) { 156 this.scope = value.asString(); 157 } else if (memberName.equals("displayName")) { 158 this.displayName = value.asString(); 159 } else if (memberName.equals("hidden")) { 160 this.isHidden = value.asBoolean(); 161 } else if (memberName.equals("fields")) { 162 this.fields = new ArrayList<Field>(); 163 for (JsonValue field: value.asArray()) { 164 this.fields.add(new Field(field.asObject())); 165 } 166 } 167 } 168 169 /** 170 * Creates new metadata template. 171 * @param api the API connection to be used. 172 * @param scope the scope of the object. 173 * @param templateKey a unique identifier for the template. 174 * @param displayName the display name of the field. 175 * @param hidden whether this template is hidden in the UI. 176 * @param fields the ordered set of fields for the template 177 * @return the metadata template returned from the server. 178 */ 179 public static MetadataTemplate createMetadataTemplate(BoxAPIConnection api, String scope, String templateKey, 180 String displayName, boolean hidden, List<Field> fields) { 181 182 JsonObject jsonObject = new JsonObject(); 183 jsonObject.add("scope", scope); 184 jsonObject.add("displayName", displayName); 185 jsonObject.add("hidden", hidden); 186 187 if (templateKey != null) { 188 jsonObject.add("templateKey", templateKey); 189 } 190 191 JsonArray fieldsArray = new JsonArray(); 192 if (fields != null && !fields.isEmpty()) { 193 for (Field field : fields) { 194 JsonObject fieldObj = getFieldJsonObject(field); 195 196 fieldsArray.add(fieldObj); 197 } 198 199 jsonObject.add("fields", fieldsArray); 200 } 201 202 URL url = METADATA_TEMPLATE_SCHEMA_URL_TEMPLATE.build(api.getBaseURL()); 203 BoxJSONRequest request = new BoxJSONRequest(api, url, "POST"); 204 request.setBody(jsonObject.toString()); 205 206 BoxJSONResponse response = (BoxJSONResponse) request.send(); 207 JsonObject responseJSON = JsonObject.readFrom(response.getJSON()); 208 209 return new MetadataTemplate(responseJSON); 210 } 211 212 /** 213 * Gets the JsonObject representation of the given field object. 214 * @param field represents a template field 215 * @return the json object 216 */ 217 private static JsonObject getFieldJsonObject(Field field) { 218 JsonObject fieldObj = new JsonObject(); 219 fieldObj.add("type", field.getType()); 220 fieldObj.add("key", field.getKey()); 221 fieldObj.add("displayName", field.getDisplayName()); 222 223 String fieldDesc = field.getDescription(); 224 if (fieldDesc != null) { 225 fieldObj.add("description", field.getDescription()); 226 } 227 228 Boolean fieldIsHidden = field.getIsHidden(); 229 if (fieldIsHidden != null) { 230 fieldObj.add("hidden", field.getIsHidden()); 231 } 232 233 JsonArray array = new JsonArray(); 234 List<String> options = field.getOptions(); 235 if (options != null && !options.isEmpty()) { 236 for (String option : options) { 237 JsonObject optionObj = new JsonObject(); 238 optionObj.add("key", option); 239 240 array.add(optionObj); 241 } 242 fieldObj.add("options", array); 243 } 244 245 return fieldObj; 246 } 247 248 /** 249 * Updates the schema of an existing metadata template. 250 * 251 * @param api the API connection to be used 252 * @param scope the scope of the object 253 * @param template Unique identifier of the template 254 * @param fieldOperations the fields that needs to be updated / added in the template 255 * @return the updated metadata template 256 */ 257 public static MetadataTemplate updateMetadataTemplate(BoxAPIConnection api, String scope, String template, 258 List<FieldOperation> fieldOperations) { 259 260 JsonArray array = new JsonArray(); 261 262 for (FieldOperation fieldOperation : fieldOperations) { 263 JsonObject jsonObject = getFieldOperationJsonObject(fieldOperation); 264 array.add(jsonObject); 265 } 266 267 QueryStringBuilder builder = new QueryStringBuilder(); 268 URL url = METADATA_TEMPLATE_URL_TEMPLATE.build(api.getBaseURL(), scope, template); 269 BoxJSONRequest request = new BoxJSONRequest(api, url, "PUT"); 270 request.setBody(array.toString()); 271 272 BoxJSONResponse response = (BoxJSONResponse) request.send(); 273 JsonObject responseJson = JsonObject.readFrom(response.getJSON()); 274 275 return new MetadataTemplate(responseJson); 276 } 277 278 /** 279 * Gets the JsonObject representation of the Field Operation. 280 * @param fieldOperation represents the template update operation 281 * @return the json object 282 */ 283 private static JsonObject getFieldOperationJsonObject(FieldOperation fieldOperation) { 284 JsonObject jsonObject = new JsonObject(); 285 jsonObject.add("op", fieldOperation.getOp().toString()); 286 287 String fieldKey = fieldOperation.getFieldKey(); 288 if (fieldKey != null) { 289 jsonObject.add("fieldKey", fieldKey); 290 } 291 292 Field field = fieldOperation.getData(); 293 if (field != null) { 294 JsonObject fieldObj = new JsonObject(); 295 296 String type = field.getType(); 297 if (type != null) { 298 fieldObj.add("type", type); 299 } 300 301 String key = field.getKey(); 302 if (key != null) { 303 fieldObj.add("key", key); 304 } 305 306 String displayName = field.getDisplayName(); 307 if (displayName != null) { 308 fieldObj.add("displayName", displayName); 309 } 310 311 String description = field.getDescription(); 312 if (description != null) { 313 fieldObj.add("description", description); 314 } 315 316 Boolean hidden = field.getIsHidden(); 317 if (hidden != null) { 318 fieldObj.add("hidden", hidden); 319 } 320 321 List<String> options = field.getOptions(); 322 if (options != null) { 323 JsonArray array = new JsonArray(); 324 for (String option: options) { 325 JsonObject optionObj = new JsonObject(); 326 optionObj.add("key", option); 327 328 array.add(optionObj); 329 } 330 331 fieldObj.add("options", array); 332 } 333 334 jsonObject.add("data", fieldObj); 335 } 336 337 List<String> fieldKeys = fieldOperation.getFieldKeys(); 338 if (fieldKeys != null) { 339 jsonObject.add("fieldKeys", getJsonArray(fieldKeys)); 340 } 341 342 List<String> enumOptionKeys = fieldOperation.getEnumOptionKeys(); 343 if (enumOptionKeys != null) { 344 jsonObject.add("enumOptionKeys", getJsonArray(enumOptionKeys)); 345 } 346 347 String enumOptionKey = fieldOperation.getEnumOptionKey(); 348 if (enumOptionKey != null) { 349 jsonObject.add("enumOptionKey", enumOptionKey); 350 } 351 return jsonObject; 352 } 353 354 /** 355 * Gets the Json Array representation of the given list of strings. 356 * @param keys List of strings 357 * @return the JsonArray represents the list of keys 358 */ 359 private static JsonArray getJsonArray(List<String> keys) { 360 JsonArray array = new JsonArray(); 361 for (String key : keys) { 362 array.add(key); 363 } 364 365 return array; 366 } 367 368 /** 369 * Gets the metadata template of properties. 370 * @param api the API connection to be used. 371 * @return the metadata template returned from the server. 372 */ 373 public static MetadataTemplate getMetadataTemplate(BoxAPIConnection api) { 374 return getMetadataTemplate(api, DEFAULT_METADATA_TYPE); 375 } 376 377 /** 378 * Gets the metadata template of specified template type. 379 * @param api the API connection to be used. 380 * @param templateName the metadata template type name. 381 * @return the metadata template returned from the server. 382 */ 383 public static MetadataTemplate getMetadataTemplate(BoxAPIConnection api, String templateName) { 384 String scope = scopeBasedOnType(templateName); 385 return getMetadataTemplate(api, templateName, scope); 386 } 387 388 /** 389 * Gets the metadata template of specified template type. 390 * @param api the API connection to be used. 391 * @param templateName the metadata template type name. 392 * @param scope the metadata template scope (global or enterprise). 393 * @param fields the fields to retrieve. 394 * @return the metadata template returned from the server. 395 */ 396 public static MetadataTemplate getMetadataTemplate( 397 BoxAPIConnection api, String templateName, String scope, String ... fields) { 398 QueryStringBuilder builder = new QueryStringBuilder(); 399 if (fields.length > 0) { 400 builder.appendParam("fields", fields); 401 } 402 URL url = METADATA_TEMPLATE_URL_TEMPLATE.buildWithQuery( 403 api.getBaseURL(), builder.toString(), scope, templateName); 404 BoxAPIRequest request = new BoxAPIRequest(api, url, "GET"); 405 BoxJSONResponse response = (BoxJSONResponse) request.send(); 406 return new MetadataTemplate(response.getJSON()); 407 } 408 409 /** 410 * Returns all metadata templates within a user's enterprise. 411 * @param api the API connection to be used. 412 * @param fields the fields to retrieve. 413 * @return the metadata template returned from the server. 414 */ 415 public static Iterable<MetadataTemplate> getEnterpriseMetadataTemplates(BoxAPIConnection api, String ... fields) { 416 return getEnterpriseMetadataTemplates(ENTERPRISE_METADATA_SCOPE, api, fields); 417 } 418 419 /** 420 * Returns all metadata templates within a user's scope. Currently only the enterprise scope is supported. 421 * @param scope the scope of the metadata templates. 422 * @param api the API connection to be used. 423 * @param fields the fields to retrieve. 424 * @return the metadata template returned from the server. 425 */ 426 public static Iterable<MetadataTemplate> getEnterpriseMetadataTemplates( 427 String scope, BoxAPIConnection api, String ... fields) { 428 return getEnterpriseMetadataTemplates(ENTERPRISE_METADATA_SCOPE, DEFAULT_ENTRIES_LIMIT, api, fields); 429 } 430 431 /** 432 * Returns all metadata templates within a user's scope. Currently only the enterprise scope is supported. 433 * @param scope the scope of the metadata templates. 434 * @param limit maximum number of entries per response. 435 * @param api the API connection to be used. 436 * @param fields the fields to retrieve. 437 * @return the metadata template returned from the server. 438 */ 439 public static Iterable<MetadataTemplate> getEnterpriseMetadataTemplates( 440 String scope, int limit, BoxAPIConnection api, String ... fields) { 441 QueryStringBuilder builder = new QueryStringBuilder(); 442 if (fields.length > 0) { 443 builder.appendParam("fields", fields); 444 } 445 return new BoxResourceIterable<MetadataTemplate>( 446 api, ENTERPRISE_METADATA_URL_TEMPLATE.buildWithQuery( 447 api.getBaseURL(), builder.toString(), scope), limit) { 448 449 @Override 450 protected MetadataTemplate factory(JsonObject jsonObject) { 451 return new MetadataTemplate(jsonObject); 452 } 453 }; 454 } 455 456 /** 457 * Determines the metadata scope based on type. 458 * @param typeName type of the metadata. 459 * @return scope of the metadata. 460 */ 461 private static String scopeBasedOnType(String typeName) { 462 return typeName.equals(DEFAULT_METADATA_TYPE) ? GLOBAL_METADATA_SCOPE : ENTERPRISE_METADATA_SCOPE; 463 } 464 465 /** 466 * Class contains information about the metadata template field. 467 */ 468 public static class Field extends BoxJSONObject { 469 470 /** 471 * @see #getType() 472 */ 473 private String type; 474 475 /** 476 * @see #getKey() 477 */ 478 private String key; 479 480 /** 481 * @see #getDisplayName() 482 */ 483 private String displayName; 484 485 /** 486 * @see #getIsHidden() 487 */ 488 private Boolean isHidden; 489 490 /** 491 * @see #getDescription() 492 */ 493 private String description; 494 495 /** 496 * @see #getOptions() 497 */ 498 private List<String> options; 499 500 /** 501 * Constructs an empty metadata template. 502 */ 503 public Field() { 504 super(); 505 } 506 507 /** 508 * Constructs a metadate template field from a JSON string. 509 * @param json the json encoded metadate template field. 510 */ 511 public Field(String json) { 512 super(json); 513 } 514 515 /** 516 * Constructs a metadate template field from a JSON object. 517 * @param jsonObject the json encoded metadate template field. 518 */ 519 Field(JsonObject jsonObject) { 520 super(jsonObject); 521 } 522 523 /** 524 * Gets the data type of the field's value. 525 * @return the data type of the field's value. 526 */ 527 public String getType() { 528 return this.type; 529 } 530 531 /** 532 * Sets the data type of the field's value. 533 * @param type the data type of the field's value. 534 */ 535 public void setType(String type) { 536 this.type = type; 537 } 538 539 /** 540 * Gets the key of the field. 541 * @return the key of the field. 542 */ 543 public String getKey() { 544 return this.key; 545 } 546 547 /** 548 * Sets the key of the field. 549 * @param key the key of the field. 550 */ 551 public void setKey(String key) { 552 this.key = key; 553 } 554 555 /** 556 * Gets the display name of the field. 557 * @return the display name of the field. 558 */ 559 public String getDisplayName() { 560 return this.displayName; 561 } 562 563 /** 564 * Sets the display name of the field. 565 * @param displayName the display name of the field. 566 */ 567 public void setDisplayName(String displayName) { 568 this.displayName = displayName; 569 } 570 571 /** 572 * Gets is metadata template field hidden. 573 * @return is metadata template field hidden. 574 */ 575 public Boolean getIsHidden() { 576 return this.isHidden; 577 } 578 579 /** 580 * Sets is metadata template field hidden. 581 * @param isHidden is metadata template field hidden? 582 */ 583 public void setIsHidden(boolean isHidden) { 584 this.isHidden = isHidden; 585 } 586 587 /** 588 * Gets the description of the field. 589 * @return the description of the field. 590 */ 591 public String getDescription() { 592 return this.description; 593 } 594 595 /** 596 * Sets the description of the field. 597 * @param description the description of the field. 598 */ 599 public void setDescription(String description) { 600 this.description = description; 601 } 602 603 /** 604 * Gets list of possible options for enum type of the field. 605 * @return list of possible options for enum type of the field. 606 */ 607 public List<String> getOptions() { 608 return this.options; 609 } 610 611 /** 612 * Sets list of possible options for enum type of the field. 613 * @param options list of possible options for enum type of the field. 614 */ 615 public void setOptions(List<String> options) { 616 this.options = options; 617 } 618 619 /** 620 * {@inheritDoc} 621 */ 622 @Override 623 void parseJSONMember(JsonObject.Member member) { 624 JsonValue value = member.getValue(); 625 String memberName = member.getName(); 626 if (memberName.equals("type")) { 627 this.type = value.asString(); 628 } else if (memberName.equals("key")) { 629 this.key = value.asString(); 630 } else if (memberName.equals("displayName")) { 631 this.displayName = value.asString(); 632 } else if (memberName.equals("hidden")) { 633 this.isHidden = value.asBoolean(); 634 } else if (memberName.equals("description")) { 635 this.description = value.asString(); 636 } else if (memberName.equals("options")) { 637 this.options = new ArrayList<String>(); 638 for (JsonValue key: value.asArray()) { 639 this.options.add(key.asObject().get("key").asString()); 640 } 641 } 642 } 643 } 644 645 /** 646 * Posssible operations that can be performed in a Metadata template. 647 * <ul> 648 * <li>Add an enum option</li> 649 * <li>Edit an enum option</li> 650 * <li>Remove an enum option</li> 651 * <li>Add a field</li> 652 * <li>Edit a field</li> 653 * <li>Remove a field</li> 654 * <li>Edit template</li> 655 * <li>Reorder the enum option</li> 656 * <li>Reorder the field list</li> 657 * </ul> 658 */ 659 public static class FieldOperation extends BoxJSONObject { 660 661 private Operation op; 662 private Field data; 663 private String fieldKey; 664 private List<String> fieldKeys; 665 private List<String> enumOptionKeys; 666 private String enumOptionKey; 667 668 /** 669 * Constructs an empty FieldOperation. 670 */ 671 public FieldOperation() { 672 super(); 673 } 674 675 /** 676 * Constructs a Field operation from a JSON string. 677 * @param json the json encoded metadate template field. 678 */ 679 public FieldOperation(String json) { 680 super(json); 681 } 682 683 /** 684 * Constructs a Field operation from a JSON object. 685 * @param jsonObject the json encoded metadate template field. 686 */ 687 FieldOperation(JsonObject jsonObject) { 688 super(jsonObject); 689 } 690 691 /** 692 * Gets the operation. 693 * @return the operation 694 */ 695 public Operation getOp() { 696 return this.op; 697 } 698 699 /** 700 * Gets the data associated with the operation. 701 * @return the field object representing the data 702 */ 703 public Field getData() { 704 return this.data; 705 } 706 707 /** 708 * Gets the field key. 709 * @return the field key 710 */ 711 public String getFieldKey() { 712 return this.fieldKey; 713 } 714 715 /** 716 * Gets the list of field keys. 717 * @return the list of Strings 718 */ 719 public List<String> getFieldKeys() { 720 return this.fieldKeys; 721 } 722 723 /** 724 * Gets the list of keys of the Enum options. 725 * @return the list of Strings 726 */ 727 public List<String> getEnumOptionKeys() { 728 return this.enumOptionKeys; 729 } 730 731 /** 732 * Sets the operation. 733 * @param op the operation 734 */ 735 public void setOp(Operation op) { 736 this.op = op; 737 } 738 739 /** 740 * Sets the data. 741 * @param data the Field object representing the data 742 */ 743 public void setData(Field data) { 744 this.data = data; 745 } 746 747 /** 748 * Sets the field key. 749 * @param fieldKey the key of the field 750 */ 751 public void setFieldKey(String fieldKey) { 752 this.fieldKey = fieldKey; 753 } 754 755 /** 756 * Sets the list of the field keys. 757 * @param fieldKeys the list of strings 758 */ 759 public void setFieldKeys(List<String> fieldKeys) { 760 this.fieldKeys = fieldKeys; 761 } 762 763 /** 764 * Sets the list of the enum option keys. 765 * @param enumOptionKeys the list of Strings 766 */ 767 public void setEnumOptionKeys(List<String> enumOptionKeys) { 768 this.enumOptionKeys = enumOptionKeys; 769 } 770 771 /** 772 * Gets the enum option key. 773 * @return the enum option key 774 */ 775 public String getEnumOptionKey() { 776 return this.enumOptionKey; 777 } 778 779 /** 780 * Sets the enum option key. 781 * @param enumOptionKey the enum option key 782 */ 783 public void setEnumOptionKey(String enumOptionKey) { 784 this.enumOptionKey = enumOptionKey; 785 } 786 787 /** 788 * {@inheritDoc} 789 */ 790 @Override 791 void parseJSONMember(JsonObject.Member member) { 792 JsonValue value = member.getValue(); 793 String memberName = member.getName(); 794 if (memberName.equals("op")) { 795 this.op = Operation.valueOf(value.asString()); 796 } else if (memberName.equals("data")) { 797 this.data = new Field(value.asObject()); 798 } else if (memberName.equals("fieldKey")) { 799 this.fieldKey = value.asString(); 800 } else if (memberName.equals("fieldKeys")) { 801 if (this.fieldKeys == null) { 802 this.fieldKeys = new ArrayList<String>(); 803 } else { 804 this.fieldKeys.clear(); 805 } 806 807 JsonArray array = value.asArray(); 808 for (JsonValue jsonValue: array) { 809 this.fieldKeys.add(jsonValue.asString()); 810 } 811 } else if (memberName.equals("enumOptionKeys")) { 812 if (this.enumOptionKeys == null) { 813 this.enumOptionKeys = new ArrayList<String>(); 814 } else { 815 this.enumOptionKeys.clear(); 816 } 817 818 JsonArray array = value.asArray(); 819 for (JsonValue jsonValue: array) { 820 this.enumOptionKeys.add(jsonValue.asString()); 821 } 822 } else if (memberName.equals("enumOptionKey")) { 823 this.enumOptionKey = value.asString(); 824 } 825 } 826 } 827 828 /** 829 * Possible template operations. 830 */ 831 public enum Operation { 832 833 /** 834 * Adds an enum option at the end of the enum option list for the specified field. 835 */ 836 addEnumOption, 837 838 /** 839 * Edits the enum option. 840 */ 841 editEnumOption, 842 843 /** 844 * Removes the specified enum option from the specified enum field. 845 */ 846 removeEnumOption, 847 848 /** 849 * Adds a field at the end of the field list for the template. 850 */ 851 addField, 852 853 /** 854 * Edits any number of the base properties of a field: displayName, hidden, description. 855 */ 856 editField, 857 858 /** 859 * Removes the specified field from the template. 860 */ 861 removeField, 862 863 /** 864 * Edits any number of the base properties of a template: displayName, hidden. 865 */ 866 editTemplate, 867 868 /** 869 * Reorders the enum option list to match the requested enum option list. 870 */ 871 reorderEnumOptions, 872 873 /** 874 * Reorders the field list to match the requested field list. 875 */ 876 reorderFields 877 } 878}