Bläddra i källkod

Feat/14573 support more types in form (#15093)

crazywoola 1 månad sedan
förälder
incheckning
8369e59b4d

+ 1 - 1
web/app/components/base/date-and-time-picker/date-picker/index.tsx

@@ -234,7 +234,7 @@ const DatePicker = ({
           </div>
         )}
       </PortalToFollowElemTrigger>
-      <PortalToFollowElemContent>
+      <PortalToFollowElemContent className='z-50'>
         <div className='w-[252px] mt-1 bg-components-panel-bg rounded-xl shadow-lg shadow-shadow-shadow-5 border-[0.5px] border-components-panel-border'>
           {/* Header */}
           {view === ViewType.date ? (

+ 1 - 1
web/app/components/base/date-and-time-picker/time-picker/index.tsx

@@ -142,7 +142,7 @@ const TimePicker = ({
           </div>
         )}
       </PortalToFollowElemTrigger>
-      <PortalToFollowElemContent>
+      <PortalToFollowElemContent className='z-50'>
         <div className='w-[252px] mt-1 bg-components-panel-bg rounded-xl shadow-lg shadow-shadow-shadow-5 border-[0.5px] border-components-panel-border'>
           {/* Header */}
           <Header />

+ 100 - 10
web/app/components/base/markdown-blocks/form.tsx

@@ -2,6 +2,10 @@ import React, { useEffect, useState } from 'react'
 import Button from '@/app/components/base/button'
 import Input from '@/app/components/base/input'
 import Textarea from '@/app/components/base/textarea'
+import DatePicker from '@/app/components/base/date-and-time-picker/date-picker'
+import TimePicker from '@/app/components/base/date-and-time-picker/time-picker'
+import Checkbox from '@/app/components/base/checkbox'
+import Select from '@/app/components/base/select'
 import { useChatContext } from '@/app/components/base/chat/chat/context'
 
 enum DATA_FORMAT {
@@ -19,18 +23,13 @@ enum SUPPORTED_TYPES {
   PASSWORD = 'password',
   EMAIL = 'email',
   NUMBER = 'number',
+  DATE = 'date',
+  TIME = 'time',
+  DATETIME = 'datetime',
+  CHECKBOX = 'checkbox',
+  SELECT = 'select',
 }
 const MarkdownForm = ({ node }: any) => {
-  // const supportedTypes = ['text', 'password', 'email', 'number']
-  //   <form data-format="text">
-  //      <label for="username">Username:</label>
-  //      <input type="text" name="username" />
-  //      <label for="password">Password:</label>
-  //      <input type="password" name="password" />
-  //      <label for="content">Content:</label>
-  //      <textarea name="content"></textarea>
-  //      <button data-size="small" data-variant="primary">Login</button>
-  //   </form>
   const { onSend } = useChatContext()
 
   const [formValues, setFormValues] = useState<{ [key: string]: any }>({})
@@ -90,6 +89,97 @@ const MarkdownForm = ({ node }: any) => {
           )
         }
         if (child.tagName === SUPPORTED_TAGS.INPUT && Object.values(SUPPORTED_TYPES).includes(child.properties.type)) {
+          if (child.properties.type === SUPPORTED_TYPES.DATE || child.properties.type === SUPPORTED_TYPES.DATETIME) {
+            return (
+              <DatePicker
+                key={index}
+                value={formValues[child.properties.name]}
+                needTimePicker={child.properties.type === SUPPORTED_TYPES.DATETIME}
+                onChange={(date) => {
+                  setFormValues(prevValues => ({
+                    ...prevValues,
+                    [child.properties.name]: date,
+                  }))
+                }}
+                onClear={() => {
+                  setFormValues(prevValues => ({
+                    ...prevValues,
+                    [child.properties.name]: undefined,
+                  }))
+                }}
+              />
+            )
+          }
+          if (child.properties.type === SUPPORTED_TYPES.TIME) {
+            return (
+              <TimePicker
+                key={index}
+                value={formValues[child.properties.name]}
+                onChange={(time) => {
+                  setFormValues(prevValues => ({
+                    ...prevValues,
+                    [child.properties.name]: time,
+                  }))
+                }}
+                onClear={() => {
+                  setFormValues(prevValues => ({
+                    ...prevValues,
+                    [child.properties.name]: undefined,
+                  }))
+                }}
+              />
+            )
+          }
+          if (child.properties.type === SUPPORTED_TYPES.CHECKBOX) {
+            return (
+              <div className='mt-2 flex items-center h-6 space-x-2' key={index}>
+                <Checkbox
+                  key={index}
+                  checked={formValues[child.properties.name]}
+                  onCheck={() => {
+                    setFormValues(prevValues => ({
+                      ...prevValues,
+                      [child.properties.name]: !prevValues[child.properties.name],
+                    }))
+                  }}
+                />
+                <span>{child.properties.dataTip || child.properties['data-tip'] || ''}</span>
+              </div>
+            )
+          }
+          if (child.properties.type === SUPPORTED_TYPES.SELECT) {
+            return (
+              <Select
+                key={index}
+                allowSearch={false}
+                className="w-full"
+                items={(() => {
+                  let options = child.properties.dataOptions || child.properties['data-options'] || []
+                  if (typeof options === 'string') {
+                    try {
+                      options = JSON.parse(options)
+                    }
+                    catch (e) {
+                      console.error('Failed to parse options:', e)
+                      options = []
+                    }
+                  }
+                  return options.map((option: string) => ({
+                    name: option,
+                    value: option,
+                  }))
+                })()}
+                defaultValue={formValues[child.properties.name]}
+                onSelect={(item) => {
+                  setFormValues(prevValues => ({
+                    ...prevValues,
+                    [child.properties.name]: item.value,
+                  }))
+                }}
+              />
+            )
+          }
+
           return (
             <Input
               key={index}

+ 5 - 2
web/app/styles/markdown.scss

@@ -425,7 +425,10 @@
 .markdown-body ol {
   padding-left: 2em;
 }
-
+.markdown-body ul[role="listbox"] {
+  list-style: none !important;
+  padding-left: 0 !important;
+}
 .markdown-body blockquote> :first-child {
   margin-top: 0;
 }
@@ -1035,4 +1038,4 @@
 
 .markdown-body .react-syntax-highlighter-line-number {
   color: var(--color-text-quaternary);
-}
+}