feat: option to hide workflow steps (#5436)

This commit is contained in:
crazywoola 2024-06-21 12:51:10 +08:00 committed by GitHub
parent 1336b844fd
commit 92ddb410cd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
29 changed files with 165 additions and 9 deletions

View File

@ -28,6 +28,7 @@ def parse_app_site_args():
required=False, required=False,
location='json') location='json')
parser.add_argument('prompt_public', type=bool, required=False, location='json') parser.add_argument('prompt_public', type=bool, required=False, location='json')
parser.add_argument('show_workflow_steps', type=bool, required=False, location='json')
return parser.parse_args() return parser.parse_args()
@ -59,7 +60,8 @@ class AppSite(Resource):
'privacy_policy', 'privacy_policy',
'custom_disclaimer', 'custom_disclaimer',
'customize_token_strategy', 'customize_token_strategy',
'prompt_public' 'prompt_public',
'show_workflow_steps'
]: ]:
value = args.get(attr_name) value = args.get(attr_name)
if value is not None: if value is not None:

View File

@ -33,7 +33,8 @@ class AppSiteApi(WebApiResource):
'privacy_policy': fields.String, 'privacy_policy': fields.String,
'custom_disclaimer': fields.String, 'custom_disclaimer': fields.String,
'default_language': fields.String, 'default_language': fields.String,
'prompt_public': fields.Boolean 'prompt_public': fields.Boolean,
'show_workflow_steps': fields.Boolean,
} }
app_fields = { app_fields = {

View File

@ -117,6 +117,7 @@ site_fields = {
'customize_token_strategy': fields.String, 'customize_token_strategy': fields.String,
'prompt_public': fields.Boolean, 'prompt_public': fields.Boolean,
'app_base_url': fields.String, 'app_base_url': fields.String,
'show_workflow_steps': fields.Boolean,
} }
app_detail_fields_with_site = { app_detail_fields_with_site = {
@ -149,5 +150,6 @@ app_site_fields = {
'privacy_policy': fields.String, 'privacy_policy': fields.String,
'custom_disclaimer': fields.String, 'custom_disclaimer': fields.String,
'customize_token_strategy': fields.String, 'customize_token_strategy': fields.String,
'prompt_public': fields.Boolean 'prompt_public': fields.Boolean,
'show_workflow_steps': fields.Boolean,
} }

View File

@ -0,0 +1,33 @@
"""add workflow to site
Revision ID: 4ff534e1eb11
Revises: 7b45942e39bb
Create Date: 2024-06-21 04:16:03.419634
"""
import sqlalchemy as sa
from alembic import op
import models as models
# revision identifiers, used by Alembic.
revision = '4ff534e1eb11'
down_revision = '7b45942e39bb'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('sites', schema=None) as batch_op:
batch_op.add_column(sa.Column('show_workflow_steps', sa.Boolean(), server_default=sa.text('true'), nullable=False))
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('sites', schema=None) as batch_op:
batch_op.drop_column('show_workflow_steps')
# ### end Alembic commands ###

View File

@ -1043,6 +1043,7 @@ class Site(db.Model):
default_language = db.Column(db.String(255), nullable=False) default_language = db.Column(db.String(255), nullable=False)
copyright = db.Column(db.String(255)) copyright = db.Column(db.String(255))
privacy_policy = db.Column(db.String(255)) privacy_policy = db.Column(db.String(255))
show_workflow_steps = db.Column(db.Boolean, nullable=False, server_default=db.text('true'))
custom_disclaimer = db.Column(db.String(255), nullable=True) custom_disclaimer = db.Column(db.String(255), nullable=True)
customize_domain = db.Column(db.String(255)) customize_domain = db.Column(db.String(255))
customize_token_strategy = db.Column(db.String(255), nullable=False) customize_token_strategy = db.Column(db.String(255), nullable=False)

View File

@ -34,6 +34,7 @@ export type ConfigParams = {
custom_disclaimer: string custom_disclaimer: string
icon: string icon: string
icon_background: string icon_background: string
show_workflow_steps: boolean
} }
const prefixSettings = 'appOverview.overview.appInfo.settings' const prefixSettings = 'appOverview.overview.appInfo.settings'
@ -47,8 +48,8 @@ const SettingsModal: FC<ISettingsModalProps> = ({
const { notify } = useToastContext() const { notify } = useToastContext()
const [isShowMore, setIsShowMore] = useState(false) const [isShowMore, setIsShowMore] = useState(false)
const { icon, icon_background } = appInfo const { icon, icon_background } = appInfo
const { title, description, copyright, privacy_policy, custom_disclaimer, default_language } = appInfo.site const { title, description, copyright, privacy_policy, custom_disclaimer, default_language, show_workflow_steps } = appInfo.site
const [inputInfo, setInputInfo] = useState({ title, desc: description, copyright, privacyPolicy: privacy_policy, customDisclaimer: custom_disclaimer }) const [inputInfo, setInputInfo] = useState({ title, desc: description, copyright, privacyPolicy: privacy_policy, customDisclaimer: custom_disclaimer, show_workflow_steps })
const [language, setLanguage] = useState(default_language) const [language, setLanguage] = useState(default_language)
const [saveLoading, setSaveLoading] = useState(false) const [saveLoading, setSaveLoading] = useState(false)
const { t } = useTranslation() const { t } = useTranslation()
@ -57,7 +58,7 @@ const SettingsModal: FC<ISettingsModalProps> = ({
const [emoji, setEmoji] = useState({ icon, icon_background }) const [emoji, setEmoji] = useState({ icon, icon_background })
useEffect(() => { useEffect(() => {
setInputInfo({ title, desc: description, copyright, privacyPolicy: privacy_policy, customDisclaimer: custom_disclaimer }) setInputInfo({ title, desc: description, copyright, privacyPolicy: privacy_policy, customDisclaimer: custom_disclaimer, show_workflow_steps })
setLanguage(default_language) setLanguage(default_language)
setEmoji({ icon, icon_background }) setEmoji({ icon, icon_background })
}, [appInfo]) }, [appInfo])
@ -85,6 +86,7 @@ const SettingsModal: FC<ISettingsModalProps> = ({
custom_disclaimer: inputInfo.customDisclaimer, custom_disclaimer: inputInfo.customDisclaimer,
icon: emoji.icon, icon: emoji.icon,
icon_background: emoji.icon_background, icon_background: emoji.icon_background,
show_workflow_steps: inputInfo.show_workflow_steps,
} }
await onSave?.(params) await onSave?.(params)
setSaveLoading(false) setSaveLoading(false)
@ -134,6 +136,14 @@ const SettingsModal: FC<ISettingsModalProps> = ({
defaultValue={language} defaultValue={language}
onSelect={item => setLanguage(item.value as Language)} onSelect={item => setLanguage(item.value as Language)}
/> />
{(appInfo.mode === 'workflow' || appInfo.mode === 'advanced-chat') && <>
<div className={`mt-6 mb-2 font-medium ${s.settingTitle} text-gray-900 `}>{t(`${prefixSettings}.workflow.title`)}</div>
<SimpleSelect
items={[{ name: t(`${prefixSettings}.workflow.show`), value: 'true' }, { name: t(`${prefixSettings}.workflow.hide`), value: 'false' }]}
defaultValue={inputInfo.show_workflow_steps ? 'true' : 'false'}
onSelect={item => setInputInfo({ ...inputInfo, show_workflow_steps: item.value === 'true' })}
/>
</>}
{!isShowMore && <div className='w-full cursor-pointer mt-8' onClick={() => setIsShowMore(true)}> {!isShowMore && <div className='w-full cursor-pointer mt-8' onClick={() => setIsShowMore(true)}>
<div className='flex justify-between'> <div className='flex justify-between'>
<div className={`font-medium ${s.settingTitle} flex-grow text-gray-900`}>{t(`${prefixSettings}.more.entry`)}</div> <div className={`font-medium ${s.settingTitle} flex-grow text-gray-900`}>{t(`${prefixSettings}.more.entry`)}</div>

View File

@ -28,6 +28,7 @@ import EditReplyModal from '@/app/components/app/annotation/edit-annotation-moda
import { useStore as useAppStore } from '@/app/components/app/store' import { useStore as useAppStore } from '@/app/components/app/store'
import WorkflowProcessItem from '@/app/components/base/chat/chat/answer/workflow-process' import WorkflowProcessItem from '@/app/components/base/chat/chat/answer/workflow-process'
import type { WorkflowProcess } from '@/app/components/base/chat/types' import type { WorkflowProcess } from '@/app/components/base/chat/types'
import type { SiteInfo } from '@/models/share'
const MAX_DEPTH = 3 const MAX_DEPTH = 3
@ -62,6 +63,7 @@ export type IGenerationItemProps = {
contentClassName?: string contentClassName?: string
footerClassName?: string footerClassName?: string
hideProcessDetail?: boolean hideProcessDetail?: boolean
siteInfo: SiteInfo | null
} }
export const SimpleBtn = ({ className, isDisabled, onClick, children }: { export const SimpleBtn = ({ className, isDisabled, onClick, children }: {
@ -113,6 +115,7 @@ const GenerationItem: FC<IGenerationItemProps> = ({
innerClassName, innerClassName,
contentClassName, contentClassName,
hideProcessDetail, hideProcessDetail,
siteInfo,
}) => { }) => {
const { t } = useTranslation() const { t } = useTranslation()
const params = useParams() const params = useParams()
@ -152,6 +155,7 @@ const GenerationItem: FC<IGenerationItemProps> = ({
installedAppId, installedAppId,
controlClearMoreLikeThis, controlClearMoreLikeThis,
isWorkflow, isWorkflow,
siteInfo,
} }
const handleMoreLikeThis = async () => { const handleMoreLikeThis = async () => {
@ -297,7 +301,7 @@ const GenerationItem: FC<IGenerationItemProps> = ({
} }
<div className={`flex ${contentClassName}`}> <div className={`flex ${contentClassName}`}>
<div className='grow w-0'> <div className='grow w-0'>
{workflowProcessData && ( {siteInfo && siteInfo.show_workflow_steps && workflowProcessData && (
<WorkflowProcessItem grayBg hideInfo data={workflowProcessData} expand={workflowProcessData.expand} hideProcessDetail={hideProcessDetail} /> <WorkflowProcessItem grayBg hideInfo data={workflowProcessData} expand={workflowProcessData.expand} hideProcessDetail={hideProcessDetail} />
)} )}
{workflowProcessData && !isError && ( {workflowProcessData && !isError && (

View File

@ -29,6 +29,7 @@ const ChatWrapper = () => {
appMeta, appMeta,
handleFeedback, handleFeedback,
currentChatInstanceRef, currentChatInstanceRef,
appData,
} = useChatWithHistoryContext() } = useChatWithHistoryContext()
const appConfig = useMemo(() => { const appConfig = useMemo(() => {
const config = appParams || {} const config = appParams || {}
@ -128,6 +129,7 @@ const ChatWrapper = () => {
return ( return (
<Chat <Chat
appData={appData}
config={appConfig} config={appConfig}
chatList={chatList} chatList={chatList}
isResponding={isResponding} isResponding={isResponding}

View File

@ -47,7 +47,14 @@ export const useChatWithHistory = (installedAppInfo?: InstalledApp) => {
const { id, app } = installedAppInfo! const { id, app } = installedAppInfo!
return { return {
app_id: id, app_id: id,
site: { title: app.name, icon: app.icon, icon_background: app.icon_background, prompt_public: false, copyright: '' }, site: {
title: app.name,
icon: app.icon,
icon_background: app.icon_background,
prompt_public: false,
copyright: '',
show_workflow_steps: true,
},
plan: 'basic', plan: 'basic',
} as AppData } as AppData
} }

View File

@ -20,6 +20,7 @@ import LoadingAnim from '@/app/components/app/chat/loading-anim'
import Citation from '@/app/components/app/chat/citation' import Citation from '@/app/components/app/chat/citation'
import { EditTitle } from '@/app/components/app/annotation/edit-annotation-modal/edit-item' import { EditTitle } from '@/app/components/app/annotation/edit-annotation-modal/edit-item'
import type { Emoji } from '@/app/components/tools/types' import type { Emoji } from '@/app/components/tools/types'
import type { AppData } from '@/models/share'
type AnswerProps = { type AnswerProps = {
item: ChatItem item: ChatItem
@ -32,6 +33,7 @@ type AnswerProps = {
showPromptLog?: boolean showPromptLog?: boolean
chatAnswerContainerInner?: string chatAnswerContainerInner?: string
hideProcessDetail?: boolean hideProcessDetail?: boolean
appData?: AppData
} }
const Answer: FC<AnswerProps> = ({ const Answer: FC<AnswerProps> = ({
item, item,
@ -44,6 +46,7 @@ const Answer: FC<AnswerProps> = ({
showPromptLog, showPromptLog,
chatAnswerContainerInner, chatAnswerContainerInner,
hideProcessDetail, hideProcessDetail,
appData,
}) => { }) => {
const { t } = useTranslation() const { t } = useTranslation()
const { const {
@ -129,8 +132,20 @@ const Answer: FC<AnswerProps> = ({
/> />
) )
} }
{/** Render the normal steps */}
{ {
workflowProcess && ( workflowProcess && !hideProcessDetail && (
<WorkflowProcess
data={workflowProcess}
item={item}
hideInfo
hideProcessDetail={hideProcessDetail}
/>
)
}
{/** Hide workflow steps by it's settings in siteInfo */}
{
workflowProcess && hideProcessDetail && appData && appData.site.show_workflow_steps && (
<WorkflowProcess <WorkflowProcess
data={workflowProcess} data={workflowProcess}
item={item} item={item}

View File

@ -30,8 +30,10 @@ import { StopCircle } from '@/app/components/base/icons/src/vender/solid/mediaAn
import AgentLogModal from '@/app/components/base/agent-log-modal' import AgentLogModal from '@/app/components/base/agent-log-modal'
import PromptLogModal from '@/app/components/base/prompt-log-modal' import PromptLogModal from '@/app/components/base/prompt-log-modal'
import { useStore as useAppStore } from '@/app/components/app/store' import { useStore as useAppStore } from '@/app/components/app/store'
import type { AppData } from '@/models/share'
export type ChatProps = { export type ChatProps = {
appData?: AppData
chatList: ChatItem[] chatList: ChatItem[]
config?: ChatConfig config?: ChatConfig
isResponding?: boolean isResponding?: boolean
@ -57,6 +59,7 @@ export type ChatProps = {
hideProcessDetail?: boolean hideProcessDetail?: boolean
} }
const Chat: FC<ChatProps> = ({ const Chat: FC<ChatProps> = ({
appData,
config, config,
onSend, onSend,
chatList, chatList,
@ -196,6 +199,7 @@ const Chat: FC<ChatProps> = ({
const isLast = item.id === chatList[chatList.length - 1]?.id const isLast = item.id === chatList[chatList.length - 1]?.id
return ( return (
<Answer <Answer
appData={appData}
key={item.id} key={item.id}
item={item} item={item}
question={chatList[index - 1]?.content} question={chatList[index - 1]?.content}

View File

@ -18,6 +18,7 @@ import LogoAvatar from '@/app/components/base/logo/logo-embeded-chat-avatar'
const ChatWrapper = () => { const ChatWrapper = () => {
const { const {
appData,
appParams, appParams,
appPrevChatList, appPrevChatList,
currentConversationId, currentConversationId,
@ -114,6 +115,7 @@ const ChatWrapper = () => {
return ( return (
<Chat <Chat
appData={appData}
config={appConfig} config={appConfig}
chatList={chatList} chatList={chatList}
isResponding={isResponding} isResponding={isResponding}

View File

@ -442,6 +442,7 @@ const TextGeneration: FC<IMainProps> = ({
visionConfig={visionConfig} visionConfig={visionConfig}
completionFiles={completionFiles} completionFiles={completionFiles}
isShowTextToSpeech={!!textToSpeechConfig?.enabled} isShowTextToSpeech={!!textToSpeechConfig?.enabled}
siteInfo={siteInfo}
/>) />)
const renderBatchRes = () => { const renderBatchRes = () => {

View File

@ -18,6 +18,7 @@ import { TransferMethod, type VisionFile, type VisionSettings } from '@/types/ap
import { NodeRunningStatus, WorkflowRunningStatus } from '@/app/components/workflow/types' import { NodeRunningStatus, WorkflowRunningStatus } from '@/app/components/workflow/types'
import type { WorkflowProcess } from '@/app/components/base/chat/types' import type { WorkflowProcess } from '@/app/components/base/chat/types'
import { sleep } from '@/utils' import { sleep } from '@/utils'
import type { SiteInfo } from '@/models/share'
export type IResultProps = { export type IResultProps = {
isWorkflow: boolean isWorkflow: boolean
@ -42,6 +43,7 @@ export type IResultProps = {
moderationService?: (text: string) => ReturnType<ModerationService> moderationService?: (text: string) => ReturnType<ModerationService>
visionConfig: VisionSettings visionConfig: VisionSettings
completionFiles: VisionFile[] completionFiles: VisionFile[]
siteInfo: SiteInfo | null
} }
const Result: FC<IResultProps> = ({ const Result: FC<IResultProps> = ({
@ -65,6 +67,7 @@ const Result: FC<IResultProps> = ({
onCompleted, onCompleted,
visionConfig, visionConfig,
completionFiles, completionFiles,
siteInfo,
}) => { }) => {
const [isResponding, { setTrue: setRespondingTrue, setFalse: setRespondingFalse }] = useBoolean(false) const [isResponding, { setTrue: setRespondingTrue, setFalse: setRespondingFalse }] = useBoolean(false)
useEffect(() => { useEffect(() => {
@ -375,6 +378,7 @@ const Result: FC<IResultProps> = ({
controlClearMoreLikeThis={controlClearMoreLikeThis} controlClearMoreLikeThis={controlClearMoreLikeThis}
isShowTextToSpeech={isShowTextToSpeech} isShowTextToSpeech={isShowTextToSpeech}
hideProcessDetail hideProcessDetail
siteInfo={siteInfo}
/> />
) )

View File

@ -44,6 +44,11 @@ const translation = {
webDescTip: 'Dieser Text wird auf der Clientseite angezeigt und bietet grundlegende Anleitungen zur Verwendung der Anwendung', webDescTip: 'Dieser Text wird auf der Clientseite angezeigt und bietet grundlegende Anleitungen zur Verwendung der Anwendung',
webDescPlaceholder: 'Geben Sie die Beschreibung der WebApp ein', webDescPlaceholder: 'Geben Sie die Beschreibung der WebApp ein',
language: 'Sprache', language: 'Sprache',
workflow: {
title: 'Workflow-Schritte',
show: 'Anzeigen',
hide: 'Verbergen',
},
more: { more: {
entry: 'Mehr Einstellungen anzeigen', entry: 'Mehr Einstellungen anzeigen',
copyright: 'Urheberrecht', copyright: 'Urheberrecht',

View File

@ -44,6 +44,11 @@ const translation = {
webDescTip: 'This text will be displayed on the client side, providing basic guidance on how to use the application', webDescTip: 'This text will be displayed on the client side, providing basic guidance on how to use the application',
webDescPlaceholder: 'Enter the description of the WebApp', webDescPlaceholder: 'Enter the description of the WebApp',
language: 'Language', language: 'Language',
workflow: {
title: 'Workflow Steps',
show: 'Show',
hide: 'Hide',
},
more: { more: {
entry: 'Show more settings', entry: 'Show more settings',
copyright: 'Copyright', copyright: 'Copyright',

View File

@ -44,6 +44,11 @@ const translation = {
webDescTip: 'Ce texte sera affiché côté client, fournissant des directives de base sur la façon d\'utiliser l\'application', webDescTip: 'Ce texte sera affiché côté client, fournissant des directives de base sur la façon d\'utiliser l\'application',
webDescPlaceholder: 'Entrez la description de l\'application Web', webDescPlaceholder: 'Entrez la description de l\'application Web',
language: 'Langue', language: 'Langue',
workflow: {
title: 'Étapes du workflow',
show: 'Afficher',
hide: 'Masquer',
},
more: { more: {
entry: 'Afficher plus de paramètres', entry: 'Afficher plus de paramètres',
copyright: 'Droits d\'auteur', copyright: 'Droits d\'auteur',

View File

@ -48,6 +48,11 @@ const translation = {
'यह टेक्स्ट क्लाइंट साइड पर प्रदर्शित होगा, जो एप्लिकेशन का उपयोग करने के लिए बुनियादी मार्गदर्शन प्रदान करेगा', 'यह टेक्स्ट क्लाइंट साइड पर प्रदर्शित होगा, जो एप्लिकेशन का उपयोग करने के लिए बुनियादी मार्गदर्शन प्रदान करेगा',
webDescPlaceholder: 'वेबऐप का विवरण दर्ज करें', webDescPlaceholder: 'वेबऐप का विवरण दर्ज करें',
language: 'भाषा', language: 'भाषा',
workflow: {
title: 'वर्कफ़्लो स्टेप्स',
show: 'दिखाएं',
hide: 'छुपाएं',
},
more: { more: {
entry: 'अधिक सेटिंग्स दिखाएं', entry: 'अधिक सेटिंग्स दिखाएं',
copyright: 'कॉपीराइट', copyright: 'कॉपीराइट',

View File

@ -44,6 +44,11 @@ const translation = {
webDescTip: 'このテキストはクライアント側に表示され、アプリケーションの使用方法の基本的なガイダンスを提供します。', webDescTip: 'このテキストはクライアント側に表示され、アプリケーションの使用方法の基本的なガイダンスを提供します。',
webDescPlaceholder: 'WebAppの説明を入力してください', webDescPlaceholder: 'WebAppの説明を入力してください',
language: '言語', language: '言語',
workflow: {
title: 'ワークフローステップ',
show: '表示',
hide: '非表示',
},
more: { more: {
entry: 'その他の設定を表示', entry: 'その他の設定を表示',
copyright: '著作権', copyright: '著作権',

View File

@ -44,6 +44,11 @@ const translation = {
webDescTip: '이 텍스트는 클라이언트 측에서 표시되며, 애플리케이션의 사용 방법에 대한 기본적인 안내를 제공합니다.', webDescTip: '이 텍스트는 클라이언트 측에서 표시되며, 애플리케이션의 사용 방법에 대한 기본적인 안내를 제공합니다.',
webDescPlaceholder: '웹앱 설명을 입력하세요', webDescPlaceholder: '웹앱 설명을 입력하세요',
language: '언어', language: '언어',
workflow: {
title: '워크플로 단계',
show: '표시',
hide: '숨기기',
},
more: { more: {
entry: '추가 설정 보기', entry: '추가 설정 보기',
copyright: '저작권', copyright: '저작권',

View File

@ -48,6 +48,11 @@ const translation = {
'Ten tekst będzie wyświetlany po stronie klienta, zapewniając podstawowe wskazówki, jak korzystać z aplikacji', 'Ten tekst będzie wyświetlany po stronie klienta, zapewniając podstawowe wskazówki, jak korzystać z aplikacji',
webDescPlaceholder: 'Wpisz opis WebApp', webDescPlaceholder: 'Wpisz opis WebApp',
language: 'Język', language: 'Język',
workflow: {
title: 'Kroki przepływu pracy',
show: 'Pokaż',
hide: 'Ukryj',
},
more: { more: {
entry: 'Pokaż więcej ustawień', entry: 'Pokaż więcej ustawień',
copyright: 'Prawa autorskie', copyright: 'Prawa autorskie',

View File

@ -44,6 +44,11 @@ const translation = {
webDescTip: 'Este texto será exibido no lado do cliente, fornecendo orientações básicas sobre como usar o aplicativo', webDescTip: 'Este texto será exibido no lado do cliente, fornecendo orientações básicas sobre como usar o aplicativo',
webDescPlaceholder: 'Insira a descrição do WebApp', webDescPlaceholder: 'Insira a descrição do WebApp',
language: 'Idioma', language: 'Idioma',
workflow: {
title: 'Etapas do fluxo de trabalho',
show: 'Mostrar',
hide: 'Ocultar',
},
more: { more: {
entry: 'Mostrar mais configurações', entry: 'Mostrar mais configurações',
copyright: 'Direitos autorais', copyright: 'Direitos autorais',

View File

@ -44,6 +44,11 @@ const translation = {
webDescTip: 'Acest text va fi afișat pe partea clientului, oferind îndrumare de bază privind modul de utilizare a aplicației', webDescTip: 'Acest text va fi afișat pe partea clientului, oferind îndrumare de bază privind modul de utilizare a aplicației',
webDescPlaceholder: 'Introduceți descrierea aplicației web', webDescPlaceholder: 'Introduceți descrierea aplicației web',
language: 'Limbă', language: 'Limbă',
workflow: {
title: 'Pași flux de lucru',
show: 'Afișați',
hide: 'Ascundeți',
},
more: { more: {
entry: 'Afișați mai multe setări', entry: 'Afișați mai multe setări',
copyright: 'Drepturi de autor', copyright: 'Drepturi de autor',

View File

@ -44,6 +44,11 @@ const translation = {
webDescTip: 'Цей текст буде відображений на клієнтському боці, надаючи базові вказівки щодо використання додатка', webDescTip: 'Цей текст буде відображений на клієнтському боці, надаючи базові вказівки щодо використання додатка',
webDescPlaceholder: 'Введіть опис веб-додатку', webDescPlaceholder: 'Введіть опис веб-додатку',
language: 'Мова', language: 'Мова',
workflow: {
title: 'Кроки робочого процесу',
show: 'Показати',
hide: 'Приховати',
},
more: { more: {
entry: 'Показати додаткові налаштування', entry: 'Показати додаткові налаштування',
copyright: 'Авторське право', copyright: 'Авторське право',

View File

@ -44,6 +44,11 @@ const translation = {
webDescTip: 'Văn bản này sẽ được hiển thị ở phía máy khách, cung cấp hướng dẫn cơ bản về cách sử dụng ứng dụng', webDescTip: 'Văn bản này sẽ được hiển thị ở phía máy khách, cung cấp hướng dẫn cơ bản về cách sử dụng ứng dụng',
webDescPlaceholder: 'Nhập mô tả của ứng dụng web', webDescPlaceholder: 'Nhập mô tả của ứng dụng web',
language: 'Ngôn ngữ', language: 'Ngôn ngữ',
workflow: {
title: 'Các Bước Quy trình',
show: 'Hiển thị',
hide: 'Ẩn',
},
more: { more: {
entry: 'Hiển thị thêm cài đặt', entry: 'Hiển thị thêm cài đặt',
copyright: 'Bản quyền', copyright: 'Bản quyền',

View File

@ -44,6 +44,11 @@ const translation = {
webDescTip: '以下文字将展示在客户端中,对应用进行说明和使用上的基本引导', webDescTip: '以下文字将展示在客户端中,对应用进行说明和使用上的基本引导',
webDescPlaceholder: '请输入 WebApp 的描述', webDescPlaceholder: '请输入 WebApp 的描述',
language: '语言', language: '语言',
workflow: {
title: '工作流详情',
show: '显示',
hide: '隐藏',
},
more: { more: {
entry: '展示更多设置', entry: '展示更多设置',
copyright: '版权', copyright: '版权',

View File

@ -44,6 +44,11 @@ const translation = {
webDescTip: '以下文字將展示在客戶端中,對應用進行說明和使用上的基本引導', webDescTip: '以下文字將展示在客戶端中,對應用進行說明和使用上的基本引導',
webDescPlaceholder: '請輸入 WebApp 的描述', webDescPlaceholder: '請輸入 WebApp 的描述',
language: '語言', language: '語言',
workflow: {
title: '工作流程步驟',
show: '展示',
hide: '隱藏',
},
more: { more: {
entry: '展示更多設定', entry: '展示更多設定',
copyright: '版權', copyright: '版權',

View File

@ -19,6 +19,7 @@ export type SiteInfo = {
copyright?: string copyright?: string
privacy_policy?: string privacy_policy?: string
custom_disclaimer?: string custom_disclaimer?: string
show_workflow_steps?: boolean
} }
export type AppMeta = { export type AppMeta = {

View File

@ -274,6 +274,8 @@ export type SiteConfig = {
icon: string icon: string
icon_background: string icon_background: string
show_workflow_steps: boolean
} }
/** /**