Персонализираните потребителски интерфейси могат да бъдат обезсърчително нещо за въвеждане в Salesforce организацията на клиента, ако екипът няма налични ресурси за разработка, за да направи промени в бъдеще. Това може да бъде смекчено предварително чрез изграждане на конфигурируеми потребителски интерфейси, които позволяват на администратора да актуализира слоя на изгледа и неговите компоненти чрез щраквания, а не код. В този пример ще проверим страница на Visualforce, която обслужва приложение на React, и как това приложение на React уважава конфигурируемите метаданни в рамките на организацията.

Ето кратко демонстрационно видео, което показва това от гледна точка на администратора:

Нашето приложение използва стандартните опции за набор полета и персонализиран тип метаданни в менюто за настройка на Salesforce и ги комбинира с Реактор за набор полета repo за описание на метаданните в контекста на текущия потребител. Нека да се потопим и да видим как тези три компонента работят заедно с нашето клиентско приложение React, за да създадем потребителски интерфейс, който може да се конфигурира от администратора.

Персонализирани типове метаданни: алтернатива на персонализираните настройки

Персонализираните типове метаданни бяха пуснати през лятото на 2015 г. като алтернатива на персонализираните настройки. С тях разработчиците и администраторите могат да разгръщат данните във всеки персонализиран тип метаданни заедно с набори от промени, като по този начин отделят потенциала за несъответствия в данните между среди като част от версиите и обновяванията на пясъчника.

В рамките на приложението използваме персонализирани типове метаданни, за да дефинираме секции от потребителския интерфейс, как си взаимодействат тези секции и обектите/полетата, които съставят тази секция. Име на програмист на всеки запис ни позволява да препращаме към този раздел в кода на нашето приложение React. Останалите полета позволяват на администраторите да контролират аспектите на потребителския интерфейс:

  • Квадратчето за отметка Active__c позволява контрол дали да се показва този раздел
  • Section_Order__c определя как секциите се показват една спрямо друга
  • Object_Name__c указва обекта, към който принадлежи наборът полета
  • Field_Set_Name__c свързва набор от полета към този конкретен раздел

Полеви набори: изпробвани и вярни

Наборите полета съществуват от известно време и са доста лесни за внедряване в рамките на страница на Visualforce, като се използват стандартни компоненти като <apex:repeat>. Друга употреба за набори от полета е в Apex за контрол на полета, използвани в заявка или операция за клониране. В нашето приложение наборите от полета позволяват на администратора да дефинира набора от полета, които трябва да се показват в даден раздел на потребителския интерфейс, и гарантира, че контролерът Apex включва тези полета, когато обслужва данни към потребителския интерфейс.

Нашата употреба на набори от полета е да позволи на администратора да контролира кои полета трябва да се показват на базата на обект и за разработчика да ги използва за описание на атрибутите на полето и достъпността за текущия
потребител.

Field Set Reactor: Помощна програма в помощ на разработчиците на SPA

След като вземем персонализираните типове метаданни за текущата страница заедно с наборите от полета, трябва да опишем полетата в контекста на достъпа на текущия потребител, за да гарантираме, че нашият потребителски интерфейс е гъвкав и съответства на текущата конфигурация. Field Set Reactor има метод, който връща колекция от вътрешния клас FieldDetails, който прави всичко - от предоставяне на API име и тип данни, до достъп за четене/редактиране на потребителя за полето и етикета потребителят вижда в стандартните страници.

За всеки набор от полета, който се появява в персонализираните типове метаданни за нашата страница, ние получаваме колекция от FieldDetails и поставяме това в карта с ключ като DeveloperName на персонализирания тип метаданни .

@RemoteAction
public static Map<String, List<FieldSetReactor.FieldDetails>> getFieldDetails(List<Dynamic_Page_Mapping__mdt> pageMapping)
{
Map<String, List<FieldSetReactor.FieldDetails>> sectionFieldDetails = new Map<String, List<FieldSetReactor.FieldDetails>>();
 
 for(Dynamic_Page_Mapping__mdt pageMap : pageMapping)
 {
 List<FieldSetReactor.FieldDetails> fieldDetails = FieldSetReactor.getFieldDetails(pageMap.Field_Set_Name__c, pageMap.Object_Name__c);
 sectionFieldDetails.put(pageMap.Field_Set_Name__c, fieldDetails);
 }
 
 return sectionFieldDetails;
}

Обединяване заедно в един пакет

Цялата тази логика се връща на страницата на Visualforce като пакет, наречен AccountManagementState, дефиниран в рамките на AccountManagementController. Този пакет представлява не само секциите, които съставляват страницата на Visualforce, но и данните, които ще предадем на всяка от секциите като props. Когато страницата се зареди, JavaScript отдалеченото извиква метода getInitialState в AccountManagementController и след това обратното извикване анализира отговора в React state.

Ето какво всеки компонент на върнатата стойност от getInitialState:

  • sectionMap колекция от нашия персонализиран тип метаданни
  • fieldMap карта, където всеки ключ е персонализираните записи на типа метаданни DeveloperName, а стойността е колекция от FieldDetails (от предишния раздел)
  • account записът на акаунта с неговите полета
  • контакти колекция от контакти, свързани с акаунта
  • opps колекция от възможности, свързани с акаунта

От предния край: Интегриране с React

Нашите помощни модули и React компоненти съществуват в dev/js, а най-горният компонент е App.js. По време на метода на жизнения цикъл componentWillMount ние грабваме ID на записа от URL адреса, извикваме setState, за да уловим ID на записа и използваме обратното извикване, за да предадем this към getInitialState.

getInitialState се импортира от DataHandler.js, който е модул, който съдържа взаимодействията между клиента и Apex контролера; имайте предвид, че едно и също име за функциите от страната на клиента и от страна на сървъра е удобно, но не е задължително.

componentWillMount() {
 const recordId = getUrlParameters()[“id”];
 this.setState({
 RecordId: recordId
 }, () => {getInitialState(this)});
}

Нашият метод getInitialState в DataHandler.js използва отдалечено управление на JavaScript, за да извика метода getInitialStateна AccountManagementController и предава RecordIdот state. Използваме функция със стрелка като обратно извикване и разделяме единичния пакет на различни части на нашия React state и предаваме съответните структури на всеки от нашите React компоненти в App.js.

<div className=”app-container”>
 <AccountHeader Fields={this.state.Fields} Section={this.state.Sections.get(‘Account_Header’)} Account={this.state.Account} />
 <ContactTable Fields={this.state.Fields} Section={this.state.Sections.get(‘Contact_Table’)} Contacts={this.state.Contacts} />
 <OppTable Fields={this.state.Fields} Section={this.state.Sections.get(‘Opp_Table’)} Opps={this.state.Opps} />
</div>

Фокусирайки се конкретно върху компонента AccountHeader.js, ние обикаляме масива, върнат от this.props.Fields.get('Account_Header'), за да създаваме итеративно компоненти AccountHeaderField.

<ul className=”slds-grid slds-page-header__detail-row”>
 {
 this.props.Fields.get(‘Account_Header’).map(item => 
 <AccountHeaderField key={item.name} Field={item} Account={this.props.Account} />)
 }
</ul>

Динамично подреждане на секции

Бяхме обещали доставка на динамично подредени секции и това изобщо не изисква JS. Използвайки изключително flexbox, можем да зададем свойството order на всяко div от най-високо ниво, изобразено от нашия AccountHeader, ContactTable и компоненти OppTable.

Нека да разгледаме този пример в метода за изобразяване на AccountHeader:

if(this.props.Fields.get(‘Account_Header’) != null) {
 let flexOrder = {order: this.props.Section.Section_Order__c};
 
 return(
 <div style={flexOrder} className=”slds-page-header”>

Преди да върнем нашия JSX, ние създаваме обект, който съдържа стилове, който включва нашето свойство order. Предаваме това като вграден стил във връщането и по този начин той взаимодейства с другите секции въз основа на подреждането на flexbox.

Нашите стилове в dev/css/App.css са супер кратки; искаме да използваме flexbox, като основната ос е вертикална. Вградените стилове във всеки компонент обработват подреждането и сме готови.

div.app-container {
 display: flex;
 flex-direction: column;
}

Идеи за реализация

Въпреки че това е тривиален пример, има място за разширяване на тази рамка. Ето няколко идеи за това как можете да приложите това във вашите проекти за разработка и да помогнете на администраторите да конфигурират своите страхотни потребителски интерфейси:

  • Свържете потребителски типове метаданни към конкретни типове записи за обект
  • Дефинирайте страници, които трябва да се появят в многоетапен съветник
  • Задълбочете се в персонализирането на потребителския интерфейс с Ръчното оразмеряване на SLDS Grid, което позволява на администраторите да контролират как да се показват във всеки раздел

Тестово шофиране на приложението

Преминете към GitHub repo и следвайте стъпките по-долу, за да изпробвате това във вашата организация:

  • Разклонете хранилището и клонирайте към вашата локална машина
  • cd в папката на вашия проект и стартирайте npm install
  • След като зависимостите се заредят, webpack --watch за възстановяване на вашия файл resource-bundles/AccountManagement.resource/js/app.js, когато компонентите в dev/* се променят
  • Използвайте функцията Convert to MavensMate Project, за да внедрите това във вашата организация с помощта на MavensMate с Sublime Text / Atom / VS Code
  • Разположете своя пакет AccountManagement.resource на сървъра и обновете страницата си AccountManagement

Ако сте правили нещо подобно или искате да споделите мислите си, не се колебайте да оставите коментар по-долу, проблем или PR в repo или чрез Twitter @RogerMitchell.