Skip to content

Commit 1d400b4

Browse files
agalin920shrunyan
andauthored
Add AI on article writer, markdown, wysiwyg (#1750)
* Add AI on article writer, markdown, wysiwyg * Update key * lock revert * zesty-io/[email protected] Co-authored-by: Stuart Runyan <[email protected]>
1 parent 2ad916c commit 1d400b4

File tree

4 files changed

+51
-19
lines changed

4 files changed

+51
-19
lines changed

package-lock.json

+7-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
"@sentry/tracing": "^6.4.0",
5656
"@tinymce/tinymce-react": "^3.12.6",
5757
"@welldone-software/why-did-you-render": "^6.1.1",
58-
"@zesty-io/core": "1.6.7",
58+
"@zesty-io/core": "1.6.8",
5959
"@zesty-io/material": "^0.6.0",
6060
"chart.js": "^3.8.0",
6161
"chartjs-plugin-datalabels": "^2.0.0",

src/apps/content-editor/src/app/components/Editor/Field/Field.js

+9-5
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import moment from "moment-timezone";
55
import zuid from "zuid";
66

77
import { fetchFields } from "shell/store/fields";
8-
import { fetchItem, fetchItems, searchItems } from "shell/store/content";
8+
import { fetchItems, searchItems } from "shell/store/content";
99

1010
import {
1111
ToggleButtonGroup,
@@ -22,7 +22,6 @@ import {
2222
TextField,
2323
Dialog,
2424
IconButton,
25-
DialogTitle,
2625
} from "@mui/material";
2726

2827
import InfoIcon from "@mui/icons-material/InfoOutlined";
@@ -41,7 +40,6 @@ import { FieldTypeUUID } from "@zesty-io/core/FieldTypeUUID";
4140
import { FieldTypeCurrency } from "@zesty-io/core/FieldTypeCurrency";
4241
import { FieldTypeInternalLink } from "@zesty-io/core/FieldTypeInternalLink";
4342
import { FieldTypeImage } from "@zesty-io/core/FieldTypeImage";
44-
import { FieldTypeSort } from "@zesty-io/material";
4543
import { FieldTypeEditor } from "@zesty-io/core/FieldTypeEditor";
4644
import { FieldTypeTinyMCE } from "@zesty-io/core/FieldTypeTinyMCE";
4745
import {
@@ -51,13 +49,17 @@ import {
5149
FieldTypeText,
5250
FieldTypeDate,
5351
FieldTypeDateTime,
52+
FieldTypeSort,
5453
} from "@zesty-io/material";
5554

5655
import styles from "./Field.less";
5756
import { MemoryRouter } from "react-router";
5857
import { withAI } from "../../../../../../../shell/components/withAi";
5958

6059
const AITextField = withAI(FieldTypeText);
60+
const AIEditorField = withAI(FieldTypeEditor);
61+
const AITinyMCEField = withAI(FieldTypeTinyMCE);
62+
6163
const FieldLabel = memo((props) => {
6264
return (
6365
<>
@@ -350,7 +352,7 @@ export default function Field({
350352
case "wysiwyg_basic":
351353
return (
352354
<div className={styles.WYSIWYGFieldType}>
353-
<FieldTypeTinyMCE
355+
<AITinyMCEField
354356
name={name}
355357
label={FieldTypeLabel}
356358
description={description}
@@ -362,6 +364,7 @@ export default function Field({
362364
onSave={onSave}
363365
datatype={datatype}
364366
maxLength="16000"
367+
aiType="paragraph"
365368
skin="oxide"
366369
skinURL="/vendors/tinymce/skins/ui/oxide"
367370
contentCSS="/vendors/tinymce/content.css"
@@ -383,7 +386,7 @@ export default function Field({
383386
case "article_writer":
384387
return (
385388
<div className={styles.WYSIWYGFieldType}>
386-
<FieldTypeEditor
389+
<AIEditorField
387390
name={name}
388391
label={FieldTypeLabel}
389392
description={description}
@@ -394,6 +397,7 @@ export default function Field({
394397
onChange={onChange}
395398
datatype={datatype}
396399
maxLength="16000"
400+
aiType="paragraph"
397401
mediaBrowser={(opts) => {
398402
setImageModal(opts);
399403
}}

src/shell/components/withAi/index.tsx

+34-6
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,20 @@ import moment from "moment-timezone";
1010
// This date is used determine if the AI feature is enabled
1111
const enabledDate = "2023-01-13";
1212

13+
const paragraphFormat = (text: string) => {
14+
return `<p>${text
15+
.split(/\n/)
16+
.filter((s) => s)
17+
.join("</p><p>")}</p>`;
18+
};
19+
1320
export const withAI = (WrappedComponent: ComponentType) => (props: any) => {
1421
const instanceCreatedAt = useSelector(
1522
(state: AppState) => state.instance.createdAt
1623
);
1724
const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);
1825
const [focused, setFocused] = useState(false);
26+
const [key, setKey] = useState(0);
1927

2028
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
2129
setAnchorEl(event.currentTarget);
@@ -25,18 +33,38 @@ export const withAI = (WrappedComponent: ComponentType) => (props: any) => {
2533
setAnchorEl(null);
2634
};
2735

28-
const handleGenerate = (generatedText: string) => {
29-
props.onChange(
30-
{ target: { value: `${props.value}${generatedText}` } },
31-
props.name
32-
);
36+
const handleApprove = (generatedText: string) => {
37+
if (
38+
props.datatype === "article_writer" ||
39+
props.datatype === "markdown" ||
40+
props.datatype === "wysiwyg_advanced" ||
41+
props.datatype === "wysiwyg_basic"
42+
) {
43+
props.onChange(
44+
`${props.value || ""}${
45+
props.datatype === "markdown"
46+
? generatedText
47+
: paragraphFormat(generatedText)
48+
}`,
49+
props.name,
50+
props.datatype
51+
);
52+
// Force re-render after appending generated AI text due to uncontrolled component
53+
setKey(key + 1);
54+
} else {
55+
props.onChange(
56+
{ target: { value: `${props.value}${generatedText}` } },
57+
props.name
58+
);
59+
}
3360
};
3461

3562
if (moment(instanceCreatedAt).isSameOrAfter(moment(enabledDate))) {
3663
return (
3764
<>
3865
<WrappedComponent
3966
{...props}
67+
key={key}
4068
endLabel={
4169
<ThemeProvider theme={theme}>
4270
<IconButton
@@ -74,7 +102,7 @@ export const withAI = (WrappedComponent: ComponentType) => (props: any) => {
74102
}}
75103
>
76104
<AIGenerator
77-
onApprove={handleGenerate}
105+
onApprove={handleApprove}
78106
onClose={handleClose}
79107
aiType={props.aiType}
80108
label={props.label}

0 commit comments

Comments
 (0)