listmonk/frontend/src/Templates.js

440 lines
11 KiB
JavaScript
Raw Normal View History

2018-10-25 15:51:47 +02:00
import React from "react"
2019-03-09 08:46:47 +01:00
import {
Row,
Col,
Modal,
Form,
Input,
Button,
Table,
Icon,
Tooltip,
Tag,
Popconfirm,
Spin,
notification
} from "antd"
2018-10-25 15:51:47 +02:00
import ModalPreview from "./ModalPreview"
2018-10-25 15:51:47 +02:00
import Utils from "./utils"
import * as cs from "./constants"
class CreateFormDef extends React.PureComponent {
2019-03-09 08:46:47 +01:00
state = {
confirmDirty: false,
modalWaiting: false,
previewName: "",
previewBody: ""
}
// Handle create / edit form submission.
handleSubmit = e => {
e.preventDefault()
this.props.form.validateFields((err, values) => {
if (err) {
return
}
this.setState({ modalWaiting: true })
if (this.props.formType === cs.FormCreate) {
// Create a new list.
this.props
.modelRequest(
cs.ModelTemplates,
cs.Routes.CreateTemplate,
cs.MethodPost,
values
)
.then(() => {
notification["success"]({
placement: cs.MsgPosition,
message: "Template added",
description: `"${values["name"]}" added`
})
this.props.fetchRecords()
this.props.onClose()
this.setState({ modalWaiting: false })
})
.catch(e => {
notification["error"]({
placement: cs.MsgPosition,
message: "Error",
description: e.message
})
this.setState({ modalWaiting: false })
})
} else {
// Edit a list.
this.props
.modelRequest(
cs.ModelTemplates,
cs.Routes.UpdateTemplate,
cs.MethodPut,
{ ...values, id: this.props.record.id }
)
.then(() => {
notification["success"]({
placement: cs.MsgPosition,
message: "Template updated",
description: `"${values["name"]}" modified`
})
this.props.fetchRecords()
this.props.onClose()
this.setState({ modalWaiting: false })
})
.catch(e => {
notification["error"]({
placement: cs.MsgPosition,
message: "Error",
description: e.message
})
this.setState({ modalWaiting: false })
})
}
})
}
handleConfirmBlur = e => {
const value = e.target.value
this.setState({ confirmDirty: this.state.confirmDirty || !!value })
}
handlePreview = (name, body) => {
this.setState({ previewName: name, previewBody: body })
}
render() {
const { formType, record, onClose } = this.props
const { getFieldDecorator } = this.props.form
const formItemLayout = {
labelCol: { xs: { span: 16 }, sm: { span: 4 } },
wrapperCol: { xs: { span: 16 }, sm: { span: 18 } }
2018-10-25 15:51:47 +02:00
}
2019-03-09 08:46:47 +01:00
if (formType === null) {
return null
}
2019-03-09 08:46:47 +01:00
return (
<div>
<Modal
visible={true}
title={formType === cs.FormCreate ? "Add template" : record.name}
okText={this.state.form === cs.FormCreate ? "Add" : "Save"}
width="90%"
height={900}
confirmLoading={this.state.modalWaiting}
onCancel={onClose}
onOk={this.handleSubmit}
>
<Spin
spinning={
this.props.reqStates[cs.ModelTemplates] === cs.StatePending
}
>
<Form onSubmit={this.handleSubmit}>
<Form.Item {...formItemLayout} label="Name">
{getFieldDecorator("name", {
initialValue: record.name,
rules: [{ required: true }]
2019-03-28 13:34:27 +01:00
})(<Input autoFocus maxLength={200} />)}
2019-03-09 08:46:47 +01:00
</Form.Item>
<Form.Item {...formItemLayout} name="body" label="Raw HTML">
{getFieldDecorator("body", {
initialValue: record.body ? record.body : "",
rules: [{ required: true }]
})(<Input.TextArea autosize={{ minRows: 10, maxRows: 30 }} />)}
</Form.Item>
{this.props.form.getFieldValue("body") !== "" && (
<Form.Item {...formItemLayout} colon={false} label="&nbsp;">
<Button
icon="search"
onClick={() =>
this.handlePreview(
this.props.form.getFieldValue("name"),
this.props.form.getFieldValue("body")
)
}
>
Preview
</Button>
</Form.Item>
)}
</Form>
</Spin>
<Row>
<Col span="4" />
<Col span="18" className="text-grey text-small">
The placeholder{" "}
<code>
{"{"}
{"{"} template "content" . {"}"}
{"}"}
</code>{" "}
should appear in the template.{" "}
<a href="" target="_blank">
Read more on templating
</a>
.
</Col>
</Row>
</Modal>
{this.state.previewBody && (
<ModalPreview
title={
this.state.previewName
? this.state.previewName
: "Template preview"
}
previewURL={cs.Routes.PreviewNewTemplate}
body={this.state.previewBody}
onCancel={() => {
this.setState({ previewBody: null, previewName: null })
}}
/>
)}
</div>
)
}
2018-10-25 15:51:47 +02:00
}
const CreateForm = Form.create()(CreateFormDef)
class Templates extends React.PureComponent {
2019-03-09 08:46:47 +01:00
state = {
formType: null,
record: {},
previewRecord: null
}
constructor(props) {
super(props)
this.columns = [
{
title: "Name",
dataIndex: "name",
sorter: true,
width: "50%",
render: (text, record) => {
return (
<div className="name">
<a role="button" onClick={() => this.handleShowEditForm(record)}>
{text}
</a>
{record.is_default && (
<div>
<Tag>Default</Tag>
</div>
)}
</div>
)
}
},
{
title: "Created",
dataIndex: "created_at",
render: (date, _) => {
return Utils.DateString(date)
}
},
{
title: "Updated",
dataIndex: "updated_at",
render: (date, _) => {
return Utils.DateString(date)
}
},
{
title: "",
dataIndex: "actions",
width: "20%",
className: "actions",
render: (text, record) => {
return (
<div className="actions">
<Tooltip
title="Preview template"
onClick={() => this.handlePreview(record)}
>
<a role="button">
<Icon type="search" />
</a>
</Tooltip>
{!record.is_default && (
<Popconfirm
title="Are you sure?"
onConfirm={() => this.handleSetDefault(record)}
>
<Tooltip title="Set as default" placement="bottom">
<a role="button">
<Icon type="check" />
</a>
</Tooltip>
</Popconfirm>
)}
<Tooltip title="Edit template">
<a
role="button"
onClick={() => this.handleShowEditForm(record)}
>
<Icon type="edit" />
</a>
</Tooltip>
{record.id !== 1 && (
<Popconfirm
title="Are you sure?"
onConfirm={() => this.handleDeleteRecord(record)}
>
<Tooltip title="Delete template" placement="bottom">
<a role="button">
<Icon type="delete" />
</a>
</Tooltip>
</Popconfirm>
)}
</div>
)
}
}
]
}
componentDidMount() {
this.props.pageTitle("Templates")
this.fetchRecords()
}
fetchRecords = () => {
this.props.modelRequest(
cs.ModelTemplates,
cs.Routes.GetTemplates,
cs.MethodGet
)
}
handleDeleteRecord = record => {
this.props
.modelRequest(
cs.ModelTemplates,
cs.Routes.DeleteTemplate,
cs.MethodDelete,
{ id: record.id }
)
.then(() => {
notification["success"]({
placement: cs.MsgPosition,
message: "Template deleted",
description: `"${record.name}" deleted`
})
2018-10-25 15:51:47 +02:00
2019-03-09 08:46:47 +01:00
// Reload the table.
2018-10-25 15:51:47 +02:00
this.fetchRecords()
2019-03-09 08:46:47 +01:00
})
.catch(e => {
notification["error"]({ message: "Error", description: e.message })
})
}
handleSetDefault = record => {
this.props
.modelRequest(
cs.ModelTemplates,
cs.Routes.SetDefaultTemplate,
cs.MethodPut,
{ id: record.id }
)
.then(() => {
notification["success"]({
placement: cs.MsgPosition,
message: "Template updated",
description: `"${record.name}" set as default`
})
2018-10-25 15:51:47 +02:00
2019-03-09 08:46:47 +01:00
// Reload the table.
this.fetchRecords()
})
.catch(e => {
notification["error"]({
placement: cs.MsgPosition,
message: "Error",
description: e.message
})
})
}
handlePreview = record => {
this.setState({ previewRecord: record })
}
hideForm = () => {
this.setState({ formType: null })
}
handleShowCreateForm = () => {
this.setState({ formType: cs.FormCreate, record: {} })
}
handleShowEditForm = record => {
this.setState({ formType: cs.FormEdit, record: record })
}
render() {
return (
<section className="content templates">
<Row>
<Col span={22}>
<h1>Templates ({this.props.data[cs.ModelTemplates].length}) </h1>
</Col>
<Col span={2}>
<Button
type="primary"
icon="plus"
onClick={this.handleShowCreateForm}
>
Add template
</Button>
</Col>
</Row>
<br />
<Table
columns={this.columns}
rowKey={record => record.id}
dataSource={this.props.data[cs.ModelTemplates]}
loading={this.props.reqStates[cs.ModelTemplates] !== cs.StateDone}
pagination={false}
/>
<CreateForm
{...this.props}
formType={this.state.formType}
record={this.state.record}
onClose={this.hideForm}
fetchRecords={this.fetchRecords}
/>
{this.state.previewRecord && (
<ModalPreview
title={this.state.previewRecord.name}
previewURL={cs.Routes.PreviewTemplate.replace(
":id",
this.state.previewRecord.id
)}
onCancel={() => {
this.setState({ previewRecord: null })
}}
/>
)}
</section>
)
}
2018-10-25 15:51:47 +02:00
}
export default Templates