Commit 7fc5514f authored by leadream's avatar leadream

add webhook

parent 04d41f04
export const sendNotification = ({webhookUrl, data}, prUrl, version, message) => {
return fetch(`https://figma-handoff-cors.herokuapp.com/${webhookUrl}`, {
headers: {
'content-type': 'application/json'
},
body: data
.replace(/\$prUrl/g, prUrl)
.replace(/\$version/g, version)
.replace(/\$message/g, message),
method: 'POST'
})
.then(response => response.json())
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
figma.showUI(__html__, { width: 320, height: 320 }) figma.showUI(__html__, { width: 320, height: 436 })
// get github settings // get github settings
function getGithubSettings () { function getLocalData (key) {
return figma.clientStorage.getAsync('githubData') return figma.clientStorage.getAsync(key)
} }
// set github settings // set github settings
function setGithubSettings (data) { function setLocalData (key, data) {
figma.clientStorage.setAsync('githubData', data) figma.clientStorage.setAsync(key, data)
} }
// send github data to UI // send github data to UI
function init () { function init () {
getGithubSettings() getLocalData('githubData')
.then(githubData => { .then(githubData => {
figma.ui.postMessage({ type: 'githubDataGot', githubData }) figma.ui.postMessage({ type: 'githubDataGot', githubData })
}) })
getLocalData('webhookData')
.then(webhookData => {
figma.ui.postMessage({ type: 'webhookDataGot', webhookData })
})
} }
figma.ui.onmessage = msg => { figma.ui.onmessage = msg => {
switch (msg.type) { switch (msg.type) {
case 'setGithubData': case 'setGithubData':
setGithubSettings(msg.githubData) setLocalData('githubData', msg.githubData)
break
case 'setWebhookData':
setLocalData('webhookData', msg.webhookData)
break break
case 'cancel': case 'cancel':
figma.closePlugin() figma.closePlugin()
......
...@@ -49,7 +49,7 @@ export default class Settings extends React.Component<Props> { ...@@ -49,7 +49,7 @@ export default class Settings extends React.Component<Props> {
} }
} }
render () { render () {
const { visible } = this.props const { visible, githubData } = this.props
const { githubRepo, githubToken, warning } = this.state const { githubRepo, githubToken, warning } = this.state
return ( return (
<div className={!visible ? 'hide' : ''}> <div className={!visible ? 'hide' : ''}>
...@@ -84,7 +84,9 @@ export default class Settings extends React.Component<Props> { ...@@ -84,7 +84,9 @@ export default class Settings extends React.Component<Props> {
/> />
</div> </div>
<div className="form-item"> <div className="form-item">
<button className='button button--primary button-block' onClick={this.handleSubmit}>Go</button> <button className='button button--primary button-block' onClick={this.handleSubmit}>
{githubData ? 'Update' : 'Go'}
</button>
</div> </div>
<div className="setting-footer form-item type type--pos-medium-normal"> <div className="setting-footer form-item type type--pos-medium-normal">
developed by <a href="https://github.com/leadream" target="_blank">Leadream</a> developed by <a href="https://github.com/leadream" target="_blank">Leadream</a>
......
import * as React from 'react' import * as React from 'react'
import Webhook from './Webhook'
import { getContent, getCommit, updatePackage, createPullRequest, createBranch } from '../../api/github' import { getContent, getCommit, updatePackage, createPullRequest, createBranch } from '../../api/github'
import { sendNotification } from '../../api/webhook'
import { versionValue } from '../../utils/helper' import { versionValue } from '../../utils/helper'
declare function require(path: string): any declare function require(path: string): any
export interface Props { export interface Props {
onSucceed: () => void; onSucceed: () => void;
githubData: {owner?: string, name?: string, githubToken?: string}; githubData: {owner?: string, name?: string, githubToken?: string};
webhookData: {webhookUrl: string, data: string};
visible: boolean; visible: boolean;
} }
...@@ -23,7 +25,8 @@ export default class Settings extends React.Component<Props> { ...@@ -23,7 +25,8 @@ export default class Settings extends React.Component<Props> {
currentVersion: '', currentVersion: '',
currentVersionTip: '', currentVersionTip: '',
resultTip: '', resultTip: '',
prUrl: '' prUrl: '',
webhookData: null
} }
getVersion = async (githubData) => { getVersion = async (githubData) => {
const { contents, sha } = await getContent('package.json', githubData) const { contents, sha } = await getContent('package.json', githubData)
...@@ -61,6 +64,12 @@ export default class Settings extends React.Component<Props> { ...@@ -61,6 +64,12 @@ export default class Settings extends React.Component<Props> {
const { name, value } = e.target const { name, value } = e.target
this.setState({[name]: value}) this.setState({[name]: value})
} }
handleWebhookFilled = (webhookUrl, data) => {
const noData = !webhookUrl && !data
this.setState({
webhookData: noData? null : {webhookUrl, data}
})
}
validate = (callback) => { validate = (callback) => {
const { version, message, currentVersion } = this.state const { version, message, currentVersion } = this.state
// TODO: should validate async // TODO: should validate async
...@@ -91,26 +100,24 @@ export default class Settings extends React.Component<Props> { ...@@ -91,26 +100,24 @@ export default class Settings extends React.Component<Props> {
}) })
callback && callback() callback && callback()
} }
handleSubmit = () => { handleSubmit = async () => {
this.validate(() => { this.validate(async () => {
this.setState({isPushing: true}) this.setState({isPushing: true})
this.createBranch()
.then(({branchName}) => { const { branchName } = await this.createBranch()
this.changeVersion(branchName) await this.changeVersion(branchName)
.then(() => { const { html_url } = await this.createCommitAndPR(branchName)
this.createCommitAndPR(branchName)
.then(({html_url}) => { const { version, message, webhookData } = this.state
this.props.onSucceed() webhookData && sendNotification(webhookData, html_url, version, message)
this.setState({
version: '', this.setState({
message: '', version: '',
isPushing: false, message: '',
resultTip: 'Pushing successfully! You can now go to Github and merge this PR. Then your icons will be published to NPM automatically.', isPushing: false,
prUrl: html_url resultTip: 'Pushing successfully! You can now go to Github and merge this PR. Then your icons will be published to NPM automatically.',
}) prUrl: html_url
}) })
})
})
}) })
} }
onCancel = () => { onCancel = () => {
...@@ -122,7 +129,7 @@ export default class Settings extends React.Component<Props> { ...@@ -122,7 +129,7 @@ export default class Settings extends React.Component<Props> {
} }
} }
render () { render () {
const { visible } = this.props const { visible, webhookData } = this.props
const { isPushing, version, message, versionTip, messageTip, currentVersionTip, resultTip, prUrl } = this.state const { isPushing, version, message, versionTip, messageTip, currentVersionTip, resultTip, prUrl } = this.state
return ( return (
<div className={'updator ' + (!visible ? 'hide' : '')}> <div className={'updator ' + (!visible ? 'hide' : '')}>
...@@ -171,6 +178,11 @@ export default class Settings extends React.Component<Props> { ...@@ -171,6 +178,11 @@ export default class Settings extends React.Component<Props> {
<div className="type type--pos-medium-normal help-tip">{messageTip}</div> <div className="type type--pos-medium-normal help-tip">{messageTip}</div>
} }
</div> </div>
<Webhook
hidden={resultTip}
onFilled={this.handleWebhookFilled}
webhookData={webhookData}
/>
<div className={'form-item '+(resultTip ? 'hide' : '')}> <div className={'form-item '+(resultTip ? 'hide' : '')}>
<button <button
onClick={this.handleSubmit} onClick={this.handleSubmit}
...@@ -190,4 +202,4 @@ export default class Settings extends React.Component<Props> { ...@@ -190,4 +202,4 @@ export default class Settings extends React.Component<Props> {
</div> </div>
) )
} }
} }
\ No newline at end of file
import * as React from 'react'
export interface Props {
hidden: boolean;
webhookData: {webhookUrl: string, data: string};
onFilled: (webhookUrl, data) => void;
}
export default ({hidden, onFilled, webhookData}) => {
const [visible, setVisible] = React.useState(false)
const [webhookUrl, setWebhookUrl] = React.useState('')
const [data, setData] = React.useState('')
const toggle = e => {
setVisible(e.target.checked)
}
const handleChange = e => {
const { value, name } = e.target
name==='webhookUrl' ? setWebhookUrl(value) : setData(value)
}
React.useEffect(() => {
if (!visible) {
onFilled()
parent.postMessage({ pluginMessage: { type: 'setWebhookData', webhookData: '' } }, '*')
}
if (visible && webhookUrl && data) {
onFilled(webhookUrl, data)
parent.postMessage({ pluginMessage: { type: 'setWebhookData', webhookData: {webhookUrl, data} } }, '*')
}
}, [visible, webhookUrl, data])
React.useEffect(() => {
const { webhookUrl: url, data: message } = webhookData || { webhookUrl: '', data: '' }
if (url && message) {
setVisible(true)
setWebhookUrl(url)
setData(message)
}
}, [webhookData])
return (
!hidden &&
<React.Fragment>
<div className="checkbox">
<input id="visible" type="checkbox" className="checkbox__box" onChange={toggle} checked={visible}/>
<label htmlFor="visible" className="checkbox__label">Send a message to Slack/Lark</label>
</div>
<div className={visible ? '' : 'hide'}>
<div className="form-item">
<input
name="webhookUrl"
className="input"
placeholder="Webhook link"
value={webhookUrl}
onChange={handleChange}
/>
</div>
<div className="form-item">
<textarea
rows={2}
name="data"
className="textarea"
placeholder="Message data (json)"
value={data}
onChange={handleChange}
/>
<div className="type type--pos-medium-normal">You can use variables $prUrl, $version, $message in the content.</div>
</div>
</div>
</React.Fragment>
)
}
...@@ -47,7 +47,7 @@ a{ ...@@ -47,7 +47,7 @@ a{
color: #18a0fb color: #18a0fb
} }
.container{ .container-with-tab{
padding-top: 20px; padding-top: 20px;
} }
......
...@@ -11,6 +11,7 @@ class App extends React.Component { ...@@ -11,6 +11,7 @@ class App extends React.Component {
state = { state = {
updatorVisible: false, updatorVisible: false,
githubData: null, githubData: null,
webhookData: null,
settingSwitch: false, settingSwitch: false,
isDone: false isDone: false
} }
...@@ -30,7 +31,7 @@ class App extends React.Component { ...@@ -30,7 +31,7 @@ class App extends React.Component {
} }
} }
componentDidMount () { componentDidMount () {
// 所有的消息接收集中在这里 // receive messages here
window.onmessage = async (event) => { window.onmessage = async (event) => {
const msg = event.data.pluginMessage const msg = event.data.pluginMessage
switch (msg.type) { switch (msg.type) {
...@@ -42,14 +43,22 @@ class App extends React.Component { ...@@ -42,14 +43,22 @@ class App extends React.Component {
}) })
} }
break break
case 'webhookDataGot':
if (msg.webhookData) {
this.setState({
webhookData: msg.webhookData
})
}
break
} }
} }
} }
render() { render() {
const { updatorVisible, githubData, settingSwitch, isDone } = this.state const { updatorVisible, githubData, webhookData, settingSwitch, isDone } = this.state
const tabVisible = githubData&&!isDone
return ( return (
<div className="container"> <div className={'container '+ (!tabVisible ? '' : 'container-with-tab')}>
<div className={'bar-adjust '+ ((githubData&&!isDone) ? '' : 'hide')}> <div className={'bar-adjust '+ (tabVisible ? '' : 'hide')}>
<div <div
className={'adjust-item type type--pos-medium-bold '+(updatorVisible ? '' : 'active')} className={'adjust-item type type--pos-medium-bold '+(updatorVisible ? '' : 'active')}
onClick={e => this.toggleView()} onClick={e => this.toggleView()}
...@@ -72,7 +81,9 @@ class App extends React.Component { ...@@ -72,7 +81,9 @@ class App extends React.Component {
<Updator <Updator
onSucceed={this.onSucceed} onSucceed={this.onSucceed}
visible={updatorVisible} visible={updatorVisible}
githubData={githubData}/> githubData={githubData}
webhookData={webhookData}
/>
</div> </div>
) )
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment