Compare commits

...

8 Commits

@ -1,7 +1,7 @@
![cover-v5-optimized](./images/GitHub_README_if.png)
<p align="center">
📌 <a href="https://dify.ai/blog/introducing-dify-workflow-file-upload-a-demo-on-ai-podcast">Introducing Dify Workflow File Upload: Recreate Google NotebookLM Podcast</a>
📌 <a href="https://dify.ai/blog/introducing-dify-workflow-file-upload-a-demo-on-ai-podcast">Introducing Dify Workflow File Upload: Recreate Google NotebookLM Podcast111</a>
</p>
<p align="center">

@ -1011,7 +1011,9 @@ class ToolManager:
if variable is None:
raise ToolParameterError(f"Variable {tool_input.value} does not exist")
parameter_value = variable.value
elif tool_input.type in {"mixed", "constant"}:
elif tool_input.type == "constant":
parameter_value = tool_input.value
elif tool_input.type == "mixed":
segment_group = variable_pool.convert_template(str(tool_input.value))
parameter_value = segment_group.text
else:

@ -54,7 +54,7 @@ class ToolNodeData(BaseNodeData, ToolEntity):
for val in value:
if not isinstance(val, str):
raise ValueError("value must be a list of strings")
elif typ == "constant" and not isinstance(value, str | int | float | bool):
elif typ == "constant" and not isinstance(value, str | int | float | bool | dict):
raise ValueError("value must be a string, int, float, or bool")
return typ

