Skip to content

Commit

Permalink
Merge pull request #2339 from botpress/ya-studio-components
Browse files Browse the repository at this point in the history
feat(studio): added util components & change to cms
  • Loading branch information
allardy committed Sep 5, 2019
2 parents 33b30c0 + 0433724 commit 0b7b059
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 1 deletion.
3 changes: 2 additions & 1 deletion build/module-builder/src/webpack.ts
Expand Up @@ -35,7 +35,8 @@ export function config(projectPath) {
'@blueprintjs/core': 'BlueprintJsCore',
'botpress/ui': 'BotpressUI',
'botpress/content-picker': 'BotpressContentPicker',
'botpress/documentation': 'DocumentationProvider'
'botpress/documentation': 'DocumentationProvider',
'botpress/utils': 'BotpressUtils'
},
resolveLoader: {
modules: ['node_modules', path.resolve(projectPath, './node_modules/module-builder/node_modules')]
Expand Down
11 changes: 11 additions & 0 deletions src/bp/core/services/cms.ts
Expand Up @@ -276,6 +276,14 @@ export class CMSService implements IDisposeOnExit {
return `${prefix}-${nanoid(6)}`
}

async elementIdExists(botId: string, id: string): Promise<boolean> {
const element = await this.memDb(this.contentTable)
.where({ botId, id })
.get(0)

return !!element
}

async createOrUpdateContentElement(
botId: string,
contentTypeId: string,
Expand Down Expand Up @@ -314,6 +322,9 @@ export class CMSService implements IDisposeOnExit {

if (!contentElementId) {
contentElementId = this._generateElementId(contentTypeId)
}

if (!(await this.elementIdExists(botId, contentElementId))) {
await this.broadcastAddElement(botId, body, contentElementId, contentType.id)
const created = await this.getContentElement(botId, contentElementId)

Expand Down
35 changes: 35 additions & 0 deletions src/bp/ui-studio/src/web/components/Shared/Utils/Downloader.tsx
@@ -0,0 +1,35 @@
import axios from 'axios'
import React, { FC, useEffect, useRef, useState } from 'react'

import { DownloaderProps } from './typings'

export const Downloader: FC<DownloaderProps> = props => {
const downloadLink = useRef(null)
const [content, setContent] = useState<string>()
const [filename, setFilename] = useState<string>()

const startDownload = async (url: string, filename?: string, method: string = 'get') => {
const { data, headers } = await axios({ method, url, responseType: 'blob' })

if (!filename) {
const extractName = /filename=(.*\.)/.exec(headers['content-disposition'])
filename = extractName && extractName[1]
}

setContent(window.URL.createObjectURL(new Blob([data])))
setFilename(filename)

// @ts-ignore
downloadLink.current!.click()
props.onDownloadCompleted && props.onDownloadCompleted()
}

useEffect(() => {
if (props.url) {
// tslint:disable-next-line: no-floating-promises
startDownload(props.url, props.filename)
}
}, [props.url])

return <a ref={downloadLink} href={content} download={filename} />
}
@@ -0,0 +1,27 @@
import React from 'react'
import { connect } from 'react-redux'
import { fetchContentItem } from '~/actions'
import store from '~/store'

import withLanguage from '../../Util/withLanguage'

const ElementPreview = props => {
const { itemId, contentItem, contentLang } = props
if (!itemId) {
return null
}

if (!contentItem) {
props.fetchContentItem(props.itemId.replace('#!', ''))
}

return contentItem ? `${contentItem.schema.title} | ${contentItem.previews[contentLang]}` : ''
}

const mapStateToProps = ({ content: { itemsById } }, { itemId }) => ({ contentItem: itemsById[itemId] })
const ConnectedElementPreview = connect(
mapStateToProps,
{ fetchContentItem }
)(withLanguage(ElementPreview))

export default props => <ConnectedElementPreview {...props} store={store} />
2 changes: 2 additions & 0 deletions src/bp/ui-studio/src/web/components/Shared/Utils/index.tsx
@@ -0,0 +1,2 @@
export { default as ElementPreview } from './ElementPreview'
export { Downloader } from './Downloader'
24 changes: 24 additions & 0 deletions src/bp/ui-studio/src/web/components/Shared/Utils/typings.d.ts
@@ -0,0 +1,24 @@
import { IconName, MaybeElement, Position } from '@blueprintjs/core'
import React from 'react'

declare module 'botpress/utils' {
export function ElementPreview(props: ElementPreviewProps): JSX.Element
export function Downloader(props: DownloaderProps): JSX.Element
}

export interface DownloaderProps {
/** When the URL is set, the backend is called and the download is started. */
url: string
/** If the filename is not set, it will be extracted from headers */
filename?: string
/** Trigger an action after the download is done */
onDownloadCompleted?: () => void
}

export interface ElementPreviewProps {
/** The ID of the content element to display */
itemId: string
readonly contentLang?: string
readonly fetchContentItem?: (itemId: string) => void
readonly contentItem?: any
}
1 change: 1 addition & 0 deletions src/bp/ui-studio/src/web/index.jsx
Expand Up @@ -22,6 +22,7 @@ import 'expose-loader?ElementsList!~/components/Shared/ElementsList'
import 'expose-loader?SelectActionDropdown!~/views/FlowBuilder/nodeProps/SelectActionDropdown'
import 'expose-loader?BotpressTooltip!~/components/Shared/Tooltip'
import 'expose-loader?BotpressUI!~/components/Shared/Interface'
import 'expose-loader?BotpressUtils!~/components/Shared/Utils'
import 'expose-loader?DocumentationProvider!~/components/Util/DocumentationProvider'
import 'expose-loader?BlueprintJsCore!@blueprintjs/core'
/* eslint-enable */
Expand Down

0 comments on commit 0b7b059

Please sign in to comment.