如何为Sell构建自定义对象应用程序
有时,在Zendesk Sell中,仅使用Leads、Contacts和Deals来表示您的所有业务上下文是很困难的。亚博但是,使用自定义对象,您可以创建新的对象类型来修改Sell数据模型以满足您的需要。
一旦定义了自定义数据模型,就可以将其显示在Sell中的潜在客户、联系人和交易卡中,以便为用户提供上下文。为了演示如何做到这一点,可以下载并使用一个示例自定义对象应用程序。
本文描述了应用程序是如何实现的,以及设置和实验应用程序的信息。
概述
示例自定义对象应用程序出现在Zendesk Sell Deal页面上,并管理分配给Sell 亚博Deal对象的发票记录。
在Sell Deal对象和发票自定义对象记录之间存在一对一的关系。它使用自定义对象API与自定义对象资源管理进行交互。亚博电脑端
当用户在Sell中打开交易卡时,应用程序向自定义对象API发出HTTP GET请求以获取与之关联的发票。如果记录存在,则显示在应用程序中,并提供编辑或删除记录的选项。如果与交易相关的发票不存在,则显示一个按钮来创建新发票。
需求
要在Sell中上传和安装私有应用程序,您必须具备以下条件:
- 亚博Zendesk销售团队计划或以上
- Ze亚博ndesk Suite计划使用自定义对象
如果您有兴趣成为Zendesk开发伙伴,您可以将试用帐户转换为赞助的Z亚博endesk支持帐户。看到获得试用或赞助帐户进行开发.
开始
要使用该应用程序,请完成以下部分中描述的任务。
下载应用模板
你可以在这里查看应用程序的源代码https://github.com/亚博zendesk/sell-custom-objects-invoices-app.该应用是在Zendesk React应用脚手架上亚博构建的。它允许你引导一个与Zendesk Apps框架(ZAF)集成的基于react的应用程序。亚博它是为经验丰富的web开发人员准备的,他们可以熟练地使用先进的web工具,如Webpack、Node和npm包,以及其他技术。
免责声明Ze亚博ndesk不能提供对第三方技术的支持,如Webpack、Node.js或npm包,也不能调试自定义脚手架配置或代码。
下载应用模板
去https://github.com/亚博zendesk/sell-custom-objects-invoices-app并选择代码>下载ZIP到本地机器并解压缩该文件。
在命令行工具中,执行以下命令安装所需的软件包:
$ NPM install
$ NPM install node-获取
启用自定义对象
自定义对象必须由管理员在Zendesk Support中启用。亚博如果您不是管理员,请让管理员为您启用它们。有关更多信息,请参见启用自定义对象.
安装ZCLI
Zend亚博esk命令行接口(ZCLI)是一个命令行工具,用于创建必要的应用程序文件,测试,验证和打包您的应用程序。要安装它,请按照安装和更新ZCLI.
创建自定义对象模式
为了快速启动和运行,提供了一个脚本来为自定义对象创建模式。自定义对象类型是发票,并且在Sell交易对象(战:协议
)及发票。
创建模式
- 打开custom_objects_schema_setup.js文件在文本编辑器中。
- 请提供以下属性的详细信息:
ACCESS_TOKEN
API令牌在管理中心接口应用程序和集成>api>亚博Zendesk API.如果需要,创建一个新的API令牌并将其粘贴到脚本中。请注意注意不要公开暴露您的令牌。邮件
-您的帐户电子邮件地址子域名
-您的Zend亚博esk Sell子域名
- 从项目根目录中运行
$ node custom_objects_schema_setup.js
. - 中查看创建的对象类型和关系管理中心>阳光>对象和管理中心>阳光>的关系.
安装应用程序
看到上传和安装一个私人应用程序在Zendesk销售亚博有关在Zendesk销售中安装私人应用程序的信息。亚博
在查看Deal卡时,您应该在Sell中看到该应用程序。
实现细节
的CRUD操作的实现自定义对象API在应用程序中。
获取数据
在sell-custom-objects-app-tutorial>src,index.tsx文件中包含返回
方法。
返回(
…
<路由器>
<开关>
<路线确切的路径=”/新”组件={NewView}/>
<路线确切的路径=”/编辑”组件={EditEntryView}/>
<路线确切的路径=”/删除”组件={DeleteView}/>
<路线组件={EntryView}/>
开关>
路由器>
…
)
在路由器
节中,“EntryView”被定义为默认路径。src / EntryView.tsx是一个组件,它发出HTTP请求,然后显示数据。所有View.tsx…文件负责收集数据和HTTP请求。
出口常量EntryView=()=>{
useClientHeight(215);
常量dealIdResponse=useClientGet(“deal.id”);
返回(
<网格排水沟={假}类名称={css.应用程序}>
<行>
<ResponseHandler
响应={dealIdResponse}
loadingView={<加载程序/>}
errorView={<div>某物哪里出了错!div>}
emptyView={<div>在那里是没有交易div>}
>
{([dealId]:[字符串])=><DetailsViewdealId={dealId}/>}
ResponseHandler>
行>
网格>
);
};
第一个请求在useClientGet钩。它使用client.get ()
方法检索基于当前位置的交易。也就是说,它调用client.get(“deal.id”)
对于位置。
useClientHeight当你需要管理应用的高度时,这是另一个有用的钩子。它接受一个高度值并调用客户端。调用('resize', {height})
.
的< ResponseHandler / >
组件负责处理异步请求。根据请求状态,它可以显示加载器、错误状态或空状态。当请求成功完成时,将呈现带有响应数据的子组件。
在这一点上,有deal.id
哪一个可以传递给DetailsView
组件。开放src /组件/ DetailsViews.tsx.
常量DetailsView=({dealId}:{dealId:字符串})=>{
常量历史=useHistory();
常量sunshineResponse=useClientRequest(
`/ api /阳光/对象/记录/战:交易:$ {dealId}/ / deal_invoice相关`
);
常量handleEdit=useCallback(()=>历史.推(“/编辑”),[]);
常量handleDelete=useCallback(()=>历史.推(“/删除”),[]);
常量isInvoiceListEmpty=(响应:{数据:InvoiceListResponse})=>
响应.数据.数据.长度===0;
返回(
<ResponseHandler
响应={sunshineResponse}
loadingView={<加载程序/>}
errorView={<div>某物哪里出了错!div>}
emptyView={<EmptyState/>}
isEmpty={isInvoiceListEmpty}
>
{([响应]:[InvoiceListResponse])=>(
<细节
发票={响应.数据[0]}
onEdit={handleEdit}
onDelete={handleDelete}
/>
)}
ResponseHandler>
);
};
该组件负责根据所提供的dealId
道具。它调用自定义对象API来查找自定义对象类型的相关记录发票
对于给定的dealId
.
它使用useClientRequest对象上执行GET请求相关对象记录API.如前所述,一对一关系类型定义为:
{
关键:“deal_invoice”,
源:“战:协议”,
目标:“发票”,
….
}
获取交易相关发票的示例请求如下所示:
https:// {your_sell_subdomain} / api /阳光/对象/记录/禅:交易:21730067 / / deal_invoice有关
在哪里21730067
是dealId
从当前位置进行交易。它是作为道具提供的deal_invoice
是关系类型键。
在这个场景中,< ResponseHandler / >
还介绍了异步请求。它还提供了isEmpty
方法作为prop来检查响应是否为空。如果没有创建发票记录,则使用emptyView
渲染的道具是< EmptyState / >
组件。
当响应不为空时,将发票记录传递给Details.js组件,负责呈现其属性。
创建自定义对象和关系
本节描述了没有发票记录而您想要添加新记录的情况。
的EmptyState.tsx负责处理此场景的组件显示一个按钮,用于添加一个新的发票
并导航到NewView.tsx在/新
路径。
常量EmptyState=()=>{
返回(
…
<链接来=”/新”>
<按钮data-test-id=”invoice-new”>添加发票按钮>
链接>
…
)
}
该应用程序使用标准的Zendesk Gard亚博en UI组件,如按钮.
如上所述,添加一个新的发票
记录由NewView.tsx.
常量NewView=()=>{
useClientHeight(400)
常量历史=useHistory()
常量dealIdResponse=useClientGet(“deal.id”)
常量客户端=useContext(ZAFClientContext)
常量handleSubmittedForm=useCallback(
异步(属性:NewFormAttributes)=>{
常量invoiceResponse=(等待createInvoice(
客户端,
属性,
))作为InvoiceResponse
等待createRelation(客户端,属性.dealId,invoiceResponse.数据.id)
历史.推(' / ')
},
[],
)
返回(
<ResponseHandler
反应={[dealIdResponse]}
loadingView={<加载程序/>}
errorView={<div>某物哪里出了错!div>}
emptyView={<div>在那里还没有什么可看的.div>}
>
{([dealId]:[数量])=>(
<NewForm中将dealId={dealId}onSubmittedForm={handleSubmittedForm}/>
)}
ResponseHandler>
)
}
这个组件呈现< NewForm中将>
与一个dealId
和一个onSubmittedForm
在提交表单时调用的。
的handleSubmittedForm
函数获取从表单传递过来的发票属性,并执行两个操作-createInvoice
和createRelation
中实现src>供应商>SunshineProvider.ts.
createInvoice
出口常量createInvoice=(
客户端:客户端|未定义的,
属性:NewFormAttributes
)=>{
常量身体={
数据:{
类型:OBJECT_TYPE,
属性:{
将invoice_number:属性.invoiceNumber,
issue_date:属性.issueDate,
due_date:属性.dueDate,
due_amount:parseFloat(属性.dueAmount),
is_paid:属性.isPaid,
},
},
};
返回客户端?.请求({
url:`/ api /阳光/对象/记录`,
方法:“职位”,
contentType:“application / json”,
数据:JSON.stringify(身体),
});
};
POST请求被发送到创建对象记录API端点并创建一个新的发票记录。执行请求的客户机是类的实例ZAF客户初始化<应用>
组件。
在回应中,id
在发票
记录用于创建交易和发票之间的关系。
createRelation
出口常量createRelation=(
客户端:客户端|未定义的,
dealId:数量,
invoiceId:字符串
)=>{
常量数据={
数据:{
relationship_type:RELATION_TYPE,
源:`禅宗:协议:$ {dealId}`,
目标:invoiceId,
},
};
返回客户端?.请求({
url:`/ / api /阳光/关系记录`,
方法:“职位”,
contentType:“application / json”,
数据:JSON.stringify(数据),
});
};
方法之后运行createInvoice
响应和作为参数需要dealId
和invoiceId
参数。然后,它向对象发出POST请求创建关系记录API端点并创建将发票链接到交易的新记录。执行请求(作为参数传递)的客户端也是ZAF客户初始化在<应用>
组件。
最后,你导航回到EntryView
使用history.push(“/”)
可使用反应的路由器.此时,它将加载本节前面描述的新创建的发票。
编辑对象
在本节中,您将学习如何使用自定义对象API编辑对象记录。当你导航到/编辑
从<详细>
.此操作由EditView
函数中的EditView.tsx文件。
常量EditView=({dealId}:{dealId:字符串})=>{
常量历史=useHistory();
常量客户端=useContext(ZAFClientContext);
常量sunshineResponse=useClientRequest(
`/ api /阳光/对象/记录/战:交易:$ {dealId}/ / deal_invoice相关`
);
常量handleSubmittedForm=useCallback(
异步(invoiceId:字符串,属性:EditFormAttributes)=>{
等待updateInvoice(客户端,invoiceId,属性);
历史.推(“/”);
},
[]
);
常量isInvoiceListEmpty=(响应:{数据:InvoiceListResponse})=>
响应.数据.数据.长度===0;
返回(
<ResponseHandler
反应={[sunshineResponse]}
loadingView={<加载程序/>}
errorView={<div>某物哪里出了错!div>}
emptyView={<div>也的发现任何相关的发票div>}
isEmpty={isInvoiceListEmpty}
>
{([响应]:[InvoiceListResponse])=>(
<EditForm
发票={响应.数据[0]}
onSubmittedForm={handleSubmittedForm}
/>
)}
ResponseHandler>
);
};
首先,检索一个发票
从列表相关对象记录API编辑其当前属性:
常量sunshineResponse=useClientRequest(
`/ api /阳光/对象/记录/战:交易:$ {dealId}/ / deal_invoice相关`
);
响应由< ResponseHandler >
然后传递给< EditForm >
随着onSubmittedForm
道具。
同样的,对于创建
函数handleSubmittedForm
,发票属性从表单传递,并执行一个操作updateInvoice
在sunshineProvider.ts文件。
updateInvoice
出口常量updateInvoice=(
客户端:客户端|未定义的,
invoiceId:字符串,
属性:EditFormAttributes
)=>{
常量身体={
数据:{
属性:{
将invoice_number:属性.invoiceNumber,
issue_date:属性.issueDate,
due_date:属性.dueDate,
due_amount:parseFloat(属性.dueAmount),
is_paid:属性.isPaid,
},
},
};
返回客户端?.请求({
url:`/ /记录/ api /阳光/对象$ {invoiceId}`,
方法:“补丁”,
contentType:“应用程序/ merge-patch + json”,
数据:JSON.stringify(身体),
});
};
基于invoiceId
提供的参数中,此方法向更新对象记录端点。注意,Content-Type指定为“application/merge-patch+json”。
删除对象和关系
应用程序中可用的最后一个操作是从交易中分离发票记录。可以从<详细>
的按钮,该按钮将导航到/删除
路径处理。< DeleteView >
组件。
常量DeleteView=({dealId}:{dealId:字符串})=>{
常量dealRelationName=`禅宗:协议:$ {dealId}`
常量客户端=useContext(ZAFClientContext)
常量历史=useHistory()
常量sunshineResponse=useClientRequest(
`/ api /阳光/关系/记录?类型=$ {RELATION_TYPE}`,
)
常量handleDelete=useCallback(
异步(relationId:字符串,invoiceId:字符串)=>{
等待deleteRelation(客户端,relationId)
等待deleteObject(客户端,invoiceId)
历史.推(' / ')
},
[],
)
常量isRelationEmpty=(响应:{数据:RelationshipListResponse})=>
响应.数据.数据.过滤器(
(关系:RelationshipData)=>关系.源===dealRelationName,
).长度===0
返回(
<ResponseHandler
响应={sunshineResponse}
loadingView={<加载程序/>}
errorView={<div>某物哪里出了错!div>}
emptyView={<div>也的发现任何相关的发票div>}
isEmpty={isRelationEmpty}
>
{([响应]:[RelationshipListResponse])=>(
<DeleteSection
关系={
响应.数据.找到(
(关系:RelationshipData)=>
关系.源===dealRelationName,
)作为RelationshipData
}
onDelete={handleDelete}
/>
)}
ResponseHandler>
)
}
其工作原理类似于创建
行动。一旦handleDelete
方法调用,两个操作,deleteRelation
和deleteInvoice
在sunshineProvider.ts文件。向自定义对象API发出请求的顺序是:首先分离关系,然后删除自定义对象记录。
deleterrelation和deleteInvoice
出口常量deleteRelation=(
客户端:客户端|未定义的,
relationId:字符串
)=>{
返回客户端?.请求({
url:`/ /记录/ api /阳光/关系$ {relationId}`,
方法:“删除”,
});
};
出口常量deleteObject=(客户端:客户端|未定义的,objectId:字符串)=>{
返回客户端?.请求({
url:`/ /记录/ api /阳光/对象$ {objectId}`,
方法:“删除”,
});
};
对象发出DELETE请求删除对象记录和删除关系记录端点,需要id
给定对象的。
执行请求的客户机是类的实例ZAF客户初始化<应用>
组件并作为参数传递。
开发应用程序
你可以在本地测试应用,并在上传到Sell之前使用Zendesk CLI对应用进行验证和打包。亚博
为了进一步开发应用程序,建议使用nodeJS v14.15.3和npm v6.14.9。
本地测试应用程序
Zend亚博esk CLI (ZCLI)包括一个本地web服务器,这样你就可以在开发应用程序时在本地运行和测试应用程序。经常运行它来测试您的最新更改。
请注意:在测试和开发应用程序时,建议使用浏览器的隐私浏览或隐身模式。您的浏览器可能会缓存应用程序使用的某些文件。如果更改在您的应用程序中不起作用,则浏览器可能正在使用该文件的旧缓存版本。使用隐私浏览时,文件不会被缓存。
测试你的应用
在命令行界面中,导航到sell-custom-objects-app-tutorial文件夹中。
安装的依赖关系:
$ NPM install
启动应用程序:
$ NPM start
在命令行工具中打开一个新窗口并启动服务器:
NPM运行服务器
转到Deals页面,从列表中选择一个交易来打开一个交易卡。URL应该看起来像这样:
https://app.futuresimple.com/sales/deals/123
附加
? zcli_apps = true
到Deal牌URL,按输入.例子:https://app.futuresimple.com/sales/deals/123?zcli_apps=true
如果你使用的是谷歌Chrome浏览器,你的应用程序的内容可能会被屏蔽。单击地址栏左侧的锁定图标,选择网站设置.在“设置”页面上,滚动到不安全的内容节,然后选择允许.
注意:Firefox不会屏蔽应用程序内容,但Safari会,而且没有禁用屏蔽的选项。
打包并上传应用程序到Sell
要验证应用程序并将其打包到zip文件中,请在命令行工具中运行:
运行build
输出结果确认生成了一个新的zip文件。该文件可以在dist / tmp /文件夹中。看到安装应用程序将zip文件上传到Sell。