@ -32,6 +32,35 @@ export type IAppDetailLayoutProps = {
appId: string
}
const useIframeHeader = () => {
const [show, setShow] = useState(true);
useEffect(() => {
// 监听父级指定操作
const handler = (event: MessageEvent) => {
// if (event.origin !== "https://gcgj.ngsk.tech:7001") return;
if (event.data.type === "HIDDEN") setShow(() => false);
};
// 初始化完成后提示iframe操作
window.parent.postMessage(
{
type: "SIDEBA",
},
"*"
);
window.addEventListener("message", handler);
return () => window.removeEventListener("message", handler);
}, []);
return {
show,
};
};
const AppDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
const {
children,
@ -56,6 +85,7 @@ const AppDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
icon: NavIcon
selectedIcon: NavIcon
}>>([])
const { show } = useIframeHeader()
const getNavigations = useCallback((appId: string, isCurrentWorkspaceEditor: boolean, mode: string) => {
const navs = [
@ -160,9 +190,9 @@ const AppDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
return (
<div className={cn(s.app, 'relative flex', 'overflow-hidden')}>
{appDetail && (
{show ? appDetail && (
<AppSideBar title={appDetail.name} icon={appDetail.icon} icon_background={appDetail.icon_background as string} desc={appDetail.mode} navigation={navigation} />
)}
): ''}
<div className="grow overflow-hidden bg-components-panel-bg">
{children}
</div>

@ -1,5 +1,5 @@
'use client'
import React, { useState } from 'react'
import React, { useEffect, useState } from 'react'
import dayjs from 'dayjs'
import quarterOfYear from 'dayjs/plugin/quarterOfYear'
import { useTranslation } from 'react-i18next'
@ -9,6 +9,7 @@ import type { Item } from '@/app/components/base/select'
import { SimpleSelect } from '@/app/components/base/select'
import { TIME_PERIOD_MAPPING } from '@/app/components/app/log/filter'
import { useStore as useAppStore } from '@/app/components/app/store'
import { useRouter } from 'next/navigation'
dayjs.extend(quarterOfYear)
@ -21,12 +22,44 @@ export type IChartViewProps = {
headerRight: React.ReactNode
}
let state = 0
const useIframeRedirection = () => {
const router = useRouter()
useEffect(() => {
// 监听父级指定操作
const handler = (event: MessageEvent) => {
// if (event.origin !== "https://gcgj.ngsk.tech:7001") return;
if (
event.data.type === 'CHART_VIEW_REDIRECT'
&& event.data.redirectUrl
&& state < 3 // 防止无限重定向
) {
state++
router.replace(event.data.redirectUrl)
}
}
// 首页初始化完成后提示iframe操作
window.parent.postMessage(
{
type: 'CHART_VIEW',
},
'*',
)
window.addEventListener('message', handler)
return () => window.removeEventListener('message', handler)
}, [])
}
export default function ChartView({ appId, headerRight }: IChartViewProps) {
const { t } = useTranslation()
const appDetail = useAppStore(state => state.appDetail)
const isChatApp = appDetail?.mode !== 'completion' && appDetail?.mode !== 'workflow'
const isWorkflow = appDetail?.mode === 'workflow'
const [period, setPeriod] = useState<PeriodParams>({ name: t('appLog.filter.period.last7days'), query: { start: today.subtract(7, 'day').startOf('day').format(queryDateFormat), end: today.endOf('day').format(queryDateFormat) } })
useIframeRedirection()
const onSelect = (item: Item) => {
if (item.value === -1) {

@ -70,7 +70,7 @@ const HitTestingPage: FC<Props> = ({ datasetId }: Props) => {
const [isShowModifyRetrievalModal, setIsShowModifyRetrievalModal] = useState(false)
const [isShowRightPanel, { setTrue: showRightPanel, setFalse: hideRightPanel, set: setShowRightPanel }] = useBoolean(!isMobile)
const renderHitResults = (results: HitTesting[] | ExternalKnowledgeBaseHitTesting[]) => (
<div className='flex h-full flex-col rounded-t-2xl bg-background-body px-4 py-3'>
<div className='flex h-full flex-col rounded-tl-2xl bg-background-body px-4 py-3'>
<div className='mb-2 shrink-0 pl-2 font-semibold leading-6 text-text-primary'>
{t('datasetHitTesting.hit.title', { num: results.length })}
</div>
@ -93,7 +93,7 @@ const HitTestingPage: FC<Props> = ({ datasetId }: Props) => {
)
const renderEmptyState = () => (
<div className='flex h-full flex-col items-center justify-center rounded-t-2xl bg-background-body px-4 py-3'>
<div className='flex h-full flex-col items-center justify-center rounded-tl-2xl bg-background-body px-4 py-3'>
<div className={cn(docStyle.commonIcon, docStyle.targetIcon, '!h-14 !w-14 !bg-text-quaternary')} />
<div className='mt-3 text-[13px] text-text-quaternary'>
{t('datasetHitTesting.hit.emptyTip')}
@ -180,7 +180,7 @@ const HitTestingPage: FC<Props> = ({ datasetId }: Props) => {
<div className='flex flex-col pt-3'>
{/* {renderHitResults(generalResultData)} */}
{submitLoading
? <div className='flex h-full flex-col rounded-t-2xl bg-background-body px-4 py-3'>
? <div className='flex h-full flex-col rounded-tl-2xl bg-background-body px-4 py-3'>
<CardSkelton />
</div>
: (

@ -1,5 +1,5 @@
'use client'
import React, { useState } from 'react'
import React, { useState, useEffect } from "react";
import { usePathname } from 'next/navigation'
import s from './index.module.css'
import { useEventEmitterContextContext } from '@/context/event-emitter'
@ -9,6 +9,33 @@ type HeaderWrapperProps = {
children: React.ReactNode
}
const useIframeHeader = () => {
const [show, setShow] = useState(true);
useEffect(() => {
// 监听父级指定操作
const handler = (event: MessageEvent) => {
// if (event.origin !== "https://gcgj.ngsk.tech:7001") return;
if (event.data.type === "HIDDEN") setShow(() => false);
};
// 初始化完成后提示iframe操作
window.parent.postMessage(
{
type: "HEADER",
},
"*"
);
window.addEventListener("message", handler);
return () => window.removeEventListener("message", handler);
}, []);
return {
show,
};
};
const HeaderWrapper = ({
children,
}: HeaderWrapperProps) => {
@ -19,6 +46,7 @@ const HeaderWrapper = ({
const workflowCanvasMaximize = localStorage.getItem('workflow-canvas-maximize') === 'true'
const [hideHeader, setHideHeader] = useState(workflowCanvasMaximize)
const { eventEmitter } = useEventEmitterContextContext()
const { show } = useIframeHeader();
eventEmitter?.useSubscription((v: any) => {
if (v?.type === 'workflow-canvas-maximize')
@ -26,15 +54,22 @@ const HeaderWrapper = ({
})
return (
<div className={classNames(
'sticky left-0 right-0 top-0 z-[15] flex min-h-[56px] shrink-0 grow-0 basis-auto flex-col',
<>
{show ? (
<div
className={classNames(
"sticky left-0 right-0 top-0 z-[15] flex min-h-[56px] shrink-0 grow-0 basis-auto flex-col",
s.header,
isBordered ? 'border-b border-divider-regular' : '',
hideHeader && inWorkflowCanvas && 'hidden',
isBordered ? "border-b border-divider-regular" : "",
hideHeader && inWorkflowCanvas && "hidden"
)}
>
{children}
</div>
)
) : (
""
)}
</>
);
}
export default HeaderWrapper

@ -164,7 +164,7 @@ const FormInputItem: FC<Props> = ({
...value,
[variable]: {
...varInput,
...newValue,
value: newValue,
},
})
}
@ -242,7 +242,7 @@ const FormInputItem: FC<Props> = ({
<AppSelector
disabled={readOnly}
scope={scope || 'all'}
value={varInput as any}
value={varInput?.value}
onSelect={handleAppOrModelSelect}
/>
)}
@ -251,7 +251,7 @@ const FormInputItem: FC<Props> = ({
popupClassName='!w-[387px]'
isAdvancedMode
isInWorkflow
value={varInput}
value={varInput?.value}
setModel={handleAppOrModelSelect}
readonly={readOnly}
scope={scope}

@ -15,6 +15,37 @@ import Toast from '@/app/components/base/toast'
import { IS_CE_EDITION } from '@/config'
import { useGlobalPublicStore } from '@/context/global-public-context'
const useIframeToken = () => {
const router = useRouter();
useEffect(() => {
// 监听父级指定操作
const handler = (event: MessageEvent) => {
// if (event.origin !== "https://gcgj.ngsk.tech:7001") return;
if (
event.data.type === "LOGIN_AND_WORKFLOW_INTO" &&
event.data.tokens &&
event.data.workflowUrl
) {
localStorage.setItem("console_token", event.data.tokens.console_token);
localStorage.setItem("refresh_token", event.data.tokens.refresh_token);
router.replace(event.data.workflowUrl);
}
};
// 首页初始化完成后提示iframe操作
window.parent.postMessage(
{
type: "LOGIN_AND_WORKFLOW",
},
"*"
);
window.addEventListener("message", handler);
return () => window.removeEventListener("message", handler);
}, []);
};
const NormalForm = () => {
const { t } = useTranslation()
const router = useRouter()
@ -29,6 +60,7 @@ const NormalForm = () => {
const [showORLine, setShowORLine] = useState(false)
const [allMethodsAreDisabled, setAllMethodsAreDisabled] = useState(false)
const [workspaceName, setWorkSpaceName] = useState('')
useIframeToken();
const isInviteLink = Boolean(invite_token && invite_token !== 'null')

@ -43,14 +43,25 @@ const nextConfig = {
search: '',
})),
},
experimental: {
},
experimental: {},
// fix all before production. Now it slow the develop speed.
eslint: {
// Warning: This allows production builds to successfully complete even if
// your project has ESLint errors.
ignoreDuringBuilds: true,
dirs: ['app', 'bin', 'config', 'context', 'hooks', 'i18n', 'models', 'service', 'test', 'types', 'utils'],
dirs: [
'app',
'bin',
'config',
'context',
'hooks',
'i18n',
'models',
'service',
'test',
'types',
'utils',
],
},
typescript: {
// https://nextjs.org/docs/api-reference/next.config.js/ignoring-typescript-errors
@ -67,6 +78,23 @@ const nextConfig = {
]
},
output: 'standalone',
async headers() {
return [
{
source: '/(.*)', // 匹配所有路由
headers: [
{
key: 'X-Frame-Options',
value: 'SAMEORIGIN', // 或 ALLOWALL更宽松
},
{
key: 'Content-Security-Policy',
value: 'frame-ancestors "self" *', // 允许所有
},
],
},
]
},
}
module.exports = withBundleAnalyzer(withMDX(nextConfig))

Loading…
Cancel
Save