Compare commits

..

2054 Commits

Author SHA1 Message Date
Novice Lee
95eeb7b0d1 feat: agent node custom tool input 2025-02-07 11:02:31 +08:00
Yeuoly
933b6abc13 fix: ci 2025-02-06 18:36:14 +08:00
Yeuoly
1097bf314a Merge branch 'plugins/beta' into dev/plugin-deploy 2025-02-06 18:30:49 +08:00
Boris Polonsky
beebba0340 Unify plugin endpoint configuration for api and worker: An alternative solution to PR #13214 (#13239) 2025-02-06 11:29:37 +08:00
Yeuoly
4e27d82d68 improve: remove docker-legacy (#13236) 2025-02-05 20:28:02 +08:00
Boris Polonsky
cdeaf3f70b Fix ruff linting error caused by api/models/dataset.py (#13221) 2025-02-05 17:45:23 +08:00
Yeuoly
24839bb3e1 fix: mismatches dependencies in dockerfile (#13220) 2025-02-05 17:00:26 +08:00
KVOJJJin
1650dbfbb1 Fix: merge error of tracing and web app setting modal (#13219) 2025-02-05 16:16:28 +08:00
Joel
fd11817044 fix: select input not show save value (#13218) 2025-02-05 16:13:40 +08:00
Wu Tianwei
6642fc6012 fix: fix fallback route logic (#13199) 2025-02-05 14:38:36 +08:00
KVOJJJin
2710242982 Feat: feature and log dark mode (#13208) 2025-02-05 13:58:19 +08:00
kurokobo
1de84fdda0 fix: correct env vars for docker deployment (#13055) 2025-01-27 11:19:29 +08:00
Wu Tianwei
4920821270 feat: docx image preview (#13057) 2025-01-26 16:08:58 +08:00
Jyong
a16c729d5a add sign-content (#13050) 2025-01-26 16:05:19 +08:00
Wu Tianwei
3befbc1d68 feat: docx image preview (#13057) 2025-01-26 15:12:05 +08:00
Jyong
62c413aca5 add sign-content (#13050) 2025-01-26 10:58:47 +08:00
Joel
6887b501b8 fix: can choose selected tools and show tool name instead of label (#13025) 2025-01-24 22:34:09 +08:00
非法操作
f93bf131ab fix(1.0): explore market page empty (#13017) 2025-01-24 18:43:56 +08:00
非法操作
ef1f429437 fix(1.0): update github plugin 404 (#13014) 2025-01-24 18:42:14 +08:00
KVOJJJin
c966bf1474 Feat: dark mode of app configure (#13010) 2025-01-24 14:16:35 +08:00
Yeuoly
899df30bf6 Plugin/merge main to plugin/beta 20250122 (#12962)
Signed-off-by: yihong0618 <zouzou0208@gmail.com>
Signed-off-by: -LAN- <laipz8200@outlook.com>
Co-authored-by: kurokobo <kuro664@gmail.com>
Co-authored-by: Hiroshi Fujita <fujita-h@users.noreply.github.com>
Co-authored-by: NFish <douxc512@gmail.com>
Co-authored-by: Gen Sato <52241300+halogen22@users.noreply.github.com>
Co-authored-by: eux <euxuuu@gmail.com>
Co-authored-by: huangzhuo1949 <167434202+huangzhuo1949@users.noreply.github.com>
Co-authored-by: huangzhuo <huangzhuo1@xiaomi.com>
Co-authored-by: lotsik <lotsik@mail.ru>
Co-authored-by: crazywoola <100913391+crazywoola@users.noreply.github.com>
Co-authored-by: Wu Tianwei <30284043+WTW0313@users.noreply.github.com>
Co-authored-by: nite-knite <nkCoding@gmail.com>
Co-authored-by: Jyong <76649700+JohnJyong@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: gakkiyomi <gakkiyomi@aliyun.com>
Co-authored-by: CN-P5 <heibai2006@gmail.com>
Co-authored-by: CN-P5 <heibai2006@qq.com>
Co-authored-by: Chuehnone <1897025+chuehnone@users.noreply.github.com>
Co-authored-by: yihong <zouzou0208@gmail.com>
Co-authored-by: Kevin9703 <51311316+Kevin9703@users.noreply.github.com>
Co-authored-by: -LAN- <laipz8200@outlook.com>
Co-authored-by: Boris Feld <lothiraldan@gmail.com>
Co-authored-by: mbo <himabo@gmail.com>
Co-authored-by: mabo <mabo@aeyes.ai>
Co-authored-by: Warren Chen <warren.chen830@gmail.com>
Co-authored-by: KVOJJJin <jzongcode@gmail.com>
Co-authored-by: JzoNgKVO <27049666+JzoNgKVO@users.noreply.github.com>
Co-authored-by: jiandanfeng <chenjh3@wangsu.com>
Co-authored-by: zhu-an <70234959+xhdd123321@users.noreply.github.com>
Co-authored-by: zhaoqingyu.1075 <zhaoqingyu.1075@bytedance.com>
Co-authored-by: 海狸大師 <86974027+yenslife@users.noreply.github.com>
Co-authored-by: Xu Song <xusong.vip@gmail.com>
Co-authored-by: rayshaw001 <396301947@163.com>
Co-authored-by: Ding Jiatong <dingjiatong@gmail.com>
Co-authored-by: Bowen Liang <liangbowen@gf.com.cn>
Co-authored-by: JasonVV <jasonwangiii@outlook.com>
Co-authored-by: le0zh <newlight@qq.com>
Co-authored-by: zhuxinliang <zhuxinliang@didiglobal.com>
Co-authored-by: k-zaku <zaku99@outlook.jp>
Co-authored-by: Joel <iamjoel007@gmail.com>
Co-authored-by: luckylhb90 <luckylhb90@gmail.com>
Co-authored-by: hobo.l <hobo.l@binance.com>
Co-authored-by: jiangbo721 <365065261@qq.com>
Co-authored-by: 刘江波 <jiangbo721@163.com>
Co-authored-by: Shun Miyazawa <34241526+miya@users.noreply.github.com>
Co-authored-by: EricPan <30651140+Egfly@users.noreply.github.com>
Co-authored-by: crazywoola <427733928@qq.com>
Co-authored-by: zxhlyh <jasonapring2015@outlook.com>
Co-authored-by: sino <sino2322@gmail.com>
Co-authored-by: Jhvcc <37662342+Jhvcc@users.noreply.github.com>
Co-authored-by: lowell <lowell.hu@zkteco.in>
2025-01-23 14:48:16 +08:00
zxhlyh
8d8d3e3f2f fix: plugin search api url (#12977) 2025-01-23 14:25:24 +08:00
非法操作
5f0fa38ec6 fix(1.0): invoke llm raise error (#12753) 2025-01-22 16:46:35 +08:00
Yeuoly
cc1fe70d34 fix: add adapter for datasets update checking (#12939) 2025-01-22 15:40:06 +08:00
Hiroki Nagai
15ee1e11be fix: 500 error in Notion integration API (#12934) 2025-01-22 14:38:01 +08:00
Joel
c8b4a76530 fix: agent node output vars error (#12931) 2025-01-22 13:33:27 +08:00
Novice Lee
4765728cef feat: add agent node stream output 2025-01-22 09:59:40 +08:00
Yeuoly
6ee4eba86b fix: change default PLUGIN_DAEMON_URL to http://localhost:5002 (#12915) 2025-01-21 22:30:24 +08:00
非法操作
357d2e8be8 fix(1.0): add cross-env to pnpm run dev (#12600) 2025-01-21 19:51:32 +08:00
kurokobo
b5accda3fe fix: correct validation for agent node which is invoked before publishing the app (#12805) 2025-01-21 10:07:25 +08:00
非法操作
de4752a16b fix(1.0): unexpected error raise (#12812) 2025-01-21 10:04:56 +08:00
非法操作
60427f1adf chore(1.0): improve some environment variables (#12814) 2025-01-21 10:04:46 +08:00
非法操作
1a313c868d fix(1.0): sometimes add tool raise error (#12821) 2025-01-21 10:04:05 +08:00
Yeuoly
0b32b1988f fix: missing tenant_id in get_signed_file_url_for_plugin (#12734) 2025-01-14 19:39:21 +08:00
KVOJJJin
e56c051d97 Fix: tool card info (#12726) 2025-01-14 16:10:00 +08:00
Novice Lee
5063f27916 Merge branch 'fix/correct-provider-type' into dev/plugin-deploy 2025-01-14 14:21:15 +08:00
Novice Lee
11428172eb fix: correct the provider type 2025-01-14 14:20:03 +08:00
Joel
0ae072dd75 chore: add plugin/deploy deploy 2025-01-14 14:13:43 +08:00
Joel
d6b9648332 merge 2025-01-14 11:35:29 +08:00
Joel
0a6b4d01d7 fix: save tool not add type (#12712) 2025-01-14 10:28:41 +08:00
Novice Lee
8865bdca05 feat: add agent strategy on node start 2025-01-13 13:30:35 +08:00
Novice
98b139c680 feat: add agent strategy on node start (#12667)
Co-authored-by: Novice Lee <novicelee@NoviPro.local>
2025-01-13 13:04:05 +08:00
zxhlyh
f0a3c14adb fix: plugins task (#12662) 2025-01-13 10:59:34 +08:00
Yeuoly
51947575c2 feat: add skip signature verification (#12627) 2025-01-10 20:37:33 +08:00
Yeuoly
cb8debee3e Plugins/fix backend ci errors (#12615) 2025-01-10 19:46:59 +08:00
zxhlyh
d56079a549 fix: marketplace card i18n (#12623) 2025-01-10 18:15:58 +08:00
zxhlyh
c08b451874 fix: marketplace page list style (#12613) 2025-01-10 17:31:09 +08:00
非法操作
ac336ff359 fix(1.0): add missing environment variable (#12599) 2025-01-10 17:17:13 +08:00
Joel
4cbd511cd7 fix: ci use pnpm error (#12597) 2025-01-10 16:55:16 +08:00
Yeuoly
c03adcb154 Fix: style checks and unittests (#12603) 2025-01-10 16:40:39 +08:00
Hiroshi Fujita
04dade2f9b fix: update fetchReleases to use owner and repo from meta (#12590) 2025-01-10 15:46:10 +08:00
kurokobo
f69220ca96 fix: add location directive for /explore (#12572) 2025-01-10 15:42:32 +08:00
Wu Tianwei
a5e24ff6d3 fix: update language change handling in I18n component (#12596)
ok
2025-01-10 14:47:24 +08:00
zxhlyh
71976f9192 fix: marketplace serach bundle (#12581) 2025-01-10 14:03:00 +08:00
Joel
39ec6c8025 Fix/setting model page crash (#12594)
Co-authored-by: JzoNg <jzongcode@gmail.com>
2025-01-10 13:10:58 +08:00
NFish
e370045ac4 Fix:screenshots image missed (#12589) 2025-01-10 11:47:20 +08:00
Yeuoly
28edbbac0b Plugins/bump to 1.0.0 beta.1 (#12568) 2025-01-09 22:46:24 +08:00
Yeuoly
782abcecd8 bump version to 1.0.0-beta.1 (#12567) 2025-01-09 22:38:20 +08:00
Yeuoly
4deb02fc2c fix: rename plugin db name to dify_plugin (#12565) 2025-01-09 21:56:24 +08:00
Joel
f967180dc2 fix: not show stragry type (#12561) 2025-01-09 20:55:17 +08:00
Yeuoly
cead13cbc3 plugins: remove middleware.1.yaml (#12559) 2025-01-09 20:34:49 +08:00
Yeuoly
078c151065 fix: add-default-console-url (#12558) 2025-01-09 20:34:13 +08:00
Yeuoly
17babca362 Introducing: Plugin Mechanism (#12553) 2025-01-09 19:54:17 +08:00
AkaraChen
8efed8858c feat: reset parameters when switch agent strategy (#12549) 2025-01-09 19:31:02 +08:00
Yeuoly
0d411a0b5a feat: refactor docker-compose (#12550) 2025-01-09 19:08:11 +08:00
Yeuoly
13f0c01f93 feat: add ci checks to plugins/beta branch (#12542)
Co-authored-by: Novice Lee <novicelee@NoviPro.local>
2025-01-09 18:57:09 +08:00
zxhlyh
3c014f3ae5 Feat/plugins (#12547)
Co-authored-by: AkaraChen <akarachen@outlook.com>
Co-authored-by: Yi <yxiaoisme@gmail.com>
Co-authored-by: Joel <iamjoel007@gmail.com>
Co-authored-by: JzoNg <jzongcode@gmail.com>
Co-authored-by: twwu <twwu@dify.ai>
Co-authored-by: kurokobo <kuro664@gmail.com>
Co-authored-by: Hiroshi Fujita <fujita-h@users.noreply.github.com>
2025-01-09 18:47:41 +08:00
zxhlyh
da8e1ded55 Merge branch 'feat/plugins' into dev/plugin-deploy 2025-01-09 18:33:53 +08:00
zxhlyh
d78c7fc9f2 fix: agent log 2025-01-09 18:31:17 +08:00
JzoNg
dc6e02f3ec fix plugin card 2025-01-09 17:46:46 +08:00
AkaraChen
4042c1f6c4 fix: prevent show error when data is not ready 2025-01-09 17:41:27 +08:00
AkaraChen
b450c6f976 fix: checklist show error when strategy provider list not fetched 2025-01-09 17:41:08 +08:00
AkaraChen
4e29694a46 feat: show error when not select required model 2025-01-09 17:37:43 +08:00
AkaraChen
43f60cec24 feat: show error when not select required model 2025-01-09 17:37:29 +08:00
Yeuoly
e4c4490175 refactor 2025-01-09 17:27:05 +08:00
AkaraChen
4bbcc78c84 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2025-01-09 17:23:06 +08:00
AkaraChen
31e0aea181 fix: checklist show error when import dsl 2025-01-09 17:23:01 +08:00
Novice Lee
26ab0314a9 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2025-01-09 17:21:10 +08:00
Novice Lee
4b5586375f feat: add node id in agent log 2025-01-09 17:20:53 +08:00
Yi
6b0325d01d fix: revert prev commit bc it causes corner issues 2025-01-09 17:15:55 +08:00
Yeuoly
94a62f6b4e enhancement: remove unrequired deps 2025-01-09 17:06:38 +08:00
Novice Lee
ffbbd47d13 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2025-01-09 16:55:58 +08:00
Novice Lee
d76af08784 feat: add agent log icon 2025-01-09 16:55:17 +08:00
Yeuoly
f748d6c7c4 fix: mypy issues 2025-01-09 16:53:30 +08:00
Novice Lee
2b20ba697c Merge branch 'fix/chore-fix' into dev/plugin-deploy 2025-01-09 16:50:35 +08:00
Novice Lee
ff5d12a437 feat: add agent log icon 2025-01-09 16:50:05 +08:00
Yi
3bdaf2dcae chore: avoid unnecessary loading for the model selector in agent node 2025-01-09 16:48:02 +08:00
JzoNg
dfe69a9c13 keep panel show after tool selecting 2025-01-09 16:39:54 +08:00
AkaraChen
6d55ecd7fd fix: modal label show when no model selected 2025-01-09 16:39:42 +08:00
AkaraChen
90b390346b Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2025-01-09 16:22:24 +08:00
AkaraChen
60b582d97a chore: remove log 2025-01-09 16:22:13 +08:00
JzoNg
ad94bcc2b3 Merge branch 'feat/plugins' into dev/plugin-deploy 2025-01-09 16:19:03 +08:00
JzoNg
f2f0265b3e fix style of required 2025-01-09 16:18:08 +08:00
zxhlyh
e1db41a1b3 Merge branch 'feat/plugins' into dev/plugin-deploy 2025-01-09 16:14:28 +08:00
zxhlyh
f7edff6c6b fix: agent log 2025-01-09 16:13:59 +08:00
AkaraChen
145ef794b6 fix: switch version not work 2025-01-09 16:08:20 +08:00
AkaraChen
efb6a5dd3e Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2025-01-09 15:48:00 +08:00
AkaraChen
0fe4fd65e2 fix: down arrow not shown not agent strategy selector 2025-01-09 15:47:50 +08:00
Joel
ab66f30e1d feat: add parallel test case 2025-01-09 15:31:44 +08:00
AkaraChen
566dc9b4a8 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2025-01-09 15:17:31 +08:00
AkaraChen
641395b3ec feat: agent strategy form support required mark 2025-01-09 15:17:27 +08:00
Joel
db60150f30 chore: change use new log struct generator 2025-01-09 15:08:05 +08:00
AkaraChen
b964c713bd chore: add tooltip props to agent strategy select 2025-01-09 14:56:46 +08:00
AkaraChen
7b4d49a79c Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2025-01-09 14:53:07 +08:00
AkaraChen
0ad08f523b chore: add tooltip props to agent strategy select 2025-01-09 14:52:59 +08:00
Yi
f4ca5938ec Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2025-01-09 14:47:17 +08:00
Yi
38437efec0 fix: change "upgrade" to "install" for generality in plugin version switch 2025-01-09 14:47:08 +08:00
JzoNg
9604e54df5 Merge branch 'feat/plugins' into dev/plugin-deploy 2025-01-09 14:42:53 +08:00
JzoNg
52553a66ba fix style of agent strategy 2025-01-09 14:40:58 +08:00
AkaraChen
a87c2d7e20 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2025-01-09 14:31:49 +08:00
AkaraChen
08cff0045d feat: form not installed indicator 2025-01-09 14:31:43 +08:00
JzoNg
195a507b40 dark mode of api 2025-01-09 14:14:08 +08:00
JzoNg
d7ec013665 modals of app overview 2025-01-09 14:14:08 +08:00
Joel
371febf3cf chore: merge 2025-01-09 13:55:37 +08:00
Joel
dc9675d2d8 fix: plugin tool width in agent app 2025-01-09 13:53:07 +08:00
Joel
06fe17c93e chore: enchance fold into anim 2025-01-09 13:45:30 +08:00
Yeuoly
edf9409877 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2025-01-09 13:37:15 +08:00
Yeuoly
76e24d91c0 fix: migrations 2025-01-09 13:30:43 +08:00
AkaraChen
5ec4695e4a feat: tool icon check plugin status 2025-01-09 13:29:23 +08:00
AkaraChen
bb60db7078 feat: tool selector get icon from marketplace 2025-01-09 13:00:43 +08:00
AkaraChen
e3e8eafd32 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2025-01-09 11:53:30 +08:00
AkaraChen
eff6a55960 fix: install button 2025-01-09 11:53:24 +08:00
Yi
a7f0933e55 chore: add checks in the url fetch step of the installFromGitHub 2025-01-09 11:52:44 +08:00
JzoNg
eaf1177cd4 dark mode of overview card view 2025-01-09 11:35:37 +08:00
JzoNg
297b5280f0 tracing modal & config 2025-01-09 11:35:37 +08:00
Joel
4aac48ed61 feat: github install add anim 2025-01-09 11:29:48 +08:00
Joel
192af8df9f feat: local and bundle support hide anim 2025-01-09 11:16:33 +08:00
Novice Lee
805e9638da fix: change the agent strategy category 2025-01-09 11:14:08 +08:00
Novice Lee
5ce4ddc0ed fix: change the agent strategy category 2025-01-09 11:13:00 +08:00
Joel
9822445c1e chore: all hide logic to hooks 2025-01-09 11:04:23 +08:00
Joel
018e32e355 fix: installed not clear countdown 2025-01-09 10:49:22 +08:00
zxhlyh
41b720502f merge main 2025-01-09 10:40:46 +08:00
zxhlyh
cd30fd5a9a Merge branch 'feat/plugins' into dev/plugin-deploy 2025-01-09 10:36:18 +08:00
zxhlyh
a157af724f fix: marketplace submit button 2025-01-09 10:35:47 +08:00
AkaraChen
cc0d864599 fix: agent node tool list header width 2025-01-09 09:55:56 +08:00
Novice Lee
00ad751a57 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2025-01-09 08:48:00 +08:00
Novice Lee
491d641485 feat: add agent node log 2025-01-09 08:32:32 +08:00
Yeuoly
172c5f19cc fix: formatter 2025-01-08 21:11:58 +08:00
Yeuoly
b7d168ac59 fix: mypy linter 2025-01-08 21:11:42 +08:00
Yeuoly
fb309462ad Merge branch 'main' into fix/chore-fix 2025-01-08 20:36:22 +08:00
JzoNg
f1794a3d1b Merge branch 'feat/plugins' into dev/plugin-deploy 2025-01-08 20:02:34 +08:00
JzoNg
4a6a1b9855 chore: fix request form data 2025-01-08 20:01:01 +08:00
Joel
7ccc268ced fix: stop anim 2025-01-08 19:34:41 +08:00
Joel
6483d20f56 feat: install countdown 2025-01-08 19:25:01 +08:00
AkaraChen
5c82aebf4e Merge branch 'feat/plugins' into dev/plugin-deploy 2025-01-08 19:09:22 +08:00
Yi
61237e8037 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2025-01-08 17:55:41 +08:00
Yi
aae601f233 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2025-01-08 17:55:19 +08:00
AkaraChen
701520ffd0 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2025-01-08 17:54:31 +08:00
AkaraChen
596e3409b7 fix: agent prompt 2025-01-08 17:54:24 +08:00
Yi
38dd285656 fix: long model name display issue 2025-01-08 17:53:25 +08:00
zxhlyh
9ab39c3feb Merge branch 'feat/plugins' into dev/plugin-deploy 2025-01-08 17:49:11 +08:00
zxhlyh
0248c8cb8c fix: agent key 2025-01-08 17:48:26 +08:00
AkaraChen
88b3c0b7a6 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2025-01-08 17:36:32 +08:00
AkaraChen
3ae7787011 fix: number not supported 2025-01-08 17:36:26 +08:00
Yi
c357ec0f7c chore: add loading to the model selector trigger 2025-01-08 17:27:03 +08:00
Yi
763f91fcea Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2025-01-08 17:12:01 +08:00
Yi
62d53399ae fix: add bg color to the top section in plugins page 2025-01-08 17:11:55 +08:00
Joel
c3215a8f94 feat: fold into animation 2025-01-08 17:02:47 +08:00
AkaraChen
d65c1218ae Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2025-01-08 16:57:01 +08:00
AkaraChen
83723212af fix: agent node getNodeUsedVars 2025-01-08 16:56:56 +08:00
Yi
84c2a9dc3b Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2025-01-08 16:51:14 +08:00
Yi
87d7df3ed4 fix: make the status indicator component compatible with the switch plugin version component 2025-01-08 16:51:06 +08:00
zxhlyh
5cc9c79284 Merge branch 'feat/plugins' into dev/plugin-deploy 2025-01-08 16:47:27 +08:00
zxhlyh
586f9d8d89 fix: agent log 2025-01-08 16:46:35 +08:00
WTW0313
b656b7a0dd Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2025-01-08 16:41:22 +08:00
WTW0313
0fdf7b23c6 feat: add 'agent' tag to plugin constants and translations 2025-01-08 16:41:16 +08:00
Yi
369e3eb97f feat: add version switch in model selector 2025-01-08 16:39:56 +08:00
AkaraChen
f58eef74b3 feat: switch plugin version changelog 2025-01-08 16:19:41 +08:00
AkaraChen
2fd083629d feat: new switch plugin version 2025-01-08 15:58:05 +08:00
Yi
755685a89a Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2025-01-08 15:54:21 +08:00
Yi
23b29b1d21 fix: check-dependencies typo and fetch model list typo 2025-01-08 15:54:04 +08:00
zxhlyh
4b01ef2b48 fix: chat log 2025-01-08 15:42:18 +08:00
JzoNg
05d273d643 fix tracing dropdown 2025-01-08 15:40:13 +08:00
JzoNg
5481b42257 dark mode for tracing dropdown 2025-01-08 15:28:45 +08:00
AkaraChen
fa83f2e2fa fix: switch version plugin 2025-01-08 15:13:19 +08:00
AkaraChen
5e4d2f9501 Revert "chore: remove switch version component in strategy select"
This reverts commit f63cc9e069.
2025-01-08 14:55:55 +08:00
Yi
fdfe724438 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2025-01-08 14:50:25 +08:00
Yi
b0b373d2fb fix: revert the modelInList check in the model icon component 2025-01-08 14:50:14 +08:00
AkaraChen
f63cc9e069 chore: remove switch version component in strategy select 2025-01-08 14:48:36 +08:00
Yi
8c9c336b64 fix: isInModelList default value 2025-01-08 14:47:01 +08:00
Yi
2dac103463 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2025-01-08 14:45:10 +08:00
Yi
17dfb3654f feat: add version incompatible case 2025-01-08 14:45:03 +08:00
zxhlyh
730d33176e Merge branch 'feat/plugins' into dev/plugin-deploy 2025-01-08 14:20:36 +08:00
zxhlyh
98ad18ba81 fix: agent log 2025-01-08 14:20:08 +08:00
AkaraChen
53bb1bb937 fix: agent node cannot output var 2025-01-08 14:09:35 +08:00
AkaraChen
93806148cd chore: plugin mutation modal component 2025-01-08 12:37:33 +08:00
JzoNg
adf0d94a9a unsupported actions 2025-01-08 11:51:59 +08:00
zxhlyh
d17932d723 fix: install task icon 2025-01-08 10:12:55 +08:00
Yi
3cbb288a25 feat: add version check i18n 2025-01-08 10:09:11 +08:00
AkaraChen
99e2eaa6ee fix: switch plugin version 2025-01-08 10:03:00 +08:00
Novice Lee
86318d9137 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2025-01-08 08:04:48 +08:00
Novice Lee
b56d2b739b feat: add fc agent mode support 2025-01-08 07:41:17 +08:00
Yeuoly
c706226b2f Merge branch 'fix/chore-fix' into dev/plugin-deploy 2025-01-07 20:53:25 +08:00
Yeuoly
fb7b2c8ff3 fix: backwards invoke nodes 2025-01-07 20:52:25 +08:00
Yeuoly
f9f48b7139 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2025-01-07 20:16:04 +08:00
Yeuoly
c3440a27fb fix 2025-01-07 18:59:13 +08:00
Joel
6006380723 fix: tool select ui problem in workflow 2025-01-07 17:10:27 +08:00
Joel
55ad1fe1f0 chore: tool selelct use the same tools data 2025-01-07 16:58:31 +08:00
Yi
0383fce821 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2025-01-07 16:57:09 +08:00
Yi
85610651c0 node ui fix 2025-01-07 16:57:01 +08:00
AkaraChen
768e1b9da3 fix: wrong tooltip content for switch plugin version 2025-01-07 16:43:36 +08:00
Joel
a6d172f111 feat: github refresh plugin list 2025-01-07 16:42:40 +08:00
Joel
5817c07db6 feat: local install refresh 2025-01-07 16:34:08 +08:00
Yi
2f5da1f6aa fix: update model icon 2025-01-07 16:31:15 +08:00
JzoNg
d7657f4874 Merge branch 'feat/plugins' into dev/plugin-deploy 2025-01-07 15:57:17 +08:00
AkaraChen
130cfaf2a4 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2025-01-07 15:20:00 +08:00
AkaraChen
f840b7db0c fix: type for tool list 2025-01-07 15:19:46 +08:00
JzoNg
aac2184069 chore: use install button in tool item 2025-01-07 15:18:07 +08:00
AkaraChen
f03631ff9e feat: init agent strategy install from marketplace 2025-01-07 15:08:36 +08:00
Yeuoly
ff3d3f71fb fix: use host.docker.internal as the default plugin daemon middleware endpoint 2025-01-07 14:56:03 +08:00
Yeuoly
485d510e80 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2025-01-07 14:50:29 +08:00
Yi
e207894d7e Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2025-01-07 14:45:00 +08:00
Yeuoly
9685b9a302 refactor: docker-compose-middleware.yaml 2025-01-07 14:44:08 +08:00
Yi
8512a7d3ad chore: update the onOpenModel function to a hook 2025-01-07 14:43:54 +08:00
JzoNg
46614cc6f5 fix badge & refresh state of tool install state 2025-01-07 14:41:48 +08:00
AkaraChen
b39acd0bad Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2025-01-07 14:03:53 +08:00
AkaraChen
48b88b90f5 feat: i18n text in agent strategy selector 2025-01-07 14:03:40 +08:00
zxhlyh
851fe246a7 fix: installing info in plugin nav 2025-01-07 14:00:29 +08:00
Yi
ff61c22f36 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2025-01-07 12:48:42 +08:00
Yi
e6eae8568f chore: update the model install button 2025-01-07 12:48:36 +08:00
JzoNg
6d5c34564b fix qrcode z-index 2025-01-07 12:16:34 +08:00
JzoNg
6d8b54f1e5 Merge branch 'feat/plugins' into dev/plugin-deploy 2025-01-07 11:58:29 +08:00
AkaraChen
4c5fa00c50 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2025-01-07 11:57:40 +08:00
AkaraChen
910e6d17d3 feat: adjust strategy selector height 2025-01-07 11:57:35 +08:00
JzoNg
275696edba fix system model selector 2025-01-07 11:53:34 +08:00
JzoNg
1348e32015 fix balance model z-index 2025-01-07 11:53:34 +08:00
JzoNg
f5b2735dd5 theme default light 2025-01-07 11:53:34 +08:00
JzoNg
8d39ec1da5 chart drak mode 2025-01-07 11:53:34 +08:00
Yi
0f6cbf25d3 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2025-01-07 11:34:09 +08:00
Joel
0e98794d49 feat: use all refresh plugin tools to hooks 2025-01-07 11:31:22 +08:00
AkaraChen
1419430015 chore: upd 2025-01-07 11:25:06 +08:00
Yi
5d25643f54 fix: group icon style 2025-01-07 11:18:01 +08:00
AkaraChen
e24b04b30f refactor: switch plugin version component to not accept version 2025-01-07 10:58:53 +08:00
AkaraChen
a8c4870349 refactor: switch plugin version component to not accept version 2025-01-07 10:55:42 +08:00
AkaraChen
bdb9d676b1 chore: update switch plugin i18n 2025-01-07 10:49:26 +08:00
AkaraChen
0beebab605 fix: workflow store agent strategy not up to date 2025-01-07 09:57:35 +08:00
AkaraChen
15f3e46c49 refactor: some field name in strategy status 2025-01-07 09:30:35 +08:00
Yeuoly
07c7b7b886 fix: remove 5002 port from docker mapping 2025-01-06 21:45:44 +08:00
kurokobo
8d75abc976 fix: correct fetch_from for customizable models (#12400) 2025-01-06 21:16:39 +08:00
Yeuoly
aa6452b3bf fix: use session to manage AppSite 2025-01-06 21:12:50 +08:00
Yeuoly
3799d40937 feat: support docker deployment for plugin 2025-01-06 20:28:50 +08:00
Joel
61d2f70927 feat: add transform node to node data 2025-01-06 18:36:45 +08:00
Joel
228cd1cdbe feat: add iteration id 2025-01-06 16:48:24 +08:00
Joel
e0ed17a2e6 chore: can generator middle struct 2025-01-06 15:31:25 +08:00
Yeuoly
d2ff8a2381 fix: bugs 2025-01-06 14:59:40 +08:00
zxhlyh
07aa2ca9cf fix: single run log 2025-01-03 16:34:23 +08:00
Joel
5fdfba6b00 feat: make iteration 2025-01-03 15:41:04 +08:00
AkaraChen
fbf9984d85 refactor: strategy status 2025-01-03 15:25:10 +08:00
Yeuoly
150b4ea1eb Merge branch 'fix/chore-fix' into dev/plugin-deploy 2025-01-03 14:48:39 +08:00
Yeuoly
5f51a19de2 fix: allow meta to be None 2025-01-03 14:48:19 +08:00
Yeuoly
beeb11a5dc Merge branch 'fix/chore-fix' into dev/plugin-deploy 2025-01-03 14:10:22 +08:00
Yeuoly
71e0bfcbd8 fix: updating tool credentials does not works as expected 2025-01-03 14:09:17 +08:00
AkaraChen
2296bb162b Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2025-01-03 13:52:43 +08:00
AkaraChen
06f0c3c886 refactor: strategy status 2025-01-03 13:52:38 +08:00
JzoNg
483890b207 fix install in tool item 2025-01-03 13:39:23 +08:00
AkaraChen
390107f97e Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2025-01-03 10:35:11 +08:00
AkaraChen
5ba0b85738 feat: install plugin button 2025-01-03 10:35:06 +08:00
JzoNg
39335b8038 refactor I18n render in plugin detail 2025-01-03 10:16:44 +08:00
twwu
5fb356fd33 refactor: rename renderI18nObject to getValueFromI18nObject for clarity 2025-01-02 18:07:44 +08:00
twwu
c458c28c62 feat: enhance plugin item localization with i18n support 2025-01-02 17:35:11 +08:00
AkaraChen
055fb22b9b Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2025-01-02 16:36:03 +08:00
AkaraChen
f2eb095960 feat: strategy install status 2025-01-02 16:35:58 +08:00
Joel
d5cfb26db6 feat: support make retry data 2025-01-02 16:29:12 +08:00
zxhlyh
7519c9a0d6 Merge branch 'feat/plugins' into dev/plugin-deploy 2025-01-02 15:51:21 +08:00
zxhlyh
a514bde428 fix: marketplace page size 2025-01-02 15:50:40 +08:00
AkaraChen
87ce813175 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2025-01-02 15:03:23 +08:00
AkaraChen
336b26569b feat: agent form string type support var 2025-01-02 15:03:18 +08:00
zxhlyh
a432fcfd5e agent node single run 2025-01-02 14:56:15 +08:00
AkaraChen
0ed4ec5cd0 fix: agent strategy selector show workflow 2025-01-02 14:48:40 +08:00
AkaraChen
add6dff789 feat: agent node check install strategy 2025-01-02 14:27:19 +08:00
Joel
c469da2020 fix: handle install title and descript may caused i18n problem 2025-01-02 14:22:04 +08:00
Joel
55aad3718d fix: multi loop nodes remove children error 2025-01-02 14:09:57 +08:00
AkaraChen
c6c388fbda feat: agent checklist i18n 2025-01-02 13:58:30 +08:00
AkaraChen
d3d606799d Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2025-01-02 11:46:52 +08:00
AkaraChen
c1ae681b6c feat: agent checklist i18n 2025-01-02 11:46:47 +08:00
Joel
f11ea5ae97 fix: title not show all if space is enough 2025-01-02 11:37:31 +08:00
Joel
e112357e91 chore: temp 2025-01-02 11:37:31 +08:00
AkaraChen
1b8ec6710a feat: agent node checklist 2025-01-02 11:29:10 +08:00
Joel
d49974665e Merge branch 'feat/plugins' into dev/plugin-deploy 2025-01-02 11:02:24 +08:00
Joel
a8881cc7a6 chore: temp 2025-01-02 11:00:03 +08:00
JzoNg
6f97eb5713 merge feat/plugins 2025-01-02 08:51:03 +08:00
JzoNg
4663af8a60 tool setting schema 2025-01-02 08:43:09 +08:00
Yeuoly
65077cd388 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-31 17:43:16 +08:00
Yeuoly
d815c74fc5 fix: ruff 2024-12-31 16:48:20 +08:00
Yeuoly
107e44c8fb Merge branch 'main' into fix/chore-fix 2024-12-31 16:47:56 +08:00
Yeuoly
adf7eea7fe fix: ruff 2024-12-31 16:40:26 +08:00
Yeuoly
6e73ad2fc6 feat: plugin migrations 2024-12-31 16:38:02 +08:00
AkaraChen
91ac660f81 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-12-31 16:33:22 +08:00
AkaraChen
3c829a1c28 fix: some style 2024-12-31 16:33:16 +08:00
Yi
f9ce6b6a6e Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-12-31 16:13:13 +08:00
Yi
afe8c85b99 model feature icons 2024-12-31 16:13:06 +08:00
zxhlyh
bc5cd4405b agent node single run 2024-12-31 16:08:09 +08:00
Yi
be36aedac1 agent node: fix installed model ui 2024-12-31 15:59:43 +08:00
AkaraChen
9e6f3e9161 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-12-31 15:53:45 +08:00
AkaraChen
52537c9e6b fix: model deprecated in model list 2024-12-31 15:53:38 +08:00
Joel
8d229f26d0 fix: card name too long 2024-12-31 15:47:48 +08:00
Yi
504c794e8a add icons and fix ui typos 2024-12-31 15:47:14 +08:00
Joel
cab8c6c5a7 feat: support scroll into letter 2024-12-31 15:41:29 +08:00
Yi
5bba422c0b fix model icon size in llm node 2024-12-31 15:13:56 +08:00
AkaraChen
870779534f Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-12-31 15:04:17 +08:00
AkaraChen
f956c2edcd chore: update style 2024-12-31 15:04:13 +08:00
Joel
2a29dd3534 fix: letter list not right 2024-12-31 15:01:31 +08:00
Yi
b1831bc582 fix the model icon ui 2024-12-31 14:35:11 +08:00
Yi
3e979a5ded fix: model selector's trigger ui 2024-12-31 14:23:13 +08:00
zxhlyh
7011a5029e merge main 2024-12-31 14:12:35 +08:00
zxhlyh
a66d92054a Merge branch 'feat/plugins' into dev/plugin-deploy 2024-12-31 14:09:11 +08:00
zxhlyh
d7cbbbca8e fix: tool single run 2024-12-31 14:08:40 +08:00
zxhlyh
21d082f3da feat: tool single run 2024-12-31 14:05:56 +08:00
Yi
2cdf2b2e05 fix the model icon size in the agent node 2024-12-31 14:04:03 +08:00
Yi
ec2dd750f1 fix: set a fixed height to the model selection in agent node 2024-12-31 13:59:55 +08:00
AkaraChen
066595f3aa chore: remove unused code 2024-12-31 13:50:31 +08:00
AkaraChen
f81bbee6b6 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-12-31 13:46:12 +08:00
AkaraChen
4855e87876 fix: editor 2024-12-31 13:46:06 +08:00
JzoNg
e47aaad396 remove test codes 2024-12-31 12:42:49 +08:00
JzoNg
df421796bb add model info in model selector 2024-12-31 12:41:08 +08:00
AkaraChen
fe5702784e Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-12-31 11:52:20 +08:00
AkaraChen
eba4042a62 wip: instruction field 2024-12-31 11:52:15 +08:00
Joel
3bed0346d7 fix: choose tools 2024-12-31 11:51:50 +08:00
Yi
3a09f43f70 feat: update the install logic 2024-12-31 11:46:36 +08:00
Yi
232fb66edd ui fixes in model selector 2024-12-31 11:08:53 +08:00
Yeuoly
f5dc873b81 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-30 21:14:47 +08:00
Yeuoly
06412b37d3 fix: no attribbute identity 2024-12-30 21:14:24 +08:00
Joel
a3f736f6e5 feat: multi steps circle 2024-12-30 18:39:33 +08:00
Joel
d9d42b2d8c feat: multi step circle 2024-12-30 18:38:07 +08:00
Joel
0a30018330 chore: one step circle check 2024-12-30 18:27:59 +08:00
Joel
128410902c temp 2024-12-30 18:27:59 +08:00
Yi
9b6f580365 add model install in model configuration for the agent node 2024-12-30 17:55:46 +08:00
AkaraChen
afb3548e45 refactor: agent parameters 2024-12-30 17:40:56 +08:00
JzoNg
e1cb85cee1 fix label of tool picker 2024-12-30 15:43:24 +08:00
JzoNg
f6c1ae52dd Merge branch 'feat/plugins' into dev/plugin-deploy 2024-12-30 15:30:29 +08:00
JzoNg
2007828404 installation state of tool 2024-12-30 15:28:15 +08:00
AkaraChen
f5b4366bd8 fix: agent node 2024-12-30 14:49:12 +08:00
Yeuoly
db1ad3c0f1 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-30 13:42:10 +08:00
Yeuoly
63665a5ff1 feat: add conversation_id to invoke 2024-12-30 13:41:54 +08:00
Yeuoly
7330a4a783 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-30 13:35:10 +08:00
Yeuoly
05a43e3e80 fix: rebaseing to main 2024-12-30 13:34:45 +08:00
AkaraChen
cd7e6ca010 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-12-30 13:31:02 +08:00
AkaraChen
2ac6f00efb fix: agent node toolbox 2024-12-30 13:30:57 +08:00
Yi
f461f56886 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-12-30 12:55:42 +08:00
Yi
ba16cbccf0 feat: add install options for model configuration 2024-12-30 12:55:28 +08:00
AkaraChen
08a1f241ca Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-12-30 11:28:57 +08:00
AkaraChen
a5509fbe5a feat: agent node toolbox 2024-12-30 11:28:51 +08:00
zxhlyh
76d7a64c37 Merge branch 'feat/plugins' into dev/plugin-deploy 2024-12-30 11:25:59 +08:00
zxhlyh
98a03b0593 fix: agent log structure 2024-12-30 11:25:28 +08:00
zxhlyh
f72818bed5 fix: agent log structure 2024-12-30 11:14:59 +08:00
JzoNg
0c5101fb3c fix default value for multiple tool selector 2024-12-30 10:38:45 +08:00
zxhlyh
84febd5e94 fix: agent log structure 2024-12-30 10:23:48 +08:00
JzoNg
b5ad9a58f7 default value for multiple tool selector 2024-12-30 10:23:00 +08:00
Yeuoly
7122bf3e8e Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-27 22:56:55 +08:00
Yeuoly
83fdb42520 fix: variable message 2024-12-27 22:56:39 +08:00
Yeuoly
4fb5cf675b Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-27 18:37:54 +08:00
Yeuoly
cbf405beea fix: remigrate 2024-12-27 18:37:34 +08:00
Joel
8a90a9bd5d fix: in steam mode trigger the error in change list 2024-12-27 18:28:52 +08:00
zxhlyh
bc78803171 merge feat/plugins 2024-12-27 18:11:52 +08:00
zxhlyh
6f8e217580 refact workflow run log 2024-12-27 18:10:44 +08:00
Yeuoly
af2aede783 feat: support precision to PluginParameter 2024-12-27 18:07:28 +08:00
Yeuoly
b1522e860a Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-27 17:55:57 +08:00
Yeuoly
e359ace633 fix: add agent logs 2024-12-27 17:55:41 +08:00
Yeuoly
d4a7d05043 fix: linter 2024-12-27 17:39:12 +08:00
Yeuoly
4ee4740657 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-27 17:38:10 +08:00
JzoNg
891a76f2fa enabled count 2024-12-27 17:37:18 +08:00
Yeuoly
a5555f90c6 fix: models 2024-12-27 17:34:17 +08:00
Yeuoly
78664c8903 Merge branch 'main' into fix/chore-fix 2024-12-27 17:33:58 +08:00
JzoNg
3c85363392 multiple tool selector 2024-12-27 17:29:46 +08:00
zxhlyh
a863e9f674 refact workflow run log 2024-12-27 17:22:11 +08:00
Joel
6a2a7aca9b chore: tool node support agent logs 2024-12-27 16:52:22 +08:00
AkaraChen
18393d2e27 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-12-27 16:48:32 +08:00
AkaraChen
de48a1c7e9 fix: type error 2024-12-27 16:48:16 +08:00
Joel
3d5620dfb3 fix: parallel start node not insert into the right place 2024-12-27 16:47:05 +08:00
AkaraChen
da2982ba98 feat: model list on agent node 2024-12-27 16:45:46 +08:00
AkaraChen
0108b28305 feat: model list on agent node 2024-12-27 16:39:18 +08:00
JzoNg
573c8f909c add multiple tool selector 2024-12-27 16:30:34 +08:00
Joel
3a5170716b fix: pararllel title 2024-12-27 16:29:15 +08:00
zxhlyh
0631cf0c4f Merge branch 'feat/plugins' into dev/plugin-deploy 2024-12-27 16:18:41 +08:00
zxhlyh
e4cc8f7010 refact workflow run log 2024-12-27 16:18:04 +08:00
AkaraChen
23913b8640 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-12-27 16:04:53 +08:00
AkaraChen
0d0a4cfaa1 fix: select var 2024-12-27 16:04:48 +08:00
Joel
04d8d16d8a chore: fix retry not work in iteration 2024-12-27 15:54:56 +08:00
AkaraChen
0d2a74b8cb feat: output var 2024-12-27 15:34:54 +08:00
Yeuoly
45070535bd fix: linter 2024-12-27 14:47:48 +08:00
JzoNg
1b93e1ff99 Merge branch 'feat/plugins' into dev/plugin-deploy 2024-12-27 14:47:22 +08:00
JzoNg
ae42edb8d7 remove test code 2024-12-27 14:43:07 +08:00
AkaraChen
e903cd8073 fix: llm node 2024-12-27 14:31:50 +08:00
Joel
a071d2cd1b Merge branch 'feat/plugins' into dev/plugin-deploy 2024-12-27 14:25:12 +08:00
Joel
31cca291b7 chore: remove test page 2024-12-27 14:22:00 +08:00
zxhlyh
1cc15d1ce8 merge feat/plugins 2024-12-27 14:21:32 +08:00
JzoNg
ed6c9625e8 fix scope features 2024-12-27 14:20:46 +08:00
Joel
08c517dd99 feat: iteration support parallel 2024-12-27 14:20:18 +08:00
JzoNg
69a6556f52 tool item 2024-12-27 14:09:52 +08:00
Yi
e34eebfb0b Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-12-27 13:58:05 +08:00
Yi
ef3e904839 feat: model-selector in Agent node (case: installed models) 2024-12-27 13:57:54 +08:00
AkaraChen
df5fb6dca9 feat: agent strategy max iter slider 2024-12-27 13:30:39 +08:00
Joel
2f65d0439c fix: not parall not group by branch 2024-12-27 13:08:05 +08:00
Yeuoly
e7a6bc0ec9 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-27 12:17:08 +08:00
Yeuoly
048e8cf0d1 fix: remove validate credentials 2024-12-27 12:16:58 +08:00
Yeuoly
598d208e54 fix: agent error handling 2024-12-27 12:09:39 +08:00
zxhlyh
5cdca9cafe fix: marketplace i18n 2024-12-27 11:54:42 +08:00
Yi
67019d128b Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-12-27 11:49:03 +08:00
AkaraChen
697ee496b7 chore: upd mock form for dev 2024-12-27 11:43:29 +08:00
Yeuoly
494cca82a0 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-27 11:33:13 +08:00
Yeuoly
8102cee8df fix: unbound reference 2024-12-27 11:33:04 +08:00
AkaraChen
7f5e27d001 chore: extend form component for override 2024-12-27 11:30:43 +08:00
Joel
1f128729f4 fix: sub iteration would crash page 2024-12-27 11:24:47 +08:00
Yi
a562e6db89 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-12-27 10:47:07 +08:00
Joel
c23fe3b67f chore: format 2024-12-27 10:25:15 +08:00
Yeuoly
2b8f31ec98 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-26 22:58:48 +08:00
Yeuoly
c9eb9c14d7 fix: block call to flask_app 2024-12-26 22:58:34 +08:00
Yeuoly
673ba9330c Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-26 22:30:38 +08:00
Yeuoly
e77cd87842 fix: linter 2024-12-26 22:30:22 +08:00
Yeuoly
ac5e3caebc optimize: migrate speed 2024-12-26 22:30:06 +08:00
JzoNg
95da3a4cf1 tool credential panel 2024-12-26 18:58:01 +08:00
Yeuoly
b7f04c1ba8 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-26 18:07:39 +08:00
Yeuoly
23066a9ba8 feat: support extracting plugins into local files 2024-12-26 18:05:14 +08:00
JzoNg
bfecc73de9 support extra for tool selector 2024-12-26 17:58:34 +08:00
Yi
b4e9dddbca Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-12-26 17:40:42 +08:00
Yeuoly
c95c3655fa Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-26 17:39:32 +08:00
Yeuoly
0249f15609 fix: linter 2024-12-26 17:39:21 +08:00
Yeuoly
2f523dd29f optimize: add friendly logs 2024-12-26 17:39:13 +08:00
JzoNg
10218cfe8d add tool selector in agent node 2024-12-26 17:33:06 +08:00
Yeuoly
bc1502b8fc Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-26 17:26:19 +08:00
Yeuoly
b34d815883 feat: support auto generate and template 2024-12-26 17:25:56 +08:00
JzoNg
e00da7a1d8 tool setting form 2024-12-26 17:06:15 +08:00
JzoNg
469ce0f23d add tool description 2024-12-26 17:06:15 +08:00
JzoNg
23bf0a6812 tool selector support scope 2024-12-26 17:06:11 +08:00
AkaraChen
605085bddf chore: remove max_iterations for agent node 2024-12-26 16:42:34 +08:00
Yi
dbc45f0d74 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-12-26 16:36:09 +08:00
zxhlyh
6175f8c16f merge main 2024-12-26 16:35:11 +08:00
zxhlyh
7e94056507 refact workflow run log 2024-12-26 15:44:59 +08:00
AkaraChen
1429b30e84 chore: upd 2024-12-26 15:27:15 +08:00
AkaraChen
5ef9156242 feat: custom credential form 2024-12-26 14:44:05 +08:00
zxhlyh
6f865b96a2 refact workflow run log 2024-12-26 14:41:00 +08:00
AkaraChen
b7e56a23a0 feat: custom credential form 2024-12-26 14:32:21 +08:00
Yeuoly
e7d3add5df Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-26 14:12:58 +08:00
Yeuoly
51cc63d9ce fix: undefined dereference to ApiTool 2024-12-26 14:12:43 +08:00
Yeuoly
430af95b53 fix: linter 2024-12-26 14:07:29 +08:00
Yeuoly
0164d1410a migrations for plugins 2024-12-26 14:07:12 +08:00
Yeuoly
f0178bd603 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-26 13:24:16 +08:00
Yeuoly
cbc5045b7a fix: ruff formatter 2024-12-26 13:23:56 +08:00
Yeuoly
b980c07af8 fix: ruff formatter 2024-12-26 13:22:18 +08:00
Yeuoly
e231cf2c48 fix: errors occrus during rebasing 2024-12-26 13:20:12 +08:00
Yi
5b8ad3ac4b Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-12-26 13:19:32 +08:00
AkaraChen
e0b7f48b6b chore: add i18n str 2024-12-26 13:02:00 +08:00
Yi
ff70e14de2 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-12-26 12:44:41 +08:00
AkaraChen
244517e6e7 fix: no icon in tool select 2024-12-26 12:41:44 +08:00
AkaraChen
cd08f98bff chore: upd app icon 2024-12-26 12:32:02 +08:00
Yi
b752c0654e Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-12-26 10:59:33 +08:00
AkaraChen
e07d7ee4fc chore: remove console 2024-12-26 10:55:30 +08:00
Yi
c476f06388 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-12-26 10:53:02 +08:00
AkaraChen
5f13402c6e Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-12-26 10:17:21 +08:00
AkaraChen
8dcd82290c feat: select strategy 2024-12-26 10:16:52 +08:00
zxhlyh
86eb618b84 refact workflow run log 2024-12-26 10:16:12 +08:00
Joel
e1ea82475d feat: format agent 2024-12-25 18:37:05 +08:00
Yeuoly
cd00602213 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-25 18:25:21 +08:00
Yeuoly
80d8e47e42 fix: skip json transforming if error occurs 2024-12-25 18:23:31 +08:00
zxhlyh
08515957f1 refact workflow run log 2024-12-25 16:57:22 +08:00
Joel
8503099d65 feat: integration 2024-12-25 16:46:32 +08:00
Yi
c04a89d5b1 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-12-25 16:39:22 +08:00
Joel
8d225264fa feat: retry 2024-12-25 16:25:19 +08:00
zxhlyh
26901b2c87 refact workflow run log 2024-12-25 16:15:20 +08:00
JzoNg
b56acb825f fix org info in tool detail panel 2024-12-25 15:34:07 +08:00
Yeuoly
fee4dd7d7a fix: unused stream variable 2024-12-25 15:32:59 +08:00
Yi
f1e17ad134 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-12-25 15:24:59 +08:00
AkaraChen
b8e4580074 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-12-25 15:23:50 +08:00
Yeuoly
00cf5f3841 fix: linters 2024-12-25 15:18:29 +08:00
JzoNg
935c126abd strategy detail panel 2024-12-25 15:15:55 +08:00
JzoNg
b4105fcc9c strategy list 2024-12-25 15:15:55 +08:00
AkaraChen
5f65fb1b62 chore: add model select mock 2024-12-25 15:12:33 +08:00
Yeuoly
02abf950e1 Merge fix/chore-fix into dev/plugin-deploy 2024-12-25 15:12:05 +08:00
Yi
986d6eed36 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-12-25 15:10:05 +08:00
AkaraChen
e0f83d06d8 chore: add model select mock 2024-12-25 15:06:58 +08:00
Yi
f42cfe8075 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-12-25 14:54:22 +08:00
AkaraChen
a7b2f9aef0 chore: add i18n 2024-12-25 14:52:11 +08:00
Yeuoly
9ee0c7a694 merge 2024-12-25 14:39:15 +08:00
AkaraChen
c867584049 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-12-25 14:24:02 +08:00
AkaraChen
ac2c8344f2 chore: add i18n 2024-12-25 14:23:57 +08:00
Joel
8c662e04e0 feat: add iteration error 2024-12-25 14:20:39 +08:00
AkaraChen
e1d0c29711 chore: add icon for agent 2024-12-25 14:13:20 +08:00
Yi
50c77ad405 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-12-25 14:12:54 +08:00
Joel
880496db0b chore: add more tests 2024-12-25 14:12:53 +08:00
AkaraChen
057da6c31b chore: gen agent icon 2024-12-25 14:07:05 +08:00
AkaraChen
c0a8b89e93 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-12-25 14:06:08 +08:00
AkaraChen
a8a956b5f1 chore: add i18n 2024-12-25 14:05:49 +08:00
Joel
ff02e1cb8f chore: enchance test output struct 2024-12-25 14:04:46 +08:00
Yi
d78719a6f8 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-12-25 13:41:06 +08:00
JzoNg
da6d65b072 fix style of account setting 2024-12-25 12:35:27 +08:00
JzoNg
8d1a8eac51 add use-strategy 2024-12-25 11:55:59 +08:00
Joel
e34fe3d10a feat: support iteration handle 2024-12-25 11:47:31 +08:00
Yi
8d79b24883 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-12-25 11:43:00 +08:00
AkaraChen
03520a5a81 feat: strategy form init 2024-12-25 11:24:24 +08:00
Yeuoly
6ee7ca1890 fix: add specific exceptions 2024-12-24 22:00:45 +08:00
Yeuoly
f589397f25 fix: import Optional 2024-12-24 21:56:55 +08:00
Yeuoly
ee080dddf9 fix: rebase 2024-12-24 21:48:49 +08:00
Yeuoly
ee6841648c fix: migrations and imports recycle 2024-12-24 21:36:42 +08:00
Yeuoly
5a57dad93c fix: linter 2024-12-24 21:29:24 +08:00
Yeuoly
4199998c7e Merge branch 'main' into fix/chore-fix 2024-12-24 21:28:56 +08:00
Yeuoly
527abcb2e9 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-24 18:39:42 +08:00
Yeuoly
39656f7f84 fix: linter and formatter 2024-12-24 18:38:34 +08:00
Yeuoly
bf39e314d8 fix: add install count 2024-12-24 18:38:12 +08:00
Yi
d43b2c62f5 Merge branch 'main' into feat/plugins 2024-12-24 17:44:12 +08:00
JzoNg
07d7965e3b support custom output schema in tool node 2024-12-24 16:26:09 +08:00
Joel
e4d72f3442 chore: hide log 2024-12-24 16:10:37 +08:00
Joel
c93c264c5a feat: format to tracing 2024-12-24 16:08:48 +08:00
AkaraChen
77017522b8 chore: init tool select component 2024-12-24 16:01:14 +08:00
AkaraChen
aa309964e5 chore: init tool select component 2024-12-24 15:55:45 +08:00
zxhlyh
754baf8d02 refact workflow run 2024-12-24 15:38:54 +08:00
zxhlyh
b98dd22491 refact workflow run 2024-12-24 15:31:46 +08:00
AkaraChen
7c460eb6e7 chore: add warning ui for agentic stragey 2024-12-24 14:20:15 +08:00
JzoNg
e2e2090e0c support model params change 2024-12-24 14:15:18 +08:00
JzoNg
c8fc1deca6 support & operator of model-selector scope 2024-12-24 12:18:03 +08:00
Yi
6dd14ca2be chore: add agent strategy option apart from bundle 2024-12-24 12:05:35 +08:00
zxhlyh
ec6f4ee9df Merge branch 'main' into feat/plugins 2024-12-24 11:35:47 +08:00
JzoNg
9d117fa2f9 param rules panel 2024-12-24 11:00:31 +08:00
Joel
e8319f01e0 fix: crash 2024-12-24 10:33:56 +08:00
Joel
c3f3b79b79 merge main 2024-12-23 15:33:08 +08:00
JzoNg
c91c5faa9d Merge branch 'feat/plugins' into dev/plugin-deploy 2024-12-20 16:44:23 +08:00
JzoNg
327eac09e7 fix: scope value 2024-12-20 16:37:30 +08:00
JzoNg
cf75e2f053 model selector support scope 2024-12-20 16:36:22 +08:00
JzoNg
12c47d80af support llm tool_parameters 2024-12-20 12:46:07 +08:00
JzoNg
5c6916354e app selector support scope 2024-12-20 11:59:18 +08:00
JzoNg
6d2b2d7810 fix number of tool actions 2024-12-20 11:27:52 +08:00
JzoNg
1fa5b1755f dark mode for model provider 2024-12-20 10:44:39 +08:00
twwu
5dad4793e6 fix: Fix context selector usage in plugin page components 2024-12-20 09:56:06 +08:00
Yeuoly
82f6803e25 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-19 01:09:34 +08:00
Yeuoly
8cc4c109d0 fix: return types of builtin tools 2024-12-19 01:09:15 +08:00
Yeuoly
69b43c513a Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-19 01:02:56 +08:00
Yeuoly
a1cdca02e3 fix: formatter 2024-12-19 01:02:44 +08:00
Yeuoly
1b21d7513d fix: reduce model provider fetchs 2024-12-19 01:02:08 +08:00
Yeuoly
f407cf4e13 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-19 00:52:02 +08:00
takatost
d5c708c62b feat: add plugin_model_providers context 2024-12-19 00:50:46 +08:00
Yeuoly
f8bbea224f Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-18 23:55:18 +08:00
Yeuoly
342d4060ff fix: add additional parameters to exists tools 2024-12-18 23:54:48 +08:00
Joel
289a040508 chore: merge 2024-12-18 17:54:18 +08:00
Joel
d49e9890ba fix: file name text overflow not work 2024-12-18 16:49:11 +08:00
NFish
fa3f8c5bb0 merge origin/feat/parent-child-retrival 2024-12-18 16:44:51 +08:00
Joel
eead099c5e fix: not get extensions can select all types files 2024-12-18 16:38:16 +08:00
twwu
7185fd2d5a Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-12-18 15:03:12 +08:00
twwu
8d9a2d6d99 fix: Enhance components with display names and ref forwarding; fix preview and edit slice style issue 2024-12-18 14:47:33 +08:00
Joel
ade6dd4b6f fix: delimiter not support empty and not escape 2024-12-18 14:25:56 +08:00
Joel
0006852b5b fix: parent child has no overlap 2024-12-18 14:13:59 +08:00
Joel
6ea333fb44 fix: child sparator not escape 2024-12-18 14:10:18 +08:00
Joel
c22c010210 fix: empty no text 2024-12-18 13:57:29 +08:00
NFish
4e6db1f4fb fix: update parent child style 2024-12-18 11:46:41 +08:00
NFish
330cfaf6d6 Merge branch 'feat/parent-child-retrieval' of github.com:langgenius/dify into feat/parent-child-retrieval 2024-12-17 18:20:00 +08:00
NFish
827cffc4d9 fix: update dataset document processing style 2024-12-17 18:17:23 +08:00
Joel
8ee7e0a787 fix: text size 2024-12-17 18:10:44 +08:00
Joel
de6b0670a3 chore: detail ui 2024-12-17 17:53:25 +08:00
Joel
39452274f8 chore: fix chunk detail spacing 2024-12-17 17:46:43 +08:00
Joel
4ef876db23 chore: use qa language 2024-12-17 17:35:50 +08:00
twwu
a1abbedc13 Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-12-17 16:42:17 +08:00
twwu
a099e0a7e6 fix: Adjust layout and prevent default behavior in action buttons 2024-12-17 16:42:11 +08:00
Yeuoly
810ac6e1b2 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-17 15:50:13 +08:00
Yeuoly
05232d36f0 fix: add default values to WorkflowAppGenerator 2024-12-17 15:49:33 +08:00
Joel
1613eadbce chore: not free plan show auto disabled 2024-12-17 15:32:14 +08:00
twwu
f2c087b805 fix: Fix FullScreenDrawer background color missing 2024-12-17 15:20:32 +08:00
twwu
5ba51fd7d2 Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-12-17 14:29:41 +08:00
twwu
f7c38db575 feat: enhance child segment list and segment card UI with improved styling and new props for EditSlice 2024-12-17 14:29:35 +08:00
Joel
4df52e7f95 fix: retriveal text left ui 2024-12-17 14:29:12 +08:00
AkaraChen
175f5fe6af fix: input number width & default value for child delimiter 2024-12-17 14:12:34 +08:00
NFish
1e2ca1aa7b revert: checkbox style 2024-12-17 10:57:45 +08:00
NFish
642aab38fd Merge branch 'feat/parent-child-retrieval' of github.com:langgenius/dify into feat/parent-child-retrieval 2024-12-17 10:46:45 +08:00
NFish
84641b6fd6 Merge branch 'main' into feat/parent-child-retrieval 2024-12-17 10:46:17 +08:00
twwu
9006a744b9 feat: enhance segment management by adding new segment mutation and improving UI layout 2024-12-17 10:13:53 +08:00
NFish
493ec06e95 Merge branch 'feat/parent-child-retrieval' of github.com:langgenius/dify into feat/parent-child-retrieval 2024-12-17 09:45:24 +08:00
Yeuoly
040a6fbc5f fix: refresh token 2024-12-16 19:41:50 +08:00
Joel
7a82422187 chore: record ui 2024-12-16 18:33:07 +08:00
Joel
29c41bf8e8 fix: retrieval ui 2024-12-16 18:30:11 +08:00
twwu
777bba0c63 Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-12-16 18:15:59 +08:00
twwu
4850a99ce5 feat: refactor docForm type to use ChuckingMode and improve UI for question/answer sections 2024-12-16 18:15:54 +08:00
zxhlyh
9f90d70b38 merge feat/plugins 2024-12-16 18:06:06 +08:00
Joel
e418cf30f5 chore: hiting test header ui 2024-12-16 18:05:02 +08:00
nite-knite
6da7efaa1d feat: update dataset embedding error message display 2024-12-16 18:04:20 +08:00
zxhlyh
04054954c5 Merge branch 'main' into feat/plugins 2024-12-16 17:55:52 +08:00
NFish
a01a28997e fix: update datasource Step1 style 2024-12-16 17:54:48 +08:00
zxhlyh
672843dcab feat: marketplace list more link 2024-12-16 17:39:07 +08:00
nite-knite
e206866908 feat: update UI for dataset creation step three 2024-12-16 17:16:03 +08:00
twwu
14f14420e7 Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-12-16 17:10:38 +08:00
twwu
faa5b63ed4 feat: update background styles and add loading skeletons for document detail components 2024-12-16 17:10:33 +08:00
Joel
782845f1a7 fix: header text 2024-12-16 16:51:12 +08:00
JzoNg
4f8cdabef0 dark mode of model provider 2024-12-16 16:29:45 +08:00
Joel
d5a90daa44 chore: retrieval test text 2024-12-16 15:56:16 +08:00
Joel
3f9acc7029 feat: hit testing support external 2024-12-16 15:51:47 +08:00
zxhlyh
e792e91777 fix: model page 2024-12-16 14:56:55 +08:00
Yeuoly
fd02c60498 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-16 14:29:05 +08:00
JzoNg
d5cb9f0193 add help doc link of endpoint 2024-12-16 14:20:22 +08:00
Yeuoly
636dde94c7 fix: migrations 2024-12-16 14:17:39 +08:00
Yeuoly
75fe785d88 Merge branch 'main' into fix/chore-fix 2024-12-16 14:08:18 +08:00
Yeuoly
a61da6cf95 fix: replace Enum with StrEnum 2024-12-16 13:40:02 +08:00
twwu
340a052d44 fix: update dependencies array in useMemo hooks 2024-12-16 12:49:06 +08:00
twwu
d5cb3af293 feat: add horizontal divider above pagination in completed documents view 2024-12-16 12:15:01 +08:00
twwu
fb4d980096 feat: add loading state to child segment list component 2024-12-16 11:46:08 +08:00
twwu
cfde86252c Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-12-16 11:20:50 +08:00
twwu
cea24acb0a feat: enhance child segment list with empty state handling and search result display 2024-12-16 11:20:37 +08:00
JzoNg
171cc88a0d merge main 2024-12-16 11:09:13 +08:00
Joel
487809cecd fix: checkox mix merge error 2024-12-16 11:04:39 +08:00
非法操作
66d7d7a9bc fix: change http node params from dict to list tuple (#11665) 2024-12-16 11:04:38 +08:00
非法操作
ae45575226 feat: add grok-2-1212 and grok-2-vision-1212 (#11672) 2024-12-16 11:04:38 +08:00
Novice
782a24b04d fix: remove the unused QueueWorkflowPartialSuccessEvent handle in workflow (#11669)
Co-authored-by: Novice Lee <novicelee@NoviPro.local>
2024-12-16 11:04:38 +08:00
github-actions[bot]
b96686c1f9 chore: translate i18n files (#11639)
Co-authored-by: douxc <7553076+douxc@users.noreply.github.com>
2024-12-16 11:04:38 +08:00
luckylhb90
c1cf5f8d15 feat: log add trace id (#11599)
Co-authored-by: hobo.l <hobo.l@binance.com>
2024-12-16 11:04:38 +08:00
yihong
975743925e fix: _handle_workflow_run_partial_success args is wrong (#11562)
Signed-off-by: yihong0618 <zouzou0208@gmail.com>
2024-12-16 11:04:38 +08:00
yihong
d8fb14d5df fix: ExternalDatasetService.process_external_api wrong args (#11586)
Signed-off-by: yihong0618 <zouzou0208@gmail.com>
2024-12-16 11:04:38 +08:00
yihong
b8aa9a0162 fix: account.id should account_id (#11628)
Signed-off-by: yihong0618 <zouzou0208@gmail.com>
2024-12-16 11:04:38 +08:00
Bowen Liang
108c1ec929 test: run vdb tests on TiDB Vector with docker in CI tests (#11645) 2024-12-16 11:04:38 +08:00
yihong
5e3edd2b1c fix: better error message for stream (#11635)
Signed-off-by: yihong0618 <zouzou0208@gmail.com>
2024-12-16 11:04:38 +08:00
IWAI, Masaharu
0dfa34ebff Update translate to Japanese: natural Japanese expression (#11647)
Co-authored-by: IWAI, Masaharu <iwai_masaharu@funkit.co.jp>
2024-12-16 11:04:38 +08:00
yihong
294be849d5 fix: langfuse do not have created_at args and fix the typing in the file (#11648)
Signed-off-by: yihong0618 <zouzou0208@gmail.com>
2024-12-16 11:04:38 +08:00
IWAI, Masaharu
aff330945d fix: rename README filename: Japanese language code is 'JA' (#11651) 2024-12-16 11:04:38 +08:00
Junyan Qin
1ebf66718e fix: remove unnecessary curly braces in wf api doc (#11658) 2024-12-16 11:04:38 +08:00
yihong
36aebac6af fix: filter bug for keywork cause code can not reach (#11666)
Signed-off-by: yihong0618 <zouzou0208@gmail.com>
2024-12-16 11:04:38 +08:00
NFish
e9e78487b5 Feat: new entry point for app creation (#10847) 2024-12-16 11:04:32 +08:00
Kevin9703
bc82de83b7 fix: app log filter value error (#11624) 2024-12-16 11:02:47 +08:00
yihong
09184afba0 fix: split dir for opendal tests (#11627)
Signed-off-by: yihong0618 <zouzou0208@gmail.com>
2024-12-16 11:02:47 +08:00
-LAN-
674dd13fbd chore(dependency): bump gunicorn to 23.0 (#11560)
Signed-off-by: -LAN- <laipz8200@outlook.com>
2024-12-16 11:02:47 +08:00
zxhlyh
a594fd87b8 Fix/pdf preview in build (#11621) 2024-12-16 11:02:47 +08:00
Hiroshi Fujita
df1f5f7851 feat(devcontainer): add alias to stop Docker containers (#11616) 2024-12-16 11:02:47 +08:00
yihong
96bb49aded ci: better print version for ruff to check the change (#11587)
Signed-off-by: yihong0618 <zouzou0208@gmail.com>
2024-12-16 11:02:47 +08:00
JasonVV
6d1264af4e feat(model): add vertex_ai Gemini 2.0 Flash Exp (#11604) 2024-12-16 11:02:47 +08:00
crazywoola
cfd964880a fix: name of llama-3.3-70b-specdec (#11596) 2024-12-16 11:02:47 +08:00
Alok Shrivastwa
84d966d0d8 Added new models and Removed the deleted ones for Groq #11455 (#11456)
Co-authored-by: crazywoola <427733928@qq.com>
Co-authored-by: Alok Shrivastwa <Alok.Shrivastwa@microland.com>
2024-12-16 11:02:47 +08:00
Warren Chen
a926cd436f [ref] use one method to get boto client for aws bedrock (#11506) 2024-12-16 11:02:47 +08:00
github-actions[bot]
76338175e8 chore: translate i18n files (#11577)
Co-authored-by: JzoNgKVO <27049666+JzoNgKVO@users.noreply.github.com>
2024-12-16 11:02:47 +08:00
yihong
561453b63f fix: support mdx files close #11557 (#11565)
Signed-off-by: yihong0618 <zouzou0208@gmail.com>
2024-12-16 11:02:47 +08:00
Joe
39c678308b fix: change workflow trace id (#11585) 2024-12-16 11:02:47 +08:00
KVOJJJin
076bd1cf8d Feat: dark mode for logs and annotations (#11575) 2024-12-16 11:02:45 +08:00
Jiang
880094cc7b Lindorm vdb (#11574)
Co-authored-by: jiangzhijie <jiangzhijie.jzj@alibaba-inc.com>
2024-12-16 11:00:37 +08:00
非法操作
3e6ff18e1b feat: add gemini-2.0-flash-exp (#11570) 2024-12-16 11:00:37 +08:00
yihong
9a55bd119e fix: better opendal tests (#11569)
Signed-off-by: yihong0618 <zouzou0208@gmail.com>
2024-12-16 11:00:37 +08:00
liuzhenghua
ec1efe5d54 Fix: RateLimit requests were not released when a streaming generation exception occurred (#11540) 2024-12-16 11:00:37 +08:00
github-actions[bot]
708c1a19a1 chore: translate i18n files (#11545)
Co-authored-by: zxhlyh <16177003+zxhlyh@users.noreply.github.com>
2024-12-16 11:00:37 +08:00
zxhlyh
974b88d63a fix: workflow continue on error doc link (#11554) 2024-12-16 11:00:37 +08:00
-LAN-
4762d9b02d feat: integrate opendal storage (#11508)
Signed-off-by: -LAN- <laipz8200@outlook.com>
2024-12-16 11:00:37 +08:00
Novice
72b1bed79d fix: iteration node in parallel mode token count error (#11539)
Co-authored-by: Novice Lee <novicelee@NoviPro.local>
2024-12-16 11:00:37 +08:00
Novice
14912b2a1d Feat: continue on error (#11458)
Co-authored-by: Novice Lee <novicelee@NovicedeMacBook-Pro.local>
Co-authored-by: Novice Lee <novicelee@NoviPro.local>
2024-12-16 11:00:37 +08:00
zxhlyh
d1d76823d1 feat: workflow continue on error (#11474) 2024-12-16 11:00:37 +08:00
Yi Xiao
3b57b8c91f chore: update thai lang in app page (#11541) 2024-12-16 11:00:37 +08:00
Tommy
1a1d35607c [Pixtral] Add new model ; add vision (#11231) 2024-12-16 11:00:37 +08:00
zkyTech
c82271af75 fix: Remove duplicate 'response_format' parameter from model YAML files (#11531)
Co-authored-by: zhangkunyuan <zhangkunyuan@cmhi.chinamobile.com>
2024-12-16 11:00:37 +08:00
Paul van Oorschot
0b7b12b003 feat: Add llama-3.3 models for Groq (#11533) 2024-12-16 11:00:37 +08:00
yihong
cbb21149e6 fix: better error message for url add external knowledge (#11537)
Signed-off-by: yihong0618 <zouzou0208@gmail.com>
2024-12-16 11:00:37 +08:00
yihong
88df17694f Revert "fix: total tokens is wrong which is zero in inter way, close … (#11536) 2024-12-16 11:00:37 +08:00
yihong
602bd801c3 fix: can not start local by REMOTE_SETTINGS_SOURCE_NAME change it to … (#11535)
Signed-off-by: yihong0618 <zouzou0208@gmail.com>
2024-12-16 11:00:37 +08:00
yihong
a571914ffc fix: issue 11247 that Completion mode content maybe list or str (#11504)
Signed-off-by: yihong0618 <zouzou0208@gmail.com>
2024-12-16 11:00:37 +08:00
Wei Mingzhi
e2a3c2e9da Remove the processing of single quote when testing API tools. (#11390) 2024-12-16 11:00:37 +08:00
非法操作
b76cee7ad8 chore: LOCAL_FILE also try to use remote_url as Prompt message (#11443) 2024-12-16 11:00:37 +08:00
Charlie.Wei
e8f46bffde Msg file preview (#11466)
Co-authored-by: crazywoola <427733928@qq.com>
Co-authored-by: crazywoola <100913391+crazywoola@users.noreply.github.com>
2024-12-16 11:00:37 +08:00
barabicu
e299232a19 chore: fix typo in Japanese localization (#11502) 2024-12-16 11:00:37 +08:00
문정현
08a4d6d67f chore : fix translation Typo in ko-KR localization (#11509) 2024-12-16 11:00:37 +08:00
-LAN-
0deb19e800 fix(app_generator_service): overload type hints (#11507)
Signed-off-by: -LAN- <laipz8200@outlook.com>
2024-12-16 11:00:37 +08:00
orangeclk
5190cac072 feat: add siliconflow qwq and llama3.3 model (#11492) 2024-12-16 11:00:37 +08:00
huanshare
60470414fa feat:add apollo configuration to load env file (#11210)
Signed-off-by: -LAN- <laipz8200@outlook.com>
Co-authored-by: huanshare <liuhuan101@longfor.com>
Co-authored-by: -LAN- <laipz8200@outlook.com>
2024-12-16 11:00:37 +08:00
Yingchun Lai
062a57589b fix: add the missing abab6.5t-chat model of Minimax (#11484) 2024-12-16 11:00:37 +08:00
-LAN-
7f5bda81e5 chore: bump version to 0.13.2 (#11489)
Signed-off-by: -LAN- <laipz8200@outlook.com>
2024-12-16 11:00:37 +08:00
Hash Brown
61fd1947ff fix: cannot close notification manually (#11490) 2024-12-16 11:00:35 +08:00
Jyong
19e13d89bc improve message clean logic (#11487) 2024-12-16 10:59:56 +08:00
-LAN-
186e39fd2f refactor(iteration_node): use Sequence and Mapping in parameters (#11483)
Signed-off-by: -LAN- <laipz8200@outlook.com>
2024-12-16 10:59:56 +08:00
suzuki.sh
eabf59f00d Fix the token count at the iteration node (#11235)
Co-authored-by: -LAN- <laipz8200@outlook.com>
2024-12-16 10:59:56 +08:00
zhaobingshuang
83a5dcffac fix: tags could not be saved when the Workflow Tool was created (#11481)
Co-authored-by: zhaobs <zhaobs@cailian.net>
2024-12-16 10:59:56 +08:00
kurokobo
e11a876f79 feat: add 'Open in Explore' link for each apps on studio (#11402) 2024-12-16 10:59:56 +08:00
Muneyuki Noguchi
dcac973adc Fix the Japanese translation for 'Detail' (#11476) 2024-12-16 10:59:56 +08:00
Yi Xiao
45bdeb79f8 feat: ifelse condition variable editable after selection (#11431) 2024-12-16 10:59:56 +08:00
Charlie.Wei
af9060e238 Refactor: Remove redundant style and simplify Mermaid component (#11472) 2024-12-16 10:59:56 +08:00
xiandan-erizo
160c229304 Update ext_redis.py (#11214) 2024-12-16 10:59:56 +08:00
VoidIsVoid
3652d71ac6 remove mermail render cache (#11470)
Co-authored-by: Gimling <huangjl@ruyi.ai>
2024-12-16 10:59:56 +08:00
Trey Dong
3eac339dd3 fix(api): throw error when notion block can not find (#11433) 2024-12-16 10:59:56 +08:00
yihong
4208e35e54 fix: unit tests env will need clear too (#11445)
Signed-off-by: yihong0618 <zouzou0208@gmail.com>
2024-12-16 10:59:56 +08:00
Kazuki Takamatsu
9dccb51fd0 Fix model provider of vertex ai (#11437) 2024-12-16 10:59:56 +08:00
Hash Brown
65262b3ab7 fix: cannot upload animated webp image as app icon (#11453) 2024-12-16 10:59:56 +08:00
非法操作
8ed235fa0b feat: support json_schema for ollama models (#11449) 2024-12-16 10:59:56 +08:00
非法操作
7bbb745e33 feat: add gemini exp 1206 (#11444) 2024-12-16 10:59:56 +08:00
非法操作
994b7a6603 feat: add zhipu glm_4v_flash (#11440) 2024-12-16 10:59:56 +08:00
Hash Brown
26dee2e885 style: EmojiPicker component top padding (#11452) 2024-12-16 10:59:56 +08:00
yihong
24d43dceb4 fix: issue #10596 by making the iteration node outputs right (#11394)
Signed-off-by: yihong0618 <zouzou0208@gmail.com>
Signed-off-by: -LAN- <laipz8200@outlook.com>
Co-authored-by: -LAN- <laipz8200@outlook.com>
2024-12-16 10:59:56 +08:00
Huỳnh Gia Bôi
be9f58d065 fix(document_extractor): pptx file type and missing metadata_filename UnstructuredIO (#11364)
Co-authored-by: Julian Huynh <julian.huynh@immersio.io>
2024-12-16 10:59:56 +08:00
KVOJJJin
ffd1343a09 Fix: compatible with outputs data structure (#11432) 2024-12-16 10:59:56 +08:00
Jyong
898ea9bf0f update tidb batch get endpoint to basic mode (#11426) 2024-12-16 10:59:55 +08:00
Jyong
269698d8ce fix external retrieval without segment id (#11423) 2024-12-16 10:59:55 +08:00
shirochan
1e5a9acc74 FEAT: cohere rerank 3.5 model added (#11289) 2024-12-16 10:59:55 +08:00
Matsuda
8fd0eaf5b7 fix(model_runtime): add vision to Amazon Nova Lite and Pro (#11398) 2024-12-16 10:59:55 +08:00
crazywoola
e98e3e1f17 use md table systax in pr template (#11412) 2024-12-16 10:59:55 +08:00
kurokobo
083af2a044 fix: add elkjs (#11404) 2024-12-16 10:59:55 +08:00
huayaoyue6
8ae566e8fc fix: update DocumentIsPausedError (#11405) 2024-12-16 10:59:55 +08:00
Charlie.Wei
e562cdc72e Update mermaid (#11356)
Co-authored-by: luowei <glpat-EjySCyNjWiLqAED-YmwM>
Co-authored-by: crazywoola <427733928@qq.com>
Co-authored-by: crazywoola <100913391+crazywoola@users.noreply.github.com>
2024-12-16 10:59:55 +08:00
github-actions[bot]
e81d830a56 chore: translate i18n files (#11389)
Co-authored-by: JzoNgKVO <27049666+JzoNgKVO@users.noreply.github.com>
2024-12-16 10:59:55 +08:00
KVOJJJin
b68de4fa6d Fix: support file download in workflow result (#11338) 2024-12-16 10:59:15 +08:00
-LAN-
8eb888f7d6 chore: bump version to 0.13.1 (#11382)
Signed-off-by: -LAN- <laipz8200@outlook.com>
2024-12-16 10:59:15 +08:00
Warren Chen
c99b822ca5 [fix] rename yaml files to fit windows (#11379) 2024-12-16 10:59:15 +08:00
Yi Xiao
ed234e82d0 fix: empty object (conversation variable) editable (#11352) 2024-12-16 10:59:15 +08:00
yihong
824877dd5f fix: some typos using typos (#11374)
Signed-off-by: yihong0618 <zouzou0208@gmail.com>
2024-12-16 10:59:15 +08:00
Yi Xiao
a62892ccdb fix: bg typo in variable aggregator node (#11376) 2024-12-16 10:59:15 +08:00
Warren Chen
0bae1c6cb6 [feat] Add AWS Bedrock rerank (#11349)
Co-authored-by: crazywoola <427733928@qq.com>
2024-12-16 10:59:15 +08:00
twwu
6a02076c54 Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-12-16 10:55:19 +08:00
twwu
022fa663c5 fix: improve memoization for document detail processing modes 2024-12-16 10:55:13 +08:00
Joel
ab7df47768 fix: handle show child trunck 2024-12-16 10:26:52 +08:00
Yeuoly
fa03ba23bb Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-15 18:12:43 +08:00
Yeuoly
93c3699128 feat: add label to agent log 2024-12-15 18:12:29 +08:00
Yeuoly
a48608dd9b Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-13 22:53:20 +08:00
Yeuoly
6357450a7a feat: support hidden parameters 2024-12-13 22:53:08 +08:00
Yeuoly
ecb5e85ca4 fix: unbound variable 2024-12-13 20:21:47 +08:00
Yeuoly
92e02c1d0c fix: avoid sending email to unauth users 2024-12-13 20:21:02 +08:00
Yeuoly
2e2d1659ca feat: support whitelist 2024-12-13 20:09:05 +08:00
Yeuoly
3dd6d96b5a Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-13 19:51:28 +08:00
Yeuoly
6339706c68 fix: ruff reformatter 2024-12-13 19:51:09 +08:00
Yeuoly
65a4cb769b refactor: tool entities 2024-12-13 19:50:54 +08:00
twwu
8f56c6a7fa Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-12-13 17:39:44 +08:00
twwu
f1782664b6 feat: add empty state handling and translations for segment list 2024-12-13 17:38:26 +08:00
AkaraChen
031c2ad899 chore: update pnpm lock 2024-12-13 17:27:04 +08:00
AkaraChen
fe2d60dfc9 fix: option card gradient & tailwind config 2024-12-13 15:47:29 +08:00
nite-knite
7d673e7f14 feat: dataset creation UI tinkering 2024-12-13 15:28:17 +08:00
AkaraChen
8f178290be fix: preview document picker label overflow 2024-12-13 15:20:37 +08:00
AkaraChen
f304976715 fix: create dataset step one next 2024-12-13 15:13:06 +08:00
AkaraChen
b2322aca27 Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-12-13 14:57:18 +08:00
AkaraChen
6dc20ee809 fix: unique key 2024-12-13 14:57:13 +08:00
twwu
f7d6dbe90b fix: adjust layout and styling in child segment list component 2024-12-13 14:54:33 +08:00
twwu
44929133a4 Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-12-13 14:45:39 +08:00
twwu
a4c66e3659 feat: improve translation handling in segment components 2024-12-13 14:45:31 +08:00
AkaraChen
ab76266993 chore: enable type intelligence for tailwind config 2024-12-13 14:43:52 +08:00
AkaraChen
b0f34975d4 Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-12-13 14:42:13 +08:00
AkaraChen
24975d475a fix: step 2 switch to economy 2024-12-13 14:41:57 +08:00
nite-knite
8de12ef1d7 feat: update dataset creation UI 2024-12-13 14:41:19 +08:00
JzoNg
463f5a34c6 dark mode for plugins 2024-12-13 14:06:07 +08:00
AkaraChen
2fb71dce50 feat: create datasets step two dark mode 2024-12-13 13:11:37 +08:00
JzoNg
5c98f1a5aa dark mode for tools 2024-12-13 13:10:29 +08:00
twwu
766f697f83 feat: navigate to document detail on selection in DocumentPicker 2024-12-13 10:30:48 +08:00
twwu
1641638523 refactor: reorganize BatchAction import paths and enhance child segment scrolling behavior 2024-12-13 10:12:43 +08:00
Yeuoly
11c4bf5574 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-13 00:06:09 +08:00
Yeuoly
63206a7967 fix: incorrect use of node execution id 2024-12-13 00:05:57 +08:00
Yeuoly
4cbaa6b77d Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-12 23:46:58 +08:00
Yeuoly
9a6f120e5c feat: support agent log event 2024-12-12 23:46:26 +08:00
Yeuoly
d01f0278f4 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-12 19:16:31 +08:00
Yeuoly
dedc1b0c3a refactor: agent strategy parameter 2024-12-12 19:16:06 +08:00
Yeuoly
8278c8a27e Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-12 18:27:58 +08:00
Yeuoly
46bb246ecc refactor: rename agent to agent strategy 2024-12-12 18:27:43 +08:00
Yeuoly
3c628d0c26 refactor: rename agent to agent strategy 2024-12-12 18:27:31 +08:00
zxhlyh
7727ec822a Merge branch 'feat/plugins' into dev/plugin-deploy 2024-12-12 17:29:55 +08:00
zxhlyh
a0e999e438 feat: plugin add agent-strategy type 2024-12-12 17:29:25 +08:00
twwu
a8254c29c5 Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-12-12 17:14:44 +08:00
twwu
3dbd8f5d31 feat: enhance child segment list with total count and input value handling 2024-12-12 17:14:33 +08:00
AkaraChen
939f7f3e06 fix: cannot open in upload 2024-12-12 16:56:06 +08:00
AkaraChen
489015bd9e fix: update document name display to prevent overflow 2024-12-12 16:50:15 +08:00
AkaraChen
1b150d31a9 Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-12-12 16:42:34 +08:00
AkaraChen
3fa33b09af fix: add truncation to document name display and update dataset form checks 2024-12-12 16:42:23 +08:00
twwu
5a1159f9ab feat: update child chunk handling and improve UI interactions 2024-12-12 15:33:54 +08:00
JzoNg
4aef5939f1 Merge branch 'feat/plugins' into dev/plugin-deploy 2024-12-12 15:14:59 +08:00
JzoNg
e0cc990fa5 fix: tool parameter form change 2024-12-12 15:12:41 +08:00
twwu
c1d1960215 feat: enhance time formatting and add child segment detail component 2024-12-12 14:45:00 +08:00
Yeuoly
85caf51ad1 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-12 13:51:00 +08:00
Yeuoly
c2983ecbb7 fix: rename stream to streaming 2024-12-12 13:50:34 +08:00
twwu
fd339d51e2 Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-12-12 13:39:50 +08:00
twwu
36778a4ebe feat: add and delete child chunks 2024-12-12 13:39:45 +08:00
AkaraChen
3f1b92a23f fix: data source web & notion 2024-12-12 13:37:36 +08:00
AkaraChen
ac24163fb9 chore: change some color for dark mode 2024-12-12 13:13:08 +08:00
twwu
a25a3ee1f7 Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-12-11 18:38:05 +08:00
twwu
28987003fa refactor: simplify SegmentIndexTag usage and improve label prefix handling 2024-12-11 18:37:56 +08:00
Joel
f2eeaba8d7 chore: remove useless test code 2024-12-11 18:23:52 +08:00
twwu
db01c5c89d Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-12-11 18:18:06 +08:00
twwu
51f6a87aef feat: update translation files and improve segment index tag component 2024-12-11 18:15:30 +08:00
Joel
d88bb70427 fix: loding and empty css 2024-12-11 18:13:56 +08:00
AkaraChen
4f6bc54280 fix: update file type casting in PreviewDocumentPicker 2024-12-11 18:05:05 +08:00
Joel
49a48910cd chore: hit result toggle btn 2024-12-11 18:02:16 +08:00
AkaraChen
3f6aee6c51 feat: economy hover effect & upload page 2024-12-11 18:01:02 +08:00
Joel
f22c608c89 fix: tiny css problem 2024-12-11 17:48:22 +08:00
AkaraChen
41039f09bf fix: switch to parent child not use qualified 2024-12-11 16:55:11 +08:00
AkaraChen
6d689317ea Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-12-11 16:50:43 +08:00
AkaraChen
f969dce345 feat: switch to high quan modal 2024-12-11 16:50:32 +08:00
Joel
599345879e feat: result ui 2024-12-11 16:34:52 +08:00
AkaraChen
9dce37bb24 Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-12-11 15:45:14 +08:00
AkaraChen
149cfaafc5 feat: add switch to high quan dialog 2024-12-11 15:45:05 +08:00
Joel
17ae100342 chore: result main 2024-12-11 15:15:04 +08:00
Joel
361a007f42 feat: tags 2024-12-11 14:42:14 +08:00
Joel
b8ced5102c feat: new retrieval result ui 2024-12-11 14:30:01 +08:00
zxhlyh
5b3112a137 fix: model page empty 2024-12-11 14:10:28 +08:00
twwu
4017c65c1f Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-12-11 14:00:27 +08:00
twwu
8518c1ae8c feat: add regeneration confirmation and success messages in translation files 2024-12-11 14:00:21 +08:00
twwu
033ce47d01 feat: add Dot and Tag components for enhanced UI representation 2024-12-11 13:31:21 +08:00
AkaraChen
70d1d03106 fix: not use css var 2024-12-11 11:06:20 +08:00
AkaraChen
11ee45f1c2 fix: default value not match prd 2024-12-11 11:03:03 +08:00
Joel
16d8bdfc78 chore: hit result item temp 2024-12-10 18:36:45 +08:00
Joel
14c8297e36 chore: fix setting text 2024-12-10 18:36:45 +08:00
twwu
8baaf7c84e Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-12-10 18:01:43 +08:00
twwu
b4a6ec077f feat: add functionality to regenerate child chunks and enhance UI components for segment management 2024-12-10 18:01:38 +08:00
AkaraChen
27f5738c55 Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-12-10 17:32:43 +08:00
AkaraChen
5fa0fc4858 fix: dataset settings 2024-12-10 17:32:31 +08:00
Joel
87e284ef75 feat: no linked app ui 2024-12-10 17:19:05 +08:00
Joel
dd23f1093b feat: linked app new ui 2024-12-10 16:13:12 +08:00
Joel
77185d9617 feat: dataset info to new ui 2024-12-10 16:13:12 +08:00
AkaraChen
f894fb05c1 fix: retrive config cannot enable rerank 2024-12-10 16:04:42 +08:00
zxhlyh
1272cf8fe7 Merge branch 'feat/plugins' into dev/plugin-deploy 2024-12-10 15:52:16 +08:00
zxhlyh
35fb9099e3 fix: model page 2024-12-10 15:51:55 +08:00
zxhlyh
3803989480 Merge branch 'feat/plugins' into dev/plugin-deploy 2024-12-10 14:58:38 +08:00
twwu
6055e27050 Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-12-10 14:16:49 +08:00
twwu
09cdb573c7 feat: enhance NewSegmentModal with add another option and improve cancel behavior 2024-12-10 14:16:43 +08:00
Joel
430de3108b chore: remove isloading break ui 2024-12-10 14:15:14 +08:00
Joel
d1743ee3e5 feat: auto disabled api 2024-12-10 14:12:03 +08:00
Joel
335e57f3c9 feat: auto disable document ui 2024-12-10 14:12:03 +08:00
zxhlyh
c51c032334 fix: dsl check 2024-12-10 14:11:34 +08:00
zxhlyh
5825c101c9 fix: marketplace exclude 2024-12-10 13:37:02 +08:00
twwu
ae3eae413f feat: add LayoutRight2LineMod icon component and update document detail 2024-12-10 13:12:05 +08:00
twwu
89345e5c5a Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-12-10 11:32:02 +08:00
twwu
65a9cac099 feat: add new translations and enhance segment management features 2024-12-10 11:31:56 +08:00
Yeuoly
80b3de5c4f Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-10 02:21:56 +08:00
Yeuoly
527c1cf608 fix: deduplicate provider id 2024-12-10 02:21:46 +08:00
Yeuoly
6868ee5431 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-10 00:23:08 +08:00
Yeuoly
93786f516c apply ruff 2024-12-10 00:22:54 +08:00
Yeuoly
a175d6b2d7 feat: agent management 2024-12-10 00:22:41 +08:00
Yeuoly
054b59c702 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-09 23:26:38 +08:00
Yeuoly
296fd82bbf fix: agent node 2024-12-09 23:26:16 +08:00
Yeuoly
ff81d12426 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-09 23:02:50 +08:00
Yeuoly
4ccd571364 fix: ruff 2024-12-09 23:02:25 +08:00
Yeuoly
ae72514cb4 feat: support agent node 2024-12-09 23:02:11 +08:00
Joel
4c1bf96b14 fix: node build out of memory 2024-12-09 18:26:09 +08:00
Joel
54f03c5c78 fix: node build out of memory 2024-12-09 18:15:06 +08:00
AkaraChen
14934c0610 feat: file preview in step two 2024-12-09 18:10:56 +08:00
Joel
0d64a35fb6 chore: refact retry btn 2024-12-09 17:34:57 +08:00
twwu
aa0d587516 Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-12-09 16:56:58 +08:00
twwu
55ed41520f feat: enhance batch action confirmation and segment management 2024-12-09 16:55:13 +08:00
Joel
ccdb3c5931 fix: deleting problem 2024-12-09 16:29:33 +08:00
Yeuoly
6e798fad34 fix: add pnpm lock 2024-12-09 16:17:33 +08:00
Yeuoly
e401d917ac fix 2024-12-09 16:16:56 +08:00
Yeuoly
04d3abd754 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-09 16:13:33 +08:00
Yeuoly
16b49ac436 Merge branch 'main' into fix/chore-fix 2024-12-09 16:08:19 +08:00
AkaraChen
01e363f33f Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-12-09 15:43:49 +08:00
AkaraChen
20a2e76f40 feat: file selector for preview in parent child 2024-12-09 15:43:34 +08:00
Yeuoly
c377eb8c28 fix: unbound variable in tool node 2024-12-09 15:43:01 +08:00
Joel
82e2b68d9e feat: preview document picker 2024-12-09 15:42:19 +08:00
twwu
12c791149c Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-12-09 11:46:24 +08:00
twwu
1c5464dbef feat: add pagination for chunk list 2024-12-09 11:46:18 +08:00
AkaraChen
2d66077ed3 fix: option card style 2024-12-09 10:18:04 +08:00
AkaraChen
ec1c03f0a3 fix: i18n & option card props 2024-12-09 10:08:19 +08:00
AkaraChen
3d283a11b6 Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-12-06 23:01:15 +08:00
AkaraChen
cc2a9cdf37 wip: refactor 2024-12-06 22:33:53 +08:00
Joel
b7472c7ab0 chore: change batch url 2024-12-06 18:29:26 +08:00
twwu
c541d4aaa8 Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-12-06 18:21:05 +08:00
twwu
b0a4819ec1 feat: enhance translations and UI components for segment management 2024-12-06 18:20:59 +08:00
Joel
d1d9315f05 chore: list page color to css vars 2024-12-06 17:21:27 +08:00
twwu
c9114d171e Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-12-06 17:19:25 +08:00
twwu
1546859bae feat: add child segment response type and enhance dataset components with improved translations and UI updates 2024-12-06 17:18:29 +08:00
StyleZhang
b448900bb8 merge feat/plugins 2024-12-06 16:58:42 +08:00
StyleZhang
69daf4a027 merge main 2024-12-06 16:56:42 +08:00
Yeuoly
1ce7990df4 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-06 16:47:40 +08:00
Yeuoly
337eff2b79 Merge branch 'main' into fix/chore-fix 2024-12-06 16:45:25 +08:00
AkaraChen
dfebcd0ea7 Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-12-06 16:16:35 +08:00
AkaraChen
6383a64419 fix: step 2 preview ui padding 2024-12-06 16:16:30 +08:00
JzoNg
3bc9ddb006 fix mutation of model credentials update 2024-12-06 16:05:06 +08:00
JzoNg
ea2862e435 fix style of boolean form of model parameters 2024-12-06 16:05:06 +08:00
StyleZhang
ca3d96e5f4 fix: tool list 2024-12-06 15:42:02 +08:00
Joel
570bf75698 feat: support multi 2024-12-06 15:22:31 +08:00
AkaraChen
07f0140d10 feat: preview parent child chunk in create step 2 2024-12-06 15:20:14 +08:00
Joel
6748b50bf1 feat: use query to handle api and remove old api service 2024-12-06 14:26:38 +08:00
AkaraChen
6e38b523c9 wip: create datasets 2024-12-06 13:40:34 +08:00
AkaraChen
a893309b73 wip: create datasets 2024-12-06 13:27:32 +08:00
Joel
f3cfcb757e feat: document update change to batch api 2024-12-06 11:53:28 +08:00
Joel
91666c4394 chore: action i18n and remove confirm 2024-12-06 11:20:03 +08:00
Yeuoly
fbcd4fe1f7 fix: use default_factory for list fields 2024-12-05 20:58:03 +08:00
Yeuoly
b7ac287fec fix: use default_factory for list fields 2024-12-05 20:57:30 +08:00
Joel
768073ddac feat: batch action ui 2024-12-05 17:34:40 +08:00
twwu
734659c873 Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-12-05 15:44:58 +08:00
twwu
b59e95785c feat: enhance DocumentDetail and Completed components with child segment handling and improved layout 2024-12-05 15:44:53 +08:00
AkaraChen
9f8cf03155 Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-12-05 15:32:59 +08:00
AkaraChen
0361bf00d1 fix: option card overflow clip cause language selector hidden 2024-12-05 15:32:34 +08:00
Joel
1cfb938a7b feat: support check item 2024-12-05 15:29:42 +08:00
Joel
cae8ce5a1e fix: list add paging 2024-12-05 15:29:42 +08:00
Yi
d6dea67947 apply the skeleton component to the Plugin loading card 2024-12-05 15:27:47 +08:00
Yi
b8f9747849 Merge branch "main" into feat/plugins 2024-12-05 15:08:09 +08:00
AkaraChen
2417699e85 feat: new qa setting ui 2024-12-05 15:00:54 +08:00
StyleZhang
f038eb2390 Merge branch 'feat/plugins' into dev/plugin-deploy 2024-12-05 14:55:32 +08:00
StyleZhang
0e70e72594 fix: marketplace list 2024-12-05 14:54:20 +08:00
Yeuoly
243d160242 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-05 14:49:04 +08:00
Yeuoly
c1a85b0208 fix: add default value to plugin permission field 2024-12-05 14:48:34 +08:00
Yi
0e419a7a16 feat: move linear gradient bg to common config 2024-12-05 14:44:45 +08:00
Joel
8a8fc7ab50 feat: finish add chunk mode 2024-12-05 14:08:45 +08:00
Joel
1578dc50ef feat: add chunking mode 2024-12-05 11:40:46 +08:00
twwu
78fff31e61 Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-12-05 11:13:20 +08:00
twwu
b18eb58770 feat: implement ChildSegmentList component and integrate it into SegmentCard for displaying child chunks 2024-12-05 11:13:14 +08:00
twwu
52ba180bf4 feat: add SegmentDetail component for displaying and editing segment information 2024-12-05 11:11:57 +08:00
AkaraChen
8541153b15 merge main 2024-12-05 10:57:27 +08:00
AkaraChen
0185fb3369 Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-12-05 10:40:32 +08:00
AkaraChen
5bf6cd242d wip: qa mode 2024-12-05 10:40:27 +08:00
twwu
f8d6d5a6a9 refactor: replace DocumentContext with useDocumentContext for improved context management 2024-12-05 10:12:02 +08:00
twwu
7200dd42d3 refactor: update batch action component props and change id type in ChildChunkDetail 2024-12-05 09:49:37 +08:00
Yeuoly
df68b6befa Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-04 19:26:23 +08:00
Yeuoly
01efdee1dd fix: support other file types for Tool 2024-12-04 19:26:01 +08:00
Yeuoly
3d3a42945f Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-04 19:02:50 +08:00
Yeuoly
0af9c4fd9d chore: reformat 2024-12-04 19:02:28 +08:00
Yeuoly
ee38bd8817 refactor: check dependencies 2024-12-04 19:01:54 +08:00
twwu
44989ae97c Merge branch 'feat/plugins' into dev/plugin-deploy 2024-12-04 18:11:10 +08:00
twwu
0ac5e53c2e fix: refactor GitHub releases fetching to improve error handling and format response 2024-12-04 18:08:25 +08:00
Joel
44b0039e8b fix: install plugin type show error 2024-12-04 18:06:00 +08:00
AkaraChen
4048eff3ab chore: remove twc 2024-12-04 17:37:12 +08:00
twwu
becdca24df fix: enhance GitHub releases fetching with optional authentication 2024-12-04 16:49:49 +08:00
AkaraChen
8289175bfa style: fix component naming 2024-12-04 16:23:43 +08:00
AkaraChen
539050c56b style: fix component naming 2024-12-04 16:16:00 +08:00
AkaraChen
90b407ecc8 feat: loading & empty state for step 2 2024-12-04 16:07:25 +08:00
Joel
9fc0e658ad merge 2024-12-04 16:05:11 +08:00
Yeuoly
e5e8277c2d Merge remote-tracking branch 'origin/feat/plugins' into dev/plugin-deploy 2024-12-04 15:40:39 +08:00
Yeuoly
86291c13e4 Merge branch 'main' into fix/chore-fix 2024-12-04 15:34:39 +08:00
AkaraChen
1df3f4aad3 Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-12-04 14:34:38 +08:00
twwu
8d74eb4946 Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-12-04 14:24:54 +08:00
twwu
388d7918f3 feat: add translation for chunks and new icons; update checkbox styles; add new segment list and segment card 2024-12-04 14:24:47 +08:00
AkaraChen
14f46308a9 chore: gen icon for selection icon 2024-12-04 14:10:17 +08:00
AkaraChen
629152ff2c feat: ui component finish for chunk preview 2024-12-04 11:52:05 +08:00
Joel
29d29f8731 fix: can not chosse const 2024-12-04 11:17:15 +08:00
Joel
f634a4488f merge main 2024-12-04 11:06:00 +08:00
Yeuoly
d5cf64f289 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-03 19:45:25 +08:00
Yeuoly
7679a57f18 fix: agent type errors 2024-12-03 19:44:57 +08:00
Yeuoly
9cb2a031ed Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-03 19:28:22 +08:00
Yeuoly
dcf19549cb feat: move audio and webscraper back to dify 2024-12-03 19:27:57 +08:00
Yi
fc2656b4b7 fix: workspace selector UI 2024-12-03 18:34:18 +08:00
StyleZhang
b858533a57 Merge branch 'feat/plugins' into dev/plugin-deploy 2024-12-03 18:04:11 +08:00
StyleZhang
d6a4cbc6cc fix: marketplace list 2024-12-03 18:03:39 +08:00
AkaraChen
bebad5cbdd refactor: step 2 2024-12-03 17:26:45 +08:00
Yeuoly
c51fa7a440 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-03 16:52:09 +08:00
Yeuoly
574a6c1ded fix: add extension, filename and size to PluginFileEntity 2024-12-03 16:51:51 +08:00
Yeuoly
e6fcf06e59 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-03 16:29:02 +08:00
Yeuoly
c34877aecf fix: update tool provider credentials 2024-12-03 16:28:36 +08:00
Yi
1e2ee61f6a feat: add version check before Plugin install from GitHub 2024-12-03 15:47:45 +08:00
AkaraChen
dfdc4ed3b1 refactor: step 2 2024-12-03 15:23:51 +08:00
AkaraChen
a77aa169b4 refactor: step 2 2024-12-03 14:43:15 +08:00
StyleZhang
66b79ee323 Merge branch 'feat/plugins' into dev/plugin-deploy 2024-12-03 14:35:36 +08:00
StyleZhang
ab9a177c90 fix: marketplace list 2024-12-03 14:34:44 +08:00
AkaraChen
94eb069a97 refactor: step 2 2024-12-03 14:34:18 +08:00
AkaraChen
c960f78035 refactor: step 2 2024-12-03 14:14:37 +08:00
nite-knite
8b28ed589c feat: update translation for bundle 2024-12-03 13:43:13 +08:00
AkaraChen
90421b5fb5 feat: preview container components 2024-12-03 13:39:27 +08:00
Yeuoly
1dad2fdaaf Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-02 22:00:05 +08:00
Yeuoly
632b2bac2a fix: invoke-email 2024-12-02 21:59:52 +08:00
Yeuoly
dbc555f698 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-02 21:26:12 +08:00
Yeuoly
77a62f33b3 fix: Lookup errors for contextvars used in ToolManager 2024-12-02 21:25:47 +08:00
Yeuoly
78a0c3c13c Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-02 21:08:53 +08:00
Yeuoly
ad899844a1 fix: workflow loads tool provider icon 2024-12-02 21:08:36 +08:00
nite-knite
3232a45ec4 Merge branch 'feat/plugins' into dev/plugin-deploy 2024-12-02 18:00:09 +08:00
nite-knite
3b1211d6bc chore: bump cross-spawn from 7.0.3 to 7.0.6 2024-12-02 17:54:39 +08:00
nite-knite
7bd3f2b932 feat: update description for API endpoints configuration 2024-12-02 17:41:52 +08:00
Yeuoly
5abbe76ca0 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-12-02 16:51:57 +08:00
Yeuoly
b10d6051ba fix: summary and create_file_by_url 2024-12-02 16:51:37 +08:00
JzoNg
86f45d7e25 Merge branch 'feat/plugins' into dev/plugin-deploy 2024-12-02 16:13:31 +08:00
Yeuoly
e23d322c1c Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-29 18:20:59 +08:00
Yeuoly
fb44cd87e7 fix: image url message 2024-11-29 18:20:36 +08:00
Yeuoly
48c9a25393 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-29 16:49:18 +08:00
Yeuoly
89af726985 fix: cot agent 2024-11-29 16:48:39 +08:00
Yeuoly
8266bf6fa8 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-29 16:17:48 +08:00
Yeuoly
6f2d5ff099 fix: add tenant_id to invoke tts 2024-11-29 15:59:07 +08:00
Joel
b78ab0bd69 fix: other install error 2024-11-29 15:18:07 +08:00
Joel
84cad5969e fix: not handleinstall error 2024-11-29 15:09:23 +08:00
Yeuoly
f36a50ad09 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-29 14:09:54 +08:00
Yeuoly
687455ca31 fix: tool file id 2024-11-29 14:09:34 +08:00
Joel
35ef874867 fix: detect is same packege use uniqid 2024-11-29 10:56:58 +08:00
Yeuoly
df67200e18 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-28 20:44:58 +08:00
Yeuoly
8c5928da2f fix: unify error handling 2024-11-28 20:44:06 +08:00
Yeuoly
d409d30ee5 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-28 19:35:48 +08:00
Yeuoly
772009115d fix: keep process_data with None if not 2024-11-28 19:35:30 +08:00
Yeuoly
5df52b33d7 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-28 19:09:27 +08:00
Yeuoly
0452dfd029 fix: missing tool invoke messages 2024-11-28 19:09:04 +08:00
Joel
47579c86e6 fix: from marketplace install and update bundle 2024-11-28 18:47:06 +08:00
Joel
32619bd05e fix: install bunlde support update 2024-11-28 18:26:18 +08:00
Yeuoly
e79dcf93fe Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-28 18:24:19 +08:00
Yeuoly
eead6abe85 fix: tool image url response 2024-11-28 18:23:28 +08:00
JzoNg
6bd483030f Merge branch 'feat/plugins' into dev/plugin-deploy 2024-11-28 17:49:43 +08:00
JzoNg
6a500edf4d fix: loading of credential form 2024-11-28 17:48:28 +08:00
JzoNg
adba60d067 Merge branch 'feat/plugins' into dev/plugin-deploy 2024-11-28 17:30:56 +08:00
JzoNg
be7fa93ffc fix: modify tip of default embedding model 2024-11-28 17:27:21 +08:00
JzoNg
3bcd470ec6 fix: authorization in debugging plugin 2024-11-28 17:27:21 +08:00
JzoNg
73825c59e4 fix: crash of tool authorization in agent 2024-11-28 17:27:21 +08:00
JzoNg
5f76975e12 fix: icon of tool provider in agent 2024-11-28 17:27:21 +08:00
JzoNg
3ddb3d2bff fix: deleted tools in agent 2024-11-28 17:27:21 +08:00
JzoNg
a70eda6c45 add loading for auth modal 2024-11-28 17:27:21 +08:00
Yeuoly
1858e523f1 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-28 17:12:55 +08:00
Yeuoly
5c6d919a4a fix: handle detailed error type 2024-11-28 17:12:29 +08:00
NFish
42cdc55db1 fix: do not show error tooltip if http status code is 401 2024-11-28 16:04:19 +08:00
NFish
a76d0a09b6 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-11-28 16:03:05 +08:00
AkaraChen
11679dc68a feat: child chunk component for dataset 2024-11-28 15:18:56 +08:00
Joel
51f0f21a47 chore: not load updateInfo can not install 2024-11-28 14:30:31 +08:00
Joel
073e847524 fix: installed 2024-11-28 14:13:43 +08:00
Joel
3e601c4ef5 feat: local support upgrade 2024-11-28 14:09:05 +08:00
Joel
fba468e8ad fix: handle install the same version 2024-11-28 13:50:04 +08:00
twwu
d1c3c26dc7 Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-11-28 13:37:20 +08:00
twwu
32df9d6e00 feat: add segment management hooks for enabling, disabling, and deleting segments 2024-11-28 13:37:12 +08:00
Joel
f40b212b04 feat: support update if installed from marketplace 2024-11-28 12:00:12 +08:00
StyleZhang
9d8445c758 Merge branch 'feat/plugins' into dev/plugin-deploy 2024-11-28 11:27:13 +08:00
StyleZhang
37eee7be24 fix: model provider page marketplace 2024-11-28 11:26:45 +08:00
Joel
99942b26e6 chore: support install hide button 2024-11-28 10:40:33 +08:00
AkaraChen
25bccd52c2 feat: child chunk component for dataset 2024-11-28 10:36:24 +08:00
AkaraChen
521ab30bba fix: data processing form layout padding 2024-11-28 10:20:08 +08:00
Joel
cc64419c84 feat: use new file icon 2024-11-27 17:57:28 +08:00
Joel
e27568f0c7 fix: not add datasetid to picker 2024-11-27 16:52:10 +08:00
Joel
b7b49daff8 feat: add picker logic 2024-11-27 16:48:40 +08:00
StyleZhang
9302a5fac8 merge feat/plugins 2024-11-27 16:15:57 +08:00
StyleZhang
d4cda69b0e feat: marketplace add exclude 2024-11-27 16:14:15 +08:00
Joel
71e285c490 feat: add document file select 2024-11-27 15:52:58 +08:00
Yeuoly
b1f2fc3cf4 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-27 14:49:00 +08:00
Yeuoly
e39eddab03 fix: change to use convert_stream_full_response 2024-11-27 14:48:44 +08:00
StyleZhang
e145dba487 fix: dsl check 2024-11-27 14:30:47 +08:00
Joel
e908ecab8f fix: add ui 2024-11-27 10:50:39 +08:00
AkaraChen
f1655888ef fix: number input component 2024-11-27 10:29:16 +08:00
Yeuoly
3a18aaebd2 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-26 18:59:18 +08:00
Yeuoly
db726e02a0 feat: support multi token count 2024-11-26 18:59:03 +08:00
Yeuoly
66d4de39b8 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-26 18:04:34 +08:00
Yeuoly
e4b8220bc2 Merge branch 'main' into fix/chore-fix 2024-11-26 18:02:41 +08:00
Joel
a98df0158e chore: document header 2024-11-26 17:26:20 +08:00
AkaraChen
378461bf8a Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-11-26 17:22:07 +08:00
AkaraChen
e2c6ea3a3a chore: align design token 2024-11-26 17:22:02 +08:00
twwu
0c4e06e1c1 Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-11-26 16:56:34 +08:00
twwu
1e4167427c refactor: update processing status UI and add new CSS variables for success and error states 2024-11-26 16:56:27 +08:00
AkaraChen
e26a963163 fix: missing translation 2024-11-26 16:05:14 +08:00
AkaraChen
72ca69fb2a Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-11-26 15:38:03 +08:00
AkaraChen
db1956ed54 feat: dataset creation form reset 2024-11-26 15:37:57 +08:00
Joel
9aceceda2c fix: css var value 2024-11-26 15:33:58 +08:00
AkaraChen
1843f6ccb6 refactor: input number component 2024-11-26 15:29:31 +08:00
AkaraChen
b7d9987953 chore: align design token 2024-11-26 14:48:49 +08:00
Joel
b8af4aead1 fix: update version show problem 2024-11-26 14:38:43 +08:00
AkaraChen
b528b1e875 refactor: use css var 2024-11-26 14:33:40 +08:00
AkaraChen
c4aa98e609 Merge branch 'main' into feat/parent-child-retrieval 2024-11-26 14:18:56 +08:00
AkaraChen
4757db1b6b refactor: use css var 2024-11-26 14:18:42 +08:00
Joel
d40f0e645c fix: install marketplace bundle title 2024-11-26 14:11:21 +08:00
Joel
4b77ced4ad fix: not show from market bundle package icon 2024-11-26 14:07:45 +08:00
Yeuoly
d695ac4b24 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-26 14:00:28 +08:00
Yeuoly
08cfcb453c fix: missing marshal fields of leaked+dependencies 2024-11-26 13:59:52 +08:00
StyleZhang
b84b0c8ba8 merge main 2024-11-26 11:38:37 +08:00
StyleZhang
f47b32b26d fix: dsl 2024-11-26 11:10:53 +08:00
StyleZhang
102a42d24c Merge branch 'main' into feat/plugins 2024-11-26 11:08:30 +08:00
StyleZhang
00eb47384a merge main 2024-11-26 10:31:39 +08:00
StyleZhang
2041650cca merge main 2024-11-26 10:29:58 +08:00
StyleZhang
a0873a956f merge main 2024-11-26 10:27:48 +08:00
Yeuoly
6e37eeabca Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-25 23:36:35 +08:00
Yeuoly
992e1eedde fix: export agent dsl 2024-11-25 23:36:19 +08:00
Yeuoly
cdeda89801 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-25 23:22:52 +08:00
Yeuoly
c2ce8e638e fix: deleted_tools 2024-11-25 23:22:17 +08:00
Joel
df049564e8 feat: support install bundle from marketplace 2024-11-25 18:01:30 +08:00
Joel
b93be49530 chore: support update show version 2024-11-25 18:01:29 +08:00
AkaraChen
1a6a28f650 feat: settings ui for database pre-preprocessing 2024-11-25 17:57:31 +08:00
StyleZhang
6bc37f4f00 Merge branch 'feat/plugins' into dev/plugin-deploy 2024-11-25 17:54:45 +08:00
StyleZhang
57756b18e4 fix: plugin task 2024-11-25 17:54:28 +08:00
StyleZhang
2252821cae Merge branch 'feat/plugins' into dev/plugin-deploy 2024-11-25 17:33:25 +08:00
StyleZhang
8ad9ab40df fix: plugin task 2024-11-25 17:32:57 +08:00
Yeuoly
e68fec0022 fix: linter 2024-11-25 17:20:43 +08:00
Yeuoly
69b61ef57b Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-25 17:19:51 +08:00
Yeuoly
ba3659a792 feat: support delete all install tasks 2024-11-25 17:11:41 +08:00
Yeuoly
965fabd578 fix: rename dependencies 2024-11-25 16:57:38 +08:00
Yeuoly
accbbae755 cleanup: remove get_interates 2024-11-25 16:47:49 +08:00
Yeuoly
49bd1a7a49 fix: riff 2024-11-25 16:44:08 +08:00
Yeuoly
5ff9cee326 Merge branch 'main' into fix/chore-fix 2024-11-25 15:37:19 +08:00
StyleZhang
4f54ac6ed6 fix: marketplace collection condition 2024-11-25 12:03:49 +08:00
Yeuoly
dfc94cd7c2 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-22 20:04:42 +08:00
Yeuoly
200f9af5d8 optimize error messages 2024-11-22 20:04:20 +08:00
Yeuoly
1443fd6739 optimize: indexing-estimate 2024-11-22 19:39:07 +08:00
Yeuoly
f69d5caa14 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-22 18:19:27 +08:00
Yeuoly
e63ae36665 fix 2024-11-22 18:19:02 +08:00
Yeuoly
cfa7c89dfe refactor: text-embedding interfaces to returns list[int] 2024-11-22 18:09:33 +08:00
StyleZhang
a84f0e29a4 Merge branch 'feat/plugins' into dev/plugin-deploy 2024-11-22 15:27:48 +08:00
StyleZhang
3263a6a5f5 fix: marketplace plugin tags i18n 2024-11-22 15:26:25 +08:00
JzoNg
27ea150a44 Merge branch 'feat/plugins' into dev/plugin-deploy 2024-11-22 15:11:52 +08:00
JzoNg
506e5e0bc8 fix: plugin type 2024-11-22 14:53:20 +08:00
AkaraChen
bba9301788 fix: layout overflow 2024-11-22 14:09:41 +08:00
AkaraChen
7881fb4d22 fix: layout overflow 2024-11-22 13:12:24 +08:00
JzoNg
c768f8fdd1 fix: path of tool provider 2024-11-22 11:41:36 +08:00
twwu
d45ce48932 fix: update theme imports in globals.css 2024-11-22 11:02:45 +08:00
Joel
c6b1fecc21 merge 2024-11-22 11:01:00 +08:00
Joel
3e3ae989f0 chore: in tool file and files all support file and files 2024-11-22 10:54:22 +08:00
Joel
786f2d9bf6 chore: fix categoriesMap[category] undefined 2024-11-22 10:39:22 +08:00
twwu
85377d13fc Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-22 10:22:39 +08:00
twwu
51e04b45ec fix: update error icon z-index and upgrade react-query dependencies 2024-11-22 10:22:33 +08:00
JzoNg
bd6c2e519c fix: corner mark 2024-11-22 09:09:35 +08:00
Joel
3f0b35d72e feat: install bundle from marketplace code 2024-11-21 18:22:11 +08:00
JzoNg
f51336df08 Merge branch 'feat/plugins' into dev/plugin-deploy 2024-11-21 18:13:11 +08:00
JzoNg
78c867b9a3 use plugin detail for builtin tool 2024-11-21 18:11:36 +08:00
JzoNg
f213c8f393 fix: version switch 2024-11-21 18:11:36 +08:00
Joel
1b3f4f1f2a feat: support icon size 2024-11-21 18:00:13 +08:00
Joel
c59c696df2 chore: add version type in marketplace return 2024-11-21 17:43:41 +08:00
Joel
8993a91f12 fix: upgrade sussces auto hide 2024-11-21 17:38:23 +08:00
JzoNg
02c5989612 recover api tool create card 2024-11-21 17:29:28 +08:00
JzoNg
ac42ba880a fix: install handle of list refresh 2024-11-21 17:11:22 +08:00
Yeuoly
b2fdf4f85f Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-21 17:00:28 +08:00
Yeuoly
a6835ac64d fix: add detailed error messages 2024-11-21 17:00:00 +08:00
AkaraChen
fdcee1cd45 feat: create top bar 2024-11-21 16:19:32 +08:00
JzoNg
56f573ecfb fix: update plugin handle 2024-11-21 15:35:39 +08:00
Joel
2560d3edae fix: bundle install title 2024-11-21 15:22:19 +08:00
Joel
351615fb98 fix: not the first time upload bundle error 2024-11-21 15:14:21 +08:00
twwu
13c62f83f4 Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-11-21 15:13:21 +08:00
twwu
c5b9a829c0 feat: update UI styles and enhance status indicator components 2024-11-21 15:13:16 +08:00
Yeuoly
cc8117f02a Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-21 14:36:34 +08:00
Yeuoly
846c3faba7 fix: ruff 2024-11-21 14:36:01 +08:00
Yeuoly
7c74aaabcf Merge remote-tracking branch 'origin/feat/plugins' into dev/plugin-deploy 2024-11-21 14:35:14 +08:00
Joel
11ed86f2a8 feat: download package 2024-11-21 14:25:58 +08:00
JzoNg
b01c18ae7f fix: version badge 2024-11-21 14:16:02 +08:00
Yeuoly
a700b49461 fix: migration 2024-11-21 13:55:08 +08:00
Yeuoly
22df86fe8a fix: ruff 2024-11-21 13:53:08 +08:00
Yeuoly
24734009b9 Merge branch 'main' into fix/chore-fix 2024-11-21 13:52:28 +08:00
StyleZhang
84a3fe85c8 fix: marketplace card link 2024-11-21 13:50:26 +08:00
JzoNg
3efc6c5050 fix: github link 2024-11-21 13:42:06 +08:00
JzoNg
42a0534299 fix: locale of model provider 2024-11-21 13:18:33 +08:00
JzoNg
eec193488d fix: detail link of plugin 2024-11-21 13:09:10 +08:00
JzoNg
021bc57cd4 empty of tool list 2024-11-21 12:43:18 +08:00
StyleZhang
022eda9e8b fix: tool providers 2024-11-21 12:03:53 +08:00
AkaraChen
6f3a1c9d72 feat: parent child state 2024-11-21 11:40:17 +08:00
Joel
2067092f52 feat: detail link in tools 2024-11-21 11:33:21 +08:00
Joel
000db07d29 feat: in tool install plugin 2024-11-21 11:16:05 +08:00
Joel
98ae34acd5 chore: support tags filter 2024-11-21 10:51:36 +08:00
StyleZhang
698e94856e fix: plugin task zindex 2024-11-21 08:42:36 +08:00
Yeuoly
e05d7637ac Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-21 00:30:47 +08:00
Yeuoly
959d060a44 fix: remove signature verify 2024-11-21 00:30:28 +08:00
Joel
99ffe43e91 merge main 2024-11-20 18:24:03 +08:00
Yeuoly
4921e610af Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-20 18:12:45 +08:00
Yeuoly
4492295683 fix: remove plugin files 2024-11-20 18:12:12 +08:00
Joel
498222371c chore: parse marketplace bundle new api 2024-11-20 17:52:35 +08:00
twwu
13bb4aa721 Merge branch 'feat/parent-child-retrieval' of https://github.com/langgenius/dify into feat/parent-child-retrieval 2024-11-20 16:38:48 +08:00
twwu
d0ef423e66 feat: enhance SegmentCard and SegmentAdd components with new DocumentTitle and improved UI elements 2024-11-20 16:38:38 +08:00
Joel
26288e71d3 fix: local bundle install 2024-11-20 16:32:20 +08:00
AkaraChen
8e1aef6120 feat: new dataset footer ui 2024-11-20 16:24:06 +08:00
JzoNg
19fb466074 fix: tool icon in app configure 2024-11-20 16:22:51 +08:00
JzoNg
cd4eb9c3f1 fix: icon in model list 2024-11-20 16:22:51 +08:00
Joel
4ef0a3818f feat: can install bundle from local 2024-11-20 16:21:09 +08:00
twwu
77d6dbb3d0 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-20 15:31:03 +08:00
twwu
e3b8926aef fix: correct fetched releases variable in version check and update dev script for debugging 2024-11-20 15:30:57 +08:00
AkaraChen
4657df17a9 revert: qa mode 2024-11-20 15:25:26 +08:00
Joel
efb84ff03d fix: github install fix 2024-11-20 15:05:17 +08:00
AkaraChen
27ece2fb52 feat: most ui for create datasets
chore: upd
2024-11-20 14:55:59 +08:00
Joel
1846a7de73 fix: handle github item from data struct diffe 2024-11-20 14:48:38 +08:00
Joel
40d025052d fix: load package dsl error 2024-11-20 14:27:46 +08:00
Joel
bb2914652a feat: finsh loading error comp 2024-11-20 13:56:32 +08:00
Joel
e6a03f7a58 feat: loading error struct 2024-11-20 11:50:46 +08:00
JzoNg
386ee7b07b update model provider list after plugin installed 2024-11-20 11:49:20 +08:00
JzoNg
788f9de843 update model provider list after deleting plugin 2024-11-20 10:44:20 +08:00
AkaraChen
ca4d0fb4cc feat: option card component
chore: upd
2024-11-20 10:13:40 +08:00
Joel
5947e38ea0 feat: install by local bundle change 2024-11-19 18:32:17 +08:00
Joel
e151c2ee8c fix: when error can not install 2024-11-19 17:29:15 +08:00
Joel
a093a48675 feat: show package item in bundle 2024-11-19 17:29:14 +08:00
Yeuoly
6c9f77092a Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-19 16:50:47 +08:00
Yeuoly
88fac0d898 fix: add tenant_id to plugin upload files url 2024-11-19 16:50:14 +08:00
StyleZhang
f99f25ae02 Merge branch 'feat/plugins' into dev/plugin-deploy 2024-11-19 16:43:38 +08:00
StyleZhang
27b1a51572 fix: marketplace collection label description 2024-11-19 16:43:13 +08:00
JzoNg
a867040b88 fix icon of model provider 2024-11-19 16:26:23 +08:00
Joel
2e3442f74c feat: support local installed package 2024-11-19 16:04:31 +08:00
StyleZhang
ba53900ec4 merge 2024-11-19 15:14:27 +08:00
StyleZhang
43d7a538dc feat: marketplace list url support search & tags 2024-11-19 15:08:54 +08:00
Joel
c5c06c18f1 feat: can upload and parse bundle 2024-11-19 15:05:15 +08:00
Yeuoly
ba148952bd Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-19 14:04:15 +08:00
Yeuoly
8b30099672 fix: convert backwards invocation into BaseBackwardsResponse 2024-11-19 14:03:40 +08:00
twwu
972eaa5948 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-19 11:20:23 +08:00
twwu
87b23a1fac feat: refactor GitHub releases fetching and update handling with improved error notifications 2024-11-19 11:20:17 +08:00
Yeuoly
44e9758549 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-18 17:21:32 +08:00
Yeuoly
97a3727962 fix: optimize DEFAULT-USER 2024-11-18 17:21:17 +08:00
AkaraChen
07174cf52c Revert "fix: dataset details"
This reverts commit 812fbab57b.
2024-11-18 15:41:31 +08:00
twwu
d3fe6fd303 fix: display version from GitHub metadata if available 2024-11-18 11:57:31 +08:00
twwu
87ca20c047 feat: add version checking for GitHub releases and improve error handling 2024-11-18 11:54:51 +08:00
AkaraChen
07494459cc Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-18 11:23:49 +08:00
AkaraChen
812fbab57b fix: dataset details 2024-11-18 11:23:44 +08:00
JzoNg
afdfc8c609 chore: enabled for useQuery 2024-11-18 11:02:37 +08:00
JzoNg
66f0e1209a switch version 2024-11-17 12:57:34 +08:00
JzoNg
f0e4885926 tooltip of endpoints 2024-11-17 10:54:40 +08:00
Yeuoly
2698b1c222 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-15 19:54:56 +08:00
Yeuoly
2cb640de15 refactor: load tools cache 2024-11-15 19:53:50 +08:00
Yeuoly
59b76900d7 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-15 18:39:40 +08:00
Yeuoly
fb4ee813c7 fix: agent 2024-11-15 18:37:33 +08:00
Joel
1dc2d7f4a2 chore: fix jump url 2024-11-15 16:49:12 +08:00
StyleZhang
cc28dafede Merge branch 'feat/plugins' into dev/plugin-deploy 2024-11-15 16:46:46 +08:00
StyleZhang
9193bc3143 fix: marketplace link 2024-11-15 16:46:23 +08:00
Joel
3b032f086d fix: market icon not show 2024-11-15 16:37:51 +08:00
StyleZhang
5be781e007 Merge branch 'feat/plugins' into dev/plugin-deploy 2024-11-15 16:33:17 +08:00
StyleZhang
746838e276 fix: marketplace link 2024-11-15 16:32:49 +08:00
Yi
5ea306850e fix: copy tooltip shows in wrong place 2024-11-15 16:23:11 +08:00
Joel
7fe16a9f9d merge 2024-11-15 16:13:40 +08:00
Yi
a6be3fdcd0 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-11-15 16:09:21 +08:00
Yi
a7a5c6f4cb fix: update the upgrade button text content in the header 2024-11-15 16:09:04 +08:00
twwu
f53b658964 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-15 16:07:41 +08:00
twwu
70bf321fd7 fix: add plugin type to card payload and integrate categories hook 2024-11-15 16:07:34 +08:00
Yeuoly
6da877c6a6 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-15 15:56:45 +08:00
Yeuoly
6300e506fb fix: rag 2024-11-15 15:54:14 +08:00
StyleZhang
35eafd239d fix: plugin task 2024-11-15 15:50:14 +08:00
StyleZhang
3f2baf0131 fix: plugin task 2024-11-15 15:46:29 +08:00
Yeuoly
a0543ab8fb Merge branch 'main' into fix/chore-fix 2024-11-15 15:43:32 +08:00
StyleZhang
a5a6969db3 fix 2024-11-15 15:36:32 +08:00
StyleZhang
c176494405 fix: search box style 2024-11-15 15:26:29 +08:00
Joel
1e81476e3a chore: fix lockfile 2024-11-15 15:24:08 +08:00
Joel
6fbff78b9c merge 2024-11-15 15:16:53 +08:00
Joel
0738c2ef54 fix: can not get url 2024-11-15 15:03:18 +08:00
StyleZhang
984e4564f8 fix: dsl check plugin 2024-11-15 14:54:17 +08:00
StyleZhang
bc927868f4 fix: plugin task 2024-11-15 14:54:17 +08:00
Joel
a0758dc2fc feat: finish github install 2024-11-15 14:40:04 +08:00
Joel
6b759795d5 feat: can install github 2024-11-15 13:09:29 +08:00
Joel
bba80f465b just add 2024-11-15 13:09:28 +08:00
Joel
ebaa94be15 mrege 2024-11-15 12:11:00 +08:00
Joel
6699441e53 just add 2024-11-15 12:07:20 +08:00
Yi
735e47f5e5 chore: update the styling in the "members setting" 2024-11-15 11:29:48 +08:00
twwu
d354c69493 chore: update translations to include 'Marketplace' terminology in Chinese localization 2024-11-15 11:05:20 +08:00
JzoNg
8f14881aff app parameters 2024-11-15 10:43:21 +08:00
JzoNg
e53c4fc0ad empty inputs form of app selector 2024-11-15 10:43:21 +08:00
JzoNg
f9f2e68bd8 app selector in form 2024-11-15 10:43:21 +08:00
JzoNg
7b4d67d72f app list filter 2024-11-15 10:43:21 +08:00
JzoNg
7446244147 app picker 2024-11-15 10:43:21 +08:00
JzoNg
c723bd2c96 app selector trigger 2024-11-15 10:43:21 +08:00
Joel
73ce8a17a5 feat: add loading 2024-11-15 10:39:57 +08:00
Yeuoly
1812af6cfe Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-15 00:47:46 +08:00
Yeuoly
634cb6233e feat: sypport batch fetch plugin installations 2024-11-15 00:47:25 +08:00
Yeuoly
94a8547217 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-14 22:59:18 +08:00
Yeuoly
db68ae4a73 feat: support upload bundle 2024-11-14 22:58:57 +08:00
Yeuoly
5bd7598a37 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-14 18:34:32 +08:00
Yeuoly
d25e79e794 feat: support uploading images through plugin 2024-11-14 18:32:51 +08:00
Joel
6f5e010db5 chore: handle uploaded selected 2024-11-14 18:31:22 +08:00
Yi
495d86fd96 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-11-14 18:28:18 +08:00
Yi
42ba4e4f0e chore: update the plugins tab button 2024-11-14 18:26:16 +08:00
StyleZhang
6af51701de fix: card link 2024-11-14 18:18:10 +08:00
Joel
76104d811c feat: can show install plugins 2024-11-14 16:54:36 +08:00
StyleZhang
1877433f20 fix: marketplace 2024-11-14 16:37:53 +08:00
Yi
a403fb565d chore: update the plan tags 2024-11-14 16:21:28 +08:00
twwu
f58b88f319 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-14 15:47:27 +08:00
twwu
cd2860deb4 feat: add i18n support for plugin installation and empty states 2024-11-14 15:47:22 +08:00
AkaraChen
070968a048 style: add lint rule for tailwind 2024-11-14 15:39:21 +08:00
StyleZhang
ceb18d160f fix: marketplace i18n 2024-11-14 14:56:15 +08:00
StyleZhang
6a63a03cb2 feat: tool list use query 2024-11-14 14:48:13 +08:00
twwu
a0a62db6ad refactor: Split linear-gradient and color 2024-11-14 14:36:30 +08:00
StyleZhang
253abaf1a3 fix: marketplace empty page 2024-11-14 14:27:34 +08:00
AkaraChen
44cc6157f1 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-14 11:35:53 +08:00
Yi
028fc00be6 chore: update i18n & setting window 2024-11-14 11:19:39 +08:00
AkaraChen
1aed0fe5d6 chore: use mitt hook 2024-11-14 11:04:41 +08:00
JzoNg
300cd675c6 update tool list after tool selector 2024-11-14 00:04:06 +08:00
JzoNg
ff1d42bd66 add tool selector in endpoint modal 2024-11-14 00:02:04 +08:00
JzoNg
194a99220b authorization of tool selector 2024-11-14 00:02:04 +08:00
JzoNg
926f85ce4f tool selector trigger 2024-11-14 00:02:04 +08:00
Yi
6c6e1e90cd Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-11-13 18:41:27 +08:00
twwu
2fbc0c2261 revert: revert category label handling in plugin card component 2024-11-13 18:40:23 +08:00
Yi
bac1e99557 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-11-13 18:40:20 +08:00
Yi
93e3077f77 chore: update the esc button and the upgrade button 2024-11-13 18:40:11 +08:00
twwu
fa6858090b refactor: remove version prop from plugin item components and update version comparison logic 2024-11-13 18:34:04 +08:00
twwu
61eb655823 feat: update plugin category labels and improve internationalization support 2024-11-13 18:30:38 +08:00
twwu
6298332950 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-13 16:55:49 +08:00
twwu
a1719c49b7 feat: add internationalization support for plugin categories and update translations 2024-11-13 16:55:43 +08:00
Yi
b10a1cd325 chore: update the theme selector setting in globals.css 2024-11-13 16:43:00 +08:00
StyleZhang
aa88028564 fix: marketplace list 2024-11-13 16:28:38 +08:00
Joel
3e314843db chore: add missing file 2024-11-13 16:23:33 +08:00
Joel
0d607a8c90 feat: add update workflow to update use query 2024-11-13 16:23:31 +08:00
StyleZhang
577a948f42 feat: dsl check plugin 2024-11-13 15:48:25 +08:00
Yeuoly
1c411143e5 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-13 15:19:32 +08:00
Yeuoly
183b943803 feat: support check dependencies through url 2024-11-13 15:19:20 +08:00
Joel
edbfe27eb1 chore: add invalid all built in tools 2024-11-13 15:17:22 +08:00
Joel
5c98d80fdf chore: more filter text content 2024-11-13 15:12:58 +08:00
Joel
89b470d0d5 fix: toggle tool 2024-11-13 15:04:23 +08:00
Joel
19dc983d30 feat: support toggle set tool when the texts changes 2024-11-13 14:54:37 +08:00
twwu
e842a46fe2 fix: resolve issue with dark mode 2024-11-13 14:43:37 +08:00
Yeuoly
612eba2765 tests: for CD 2024-11-13 14:30:55 +08:00
Yeuoly
4fdaf57897 refactor 2024-11-13 14:28:40 +08:00
Yeuoly
479928f428 refactor cd 2024-11-13 14:23:02 +08:00
Yeuoly
a53ea578b9 tests: cd 2024-11-13 14:11:46 +08:00
Joel
1573f6f6aa feat: add tag and q filter 2024-11-13 14:08:16 +08:00
snake
3c6babdf35 cd for plugin env 2024-11-13 13:58:58 +08:00
AkaraChen
f74dc032f9 fix: new workflow init draft failed 2024-11-13 13:51:55 +08:00
snake
bc614cb507 cd for plugin env 2024-11-13 13:38:12 +08:00
AkaraChen
910d5df513 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-13 13:33:47 +08:00
snake
92c2fa0a88 deploy script add cat action 2024-11-13 13:28:46 +08:00
twwu
fa01360498 fix: Fix theme initialization issue 2024-11-13 13:11:47 +08:00
AkaraChen
1fe5be532d fix: new workflow init draft failed 2024-11-13 12:59:52 +08:00
Joel
d67eb907dd fix: show index letter problem 2024-11-13 11:56:33 +08:00
Joel
83dae7e5bc fix: can not select action in workflow and tools 2024-11-13 11:38:44 +08:00
StyleZhang
c6d1b7869d fix: plugin task 2024-11-13 11:33:58 +08:00
snake
32b8efcc73 cd for plugin env 2024-11-13 11:28:31 +08:00
snake
3aa679b061 cd for plugin env 2024-11-13 11:11:30 +08:00
snake
07def4587c cd for plugin env 2024-11-13 11:01:37 +08:00
snake
830bf4dc3c print context var 2024-11-13 10:51:40 +08:00
snake
e1c2929219 print context var 2024-11-13 10:48:02 +08:00
snake
3976c7fee8 print context var 2024-11-13 10:44:33 +08:00
snake
11fd02ae99 print context var 2024-11-13 10:42:01 +08:00
Yi
601d267b7a Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-11-13 10:39:07 +08:00
Yi
327940a120 chore: update the update plugin from GitHub 2024-11-13 10:38:56 +08:00
snake
d89ab877b7 print context var 2024-11-13 10:32:43 +08:00
snake
e83d2da661 print context var 2024-11-13 10:31:45 +08:00
snake
f3986c5600 print context var 2024-11-13 10:30:49 +08:00
snake
a31693c273 print context var 2024-11-13 10:30:07 +08:00
snake
0e541da25e print context var 2024-11-13 10:22:05 +08:00
snake
64ffe96480 print context var 2024-11-13 10:21:11 +08:00
Yeuoly
8ed2695286 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-12 21:43:44 +08:00
Yeuoly
5828abcd62 fix: uses to check if the tools are already loaded 2024-11-12 21:43:19 +08:00
Yeuoly
a42b081e32 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-12 20:48:51 +08:00
Yeuoly
56bd0dedfe fix: incorrect paths to upgrade plugins 2024-11-12 20:48:28 +08:00
Yeuoly
beea9d01f3 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-12 19:57:32 +08:00
Yeuoly
f6136427a4 feat: export dsl with dependencies 2024-11-12 19:50:56 +08:00
Yeuoly
21fd58caf9 Merge branch 'fix/chore-fix' of github.com:langgenius/dify into fix/chore-fix 2024-11-12 18:53:45 +08:00
snake
641153eed8 print context var 2024-11-12 18:47:24 +08:00
snake
370736cad9 print context var 2024-11-12 18:38:46 +08:00
snake
153f3b77ec print context var 2024-11-12 18:29:48 +08:00
StyleZhang
582c7ce348 fix: plugin task 2024-11-12 18:28:34 +08:00
snake
88611fe1aa print context var 2024-11-12 18:23:02 +08:00
snake
ede82299e1 print context var 2024-11-12 18:14:31 +08:00
snake
f031eeb473 print context var 2024-11-12 17:58:34 +08:00
StyleZhang
13d3f67746 feat: plugin task use query 2024-11-12 17:58:32 +08:00
snake
61096d7f7a print context var 2024-11-12 17:54:54 +08:00
snake
5b703d1792 print context var 2024-11-12 17:51:00 +08:00
Joel
9c6aafd415 feat: install bundle ui 2024-11-12 17:33:10 +08:00
snake
1af087abc1 print context var 2024-11-12 17:19:45 +08:00
nite-knite
3716ea46b5 chore: bump elliptic from 6.5.7 to 6.6.0 2024-11-12 17:19:02 +08:00
snake
d3d84217a7 print context var 2024-11-12 17:16:49 +08:00
snake
51e230309b revert deploy-dev.yml 2024-11-12 17:14:31 +08:00
JzoNg
3c89b8a698 confirm model selector schema in agent and workflow 2024-11-12 16:57:22 +08:00
JzoNg
b188800f16 model selector in endpoint modal 2024-11-12 16:57:22 +08:00
JzoNg
75a037bc2a update style of model & parameter selector 2024-11-12 16:57:22 +08:00
JzoNg
5efcdd6fa7 model parameters 2024-11-12 16:57:22 +08:00
JzoNg
06c4627abb tool selecting in configure 2024-11-12 16:57:22 +08:00
JzoNg
f5267d317e fix quota of model provider 2024-11-12 16:57:22 +08:00
twwu
2573950f88 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-12 16:48:28 +08:00
twwu
2ba38c6c45 feat: add marketplace-divider-bg color variable for dark and light themes 2024-11-12 16:48:24 +08:00
Joel
07edda8a85 feat: add new marketplace env 2024-11-12 15:56:03 +08:00
snake
81116a679d Update deploy-dev.yml for print context var 2024-11-12 15:55:19 +08:00
twwu
7791d290c7 refactor: update AudioPlayer styles with CSS variables and improve VideoGallery rendering 2024-11-12 15:49:00 +08:00
Joel
8203b23df2 feat: install bundle struct 2024-11-12 15:48:00 +08:00
AkaraChen
e175ad9963 fix: sse post no token 2024-11-12 14:41:09 +08:00
Joel
d4c9c76454 chore: mask the debug key 2024-11-12 14:31:15 +08:00
AkaraChen
a059660ed8 fix: sse post no token 2024-11-12 14:24:18 +08:00
Yi
20357beda4 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-11-12 13:32:26 +08:00
Joel
7e39565fd2 feat: handle on update show update modal 2024-11-12 11:48:55 +08:00
Yeuoly
a37e41de99 fix: add pnpm lock 2024-11-11 21:04:15 +08:00
Yeuoly
0a9dd367f6 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-11 21:01:23 +08:00
Yeuoly
9a69d03fbe feat: add icon and labels to plugin install task 2024-11-11 20:59:31 +08:00
takatost
1d2118fc5d fix: hosted moderation 2024-11-11 20:31:11 +08:00
takatost
bc0724b499 chore: fix typo 2024-11-11 19:50:39 +08:00
StyleZhang
27f794e197 feat: plugin task 2024-11-11 18:17:58 +08:00
Yi
a8e8e36756 chore: update the upgrade button 2024-11-11 18:00:44 +08:00
Yi
dbc10425c8 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-11-11 17:21:37 +08:00
Yi
810443c511 chore: update the upgrade button and add premium badge component 2024-11-11 17:21:25 +08:00
Joel
f47b5ce63a chore: install plugin by local use use query 2024-11-11 14:58:17 +08:00
Yeuoly
e3723f65f8 fix: temp fix for seucrity issues 2024-11-11 14:10:57 +08:00
Yeuoly
ba2d340109 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-11 14:06:39 +08:00
Yeuoly
5cdbfe2f41 Merge branch 'main' into fix/chore-fix 2024-11-11 14:00:53 +08:00
Yeuoly
2a87f61515 fix: avoid empty plugin entity 2024-11-11 13:32:03 +08:00
Yeuoly
5fd82084f9 fix: avoid empty plugin entity 2024-11-11 13:30:11 +08:00
StyleZhang
822c18cb76 fix: credentials: 2024-11-11 12:27:58 +08:00
StyleZhang
66b08e653e fix: credentials: 2024-11-11 12:27:13 +08:00
JzoNg
5e81150b22 useQuery for endpoints 2024-11-09 14:44:48 +08:00
JzoNg
1e62768eed useQuery in action list 2024-11-09 12:51:10 +08:00
JzoNg
59a9235041 useQuery for model list 2024-11-09 12:12:10 +08:00
takatost
0b2b6a3ef3 Merge branch 'refs/heads/fix/chore-fix' into dev/plugin-deploy 2024-11-08 23:11:02 +08:00
takatost
f0637ba332 fix: create basic app causing internal error when default model is not exist 2024-11-08 23:09:52 +08:00
JzoNg
f85ff9ef78 Merge branch 'feat/plugins' into dev/plugin-deploy 2024-11-08 21:34:59 +08:00
JzoNg
f2bf2e4470 fix style of provider added card 2024-11-08 21:32:46 +08:00
takatost
48fac5187a Merge branch 'refs/heads/fix/chore-fix' into dev/plugin-deploy 2024-11-08 19:24:44 +08:00
takatost
115c9486c3 fix hosted issues 2024-11-08 19:23:49 +08:00
Joel
c77b38b97d chore: install from marketplace 2024-11-08 18:29:54 +08:00
StyleZhang
33349191e9 marketplace usemutation 2024-11-08 18:21:58 +08:00
Yeuoly
1a5c2d1d58 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-08 17:27:35 +08:00
Yeuoly
8b5231b7ee fix: invalid key of marketplace response 2024-11-08 17:27:16 +08:00
AkaraChen
d4f7ebfd2e feat: refactor http client 2024-11-08 17:21:55 +08:00
Yeuoly
c34970c631 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-08 17:21:06 +08:00
Yeuoly
38cae29757 fix: wrap marketplace apis with try catch 2024-11-08 17:20:54 +08:00
JzoNg
ebdf72fffc check update 2024-11-08 17:01:49 +08:00
JzoNg
1f1c61541e install from settings 2024-11-08 16:33:00 +08:00
JzoNg
f70c23dd7a endpoints api 2024-11-08 16:19:00 +08:00
JzoNg
f498686c3a model list style fix 2024-11-08 16:19:00 +08:00
StyleZhang
d13169934d fix: marketplace i18n 2024-11-08 16:14:29 +08:00
Joel
324437b3f1 feat: mutation permersions 2024-11-08 16:12:04 +08:00
twwu
c6a6c53084 chore: update theme var define 2024-11-08 15:26:59 +08:00
Joel
edc2fe050a chore: debug info use query 2024-11-08 15:10:06 +08:00
Joel
6fcebf3ecd chore: remove log 2024-11-08 14:26:52 +08:00
Joel
b754bf80ae fix: custom tools not show 2024-11-08 14:24:28 +08:00
Joel
5d7c527702 merge feat/plugins 2024-11-08 13:57:34 +08:00
Joel
a9de7f24a2 merge main 2024-11-08 13:55:39 +08:00
Yeuoly
14a723a2a4 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-08 13:48:23 +08:00
Yeuoly
7a2b2a04c9 Merge branch 'main' into fix/chore-fix 2024-11-08 13:47:24 +08:00
twwu
6759c6d5e6 Revert "feat: add gray label color variables for dark and light themes"
This reverts commit a75cef2c3b.
2024-11-08 13:42:38 +08:00
Yeuoly
61cf6e1c7b Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-08 13:39:45 +08:00
JzoNg
920d6d6882 fix credentials of action list 2024-11-08 12:32:02 +08:00
JzoNg
2511968cb4 fix action list 2024-11-08 12:32:02 +08:00
JzoNg
f684e1c12e provider compatible in logs 2024-11-08 12:32:02 +08:00
JzoNg
be75a1e432 provider compatible in moderation 2024-11-08 12:32:02 +08:00
JzoNg
5a679ed396 provider compatible in model_config 2024-11-08 12:32:02 +08:00
JzoNg
0cfd676fd6 provider compatible 2024-11-08 12:32:02 +08:00
twwu
d997499ecf Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-08 11:33:42 +08:00
twwu
4d3ffbb6f0 fix: update repository URL format in plugin action component 2024-11-08 11:33:35 +08:00
twwu
a710858d09 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-08 11:32:34 +08:00
twwu
a75cef2c3b feat: add gray label color variables for dark and light themes 2024-11-08 11:31:48 +08:00
Yi
392db19ea2 chore: update the update plugin steps 2024-11-08 11:08:40 +08:00
Yi
7cb6039833 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-11-07 18:22:08 +08:00
Yi
e041a9e418 chore: upgrade button styling 2024-11-07 18:21:32 +08:00
Joel
281c6dc337 merge 2024-11-07 17:44:54 +08:00
-LAN-
7d7ade26ce fix(remote-files): fallback to get when remote server not support head method (#10370) 2024-11-07 17:39:52 +08:00
-LAN-
6aa2af215b refactor(iteration): introduce specific exceptions for iteration errors (#10366) 2024-11-07 17:39:52 +08:00
-LAN-
598d307afd refactor(knowledge-retrieval): improve error handling with custom exceptions (#10385) 2024-11-07 17:39:52 +08:00
-LAN-
39fdcfd7e9 refactor(tool-node): introduce specific exceptions for tool node errors (#10357) 2024-11-07 17:39:51 +08:00
-LAN-
47f638e5aa refactor(question_classifier): improve error handling with custom exceptions (#10365) 2024-11-07 17:39:51 +08:00
luckylhb90
03b57d1f0a fixed: web api remote urls error (#10383)
Co-authored-by: hobo.l <hobo.l@binance.com>
2024-11-07 17:39:51 +08:00
powerfool
99c84c423e Adjusted docker manifests and environment variables for OceanBase vector database (#10395) 2024-11-07 17:39:51 +08:00
omr
cc2cc56f25 fix typo: mMaximum -> Maximum (#10389) 2024-11-07 17:39:50 +08:00
非法操作
393885ee16 fix: remove duplicated category “recommended” (#10375) 2024-11-07 17:39:50 +08:00
Matsuda
9143d460fa fix(model_runtime): remove vision from features for Claude 3.5 Haiku (#10360) 2024-11-07 17:39:49 +08:00
Infinitnet
c0ff0cf7cf fix: remove unsupported vision in OpenRouter Haiku 3.5 (#10364) 2024-11-07 17:39:49 +08:00
Bowen Liang
9c90d98027 chore(ci): bring back poetry cache to speed up CI jobs (#10347) 2024-11-07 17:39:48 +08:00
Bowen Liang
0d74466f45 chore: lazy import sagemaker (#10342) 2024-11-07 17:39:48 +08:00
comfuture
d2e293b9be chore: update translation for 'account' from '계좌' to '계정' (#10350) 2024-11-07 17:39:48 +08:00
-LAN-
8fae321b6a chore(ci): separate vector store tests into new workflow (#10354) 2024-11-07 17:39:47 +08:00
-LAN-
a2b42c9431 fix(api): remove fixed source attribute from FileApi (#10353) 2024-11-07 17:39:47 +08:00
Nam Vu
0a4b256b5a feat: support png, gif, webp (#7947)
Co-authored-by: xuanson9699 <84961581+xuanson9699@users.noreply.github.com>
2024-11-07 17:39:47 +08:00
Chenhe Gu
9f7124a79d Update README.md (#10332) 2024-11-07 17:39:46 +08:00
方程
7a217534d1 Gitee AI tools (#10314) 2024-11-07 17:39:46 +08:00
Summer-Gu
a9ed0f0b42 feat: The SSRF request timeout configuration item is added (#10292) 2024-11-07 17:39:46 +08:00
Infinitnet
545d2b2622 feat: add support for anthropic/claude-3-5-haiku through OpenRouter (#10331) 2024-11-07 17:39:45 +08:00
Benjamin
f114da4e81 feat(vannaai): add base_url configuration (#10294) 2024-11-07 17:39:45 +08:00
-LAN-
f4e3e3fc19 docs: remove the TOC part (#10324) 2024-11-07 17:39:45 +08:00
非法操作
1277941821 fix: special prompt not work for comfyUI tool (#10307) 2024-11-07 17:39:45 +08:00
-LAN-
f500e6cf5b chore: update version to 0.11.0 across all relevant files (#10278) 2024-11-07 17:39:44 +08:00
Novice
a3b71830d0 fix: iteration none output error (#10295) 2024-11-07 17:39:44 +08:00
-LAN-
13b7e18a50 fix(http_request): improve parameter initialization and reorganize tests (#10297) 2024-11-07 17:39:44 +08:00
Matsuda
5f4bb12a1a fix typo: writeOpner to writeOpener (#10290) 2024-11-07 17:39:43 +08:00
pinsily
781e8e1a4a fix: handle KeyError when accessing rules in CleanProcessor.clean (#10258) 2024-11-07 17:39:43 +08:00
eux
c721617e19 fix: borken faq url in CONTRIBUTING.md (#10275) 2024-11-07 17:39:43 +08:00
非法操作
6b51e81de1 feat: add xAI model provider (#10272) 2024-11-07 17:39:43 +08:00
Matsuda
736719745c feat(model_runtime): add new model 'claude-3-5-haiku-20241022' (#10285) 2024-11-07 17:39:43 +08:00
Matsuda
e0e4a6f819 fix(model_runtime): fix wrong max_tokens for Claude 3.5 Haiku on Amazon Bedrock (#10286) 2024-11-07 17:39:42 +08:00
-LAN-
6ab6b9cc40 feat(model): add validation for custom disclaimer length (#10287) 2024-11-07 17:39:42 +08:00
-LAN-
52eb18937e fix(node): correct file property name in function switch (#10284) 2024-11-07 17:39:42 +08:00
NFish
aab1ab692a refactor the logic of refreshing access_token (#10068) 2024-11-07 17:39:40 +08:00
github-actions[bot]
3e7f38d904 chore: translate i18n files (#10273)
Co-authored-by: laipz8200 <16485841+laipz8200@users.noreply.github.com>
Co-authored-by: crazywoola <100913391+crazywoola@users.noreply.github.com>
2024-11-07 17:39:15 +08:00
Benjamin
94c5e36334 Updates: Add mplfonts library for customizing matplotlib fonts and Va… (#9903) 2024-11-07 17:39:14 +08:00
Novice
baaa3ae02c feat: Iteration node support parallel mode (#9493) 2024-11-07 17:39:09 +08:00
GeorgeCaoJ
623b27583b fix(workflow): handle else condition branch addition error in if-else node (#10257) 2024-11-07 17:38:39 +08:00
-LAN-
93e9aeb4e9 feat(document_extractor): support tool file in document extractor (#10217) 2024-11-07 17:38:39 +08:00
Matsuda
391ad7734e feat: support Claude 3.5 Haiku on Amazon Bedrock (#10265) 2024-11-07 17:38:38 +08:00
-LAN-
c5422af400 refactor(parameter_extractor): implement custom error classes (#10260) 2024-11-07 17:38:37 +08:00
guogeer
65a04ee0be fix: buitin tool aippt (#10234)
Co-authored-by: jinqi.guo <jinqi.guo@ubtrobot.com>
2024-11-07 17:38:37 +08:00
-LAN-
84c35aef6c fix(validation): allow to use 0 in the inputs form (#10255) 2024-11-07 17:38:37 +08:00
-LAN-
c2b4845719 chore(Dockerfile): upgrade zlib arm64 (#10244) 2024-11-07 17:38:37 +08:00
方程
cd0f10567f Using a dedicated interface to obtain the token credential for the gitee.ai provider (#10243) 2024-11-07 17:38:36 +08:00
-LAN-
454b755c6b feat(workflow): add configurable workflow file upload limit (#10176)
Co-authored-by: JzoNg <jzongcode@gmail.com>
2024-11-07 17:38:35 +08:00
shisaru292
352c1fc370 fix: missing working directory parameter in script (#10226) 2024-11-07 17:38:35 +08:00
-LAN-
181eb6038f refactor(list_operator): replace ValueError with InvalidKeyError (#10222) 2024-11-07 17:38:34 +08:00
-LAN-
c32cbeb29a refactor(workflow): introduce specific error handling for LLM nodes (#10221) 2024-11-07 17:38:34 +08:00
-LAN-
62f8c875c8 refactor(http_request): add custom exception handling for HTTP request nodes (#10219) 2024-11-07 17:38:33 +08:00
-LAN-
baed53bbfa refactor(workflow): introduce specific exceptions for code validation (#10218) 2024-11-07 17:38:32 +08:00
-LAN-
565a0d992a chore(llm_node): remove unnecessary type ignore for context assignment (#10216) 2024-11-07 17:38:32 +08:00
Jyong
e90a06a7b7 fix the ssrf of docx file extractor external images (#10237) 2024-11-07 17:38:31 +08:00
Hanqing Zhao
5a0b22dbd4 Modify translation (#10213) 2024-11-07 17:38:30 +08:00
Jiang
31445c3782 Add Lindorm as a VDB choice (#10202)
Co-authored-by: jiangzhijie <jiangzhijie.jzj@alibaba-inc.com>
2024-11-07 17:38:30 +08:00
crazywoola
8e6f5f4bb0 Fix/10199 application error a client side exception has occurred see the browser console for more information (#10211) 2024-11-07 17:38:29 +08:00
-LAN-
e259b360c2 refactor(validation): improve input validation logic (#10175) 2024-11-07 17:38:29 +08:00
-LAN-
762dec2dc4 chore(list_operator): refine exception handling for error specificity (#10206) 2024-11-07 17:38:28 +08:00
-LAN-
ada7f5c30f fix(document_extractor): update base exception class (#10208) 2024-11-07 17:38:28 +08:00
Kota-Yamaguchi
6b965eaea3 Feat : add LLM model indicator in prompt generator (#10187) 2024-11-07 17:38:27 +08:00
Xiao Ley
ea67bc1166 chore: enable vision support for models in OpenRouter that should have supported vision (#10191) 2024-11-07 17:38:26 +08:00
Kota-Yamaguchi
01e8f6066a chore : code generator preview hint (#10188) 2024-11-07 17:38:26 +08:00
zxhlyh
39effd350e fix: webapp upload file (#10195) 2024-11-07 17:38:25 +08:00
-LAN-
00bfb35759 fix(api): replace current_user with end_user in file upload (#10194) 2024-11-07 17:38:25 +08:00
-LAN-
101d9798f0 feat(document_extractor): integrate unstructured API for PPTX extraction (#10180) 2024-11-07 17:38:24 +08:00
-LAN-
ba48754be6 fix(tools): suppress RuntimeWarnings in podcast audio generator (#10182) 2024-11-07 17:38:24 +08:00
Cling_o3
d963df32b9 [fix] fix the bug that modify document name not effective (#10154) 2024-11-07 17:38:23 +08:00
-LAN-
67ce763377 fix(workflow model): ensure consistent timestamp updating (#10172) 2024-11-07 17:38:23 +08:00
jiangbo721
a32c0ef43c fix: Cannot find declaration to go to CLEAN_DAY_SETTING (#10157)
Co-authored-by: 刘江波 <liujiangbo1@xiaomi.com>
2024-11-07 17:38:22 +08:00
Lawrence Li
6e03c10285 feat: add gpustack model provider (#10158) 2024-11-07 17:38:21 +08:00
-LAN-
8f14c422a7 refactor(tools): Avoid warnings. (#10161) 2024-11-07 17:38:20 +08:00
-LAN-
07787366cd refactor(migration/model): update column types for workflow schema (#10160) 2024-11-07 17:38:20 +08:00
-LAN-
8f2d3b6743 Feat/add-remote-file-upload-api (#9906) 2024-11-07 17:38:19 +08:00
zxhlyh
e7bc863f26 fix: upload remote image preview (#9952) 2024-11-07 17:38:19 +08:00
Jyong
1d411e195a clean un-allowed special charters when doing indexing estimate (#10153) 2024-11-07 17:38:19 +08:00
-LAN-
2a7ae6b0df refactor(service): handle unsupported DSL version with warning (#10151) 2024-11-07 17:38:18 +08:00
larcane97
8f8a3f4318 Add VESSL AI OpenAI API-compatible model provider and LLM model (#9474)
Co-authored-by: moon <moon@vessl.ai>
2024-11-07 17:38:18 +08:00
Kota-Yamaguchi
4b89dba3a5 feat: synchronize input/output variables in the panel with generated code by the code generator (#10150) 2024-11-07 17:38:18 +08:00
Zixuan Cheng
19c0d1fbf8 Refined README for better reading experience. (#10143) 2024-11-07 17:38:17 +08:00
Coal Pigeon
94cd4912e1 add llm: ernie-4.0-turbo-128k of wenxin (#10135)
Co-authored-by: Pigeon姚宏锋 <pigeon.yhf@galaxyoversea.com>
2024-11-07 17:38:17 +08:00
Shili Cao
602f75bb30 fix: avoid unexpected error when create knowledge base with baidu vector database and wenxin embedding model (#10130) 2024-11-07 17:38:15 +08:00
llinvokerl
c2810de952 fix: bar chart issue with duplicate x-axis labels being incorrectly ignored (#10134)
Co-authored-by: liusurong.lsr <liusurong.lsr@alibaba-inc.com>
2024-11-07 17:38:14 +08:00
Jyong
1b645c1cc9 fix issue: query is none when doing retrieval (#10129) 2024-11-07 17:38:14 +08:00
zxhlyh
ae3482e0b4 Fix/rerank validation issue (#10131)
Co-authored-by: Yi <yxiaoisme@gmail.com>
2024-11-07 17:38:14 +08:00
Jyong
76c265f781 Feat/update knowledge api url (#10102)
Co-authored-by: nite-knite <nkCoding@gmail.com>
2024-11-07 17:38:12 +08:00
omr
b1946c60d8 fix: optimize unique document filtering with set (#10082) 2024-11-07 17:38:12 +08:00
-LAN-
c1c13cf828 fix(Dockerfile): conditionally install zlib1g based on architecture (#10118) 2024-11-07 17:38:11 +08:00
Hash Brown
e4a48e28e5 fix: log detail panel not showing any message when total count greate… (#10119) 2024-11-07 17:38:11 +08:00
Jyong
67efcbd6bb fix issue: update document segment setting failed (#10107) 2024-11-07 17:38:11 +08:00
Nam Vu
7466061e5a fix: Version '1:1.3.dfsg+really1.3.1-1' for 'zlib1g' was not found (#10096) 2024-11-07 17:38:10 +08:00
-LAN-
b7534b764d feat(app_dsl_service): enhance error handling and DSL version management (#10108) 2024-11-07 17:38:09 +08:00
非法操作
eb335ed464 chore: save uploaded file extension as lower case (#10111) 2024-11-07 17:38:09 +08:00
-LAN-
4d9e7c1884 refactor(version): simplify version comparison logic (#10109) 2024-11-07 17:38:09 +08:00
beginnerZhang
8f7cac6bde fix: view logs in prompt, no response when clicked (#10093)
Co-authored-by: zhanganguo <zhanganguo@lixiang.com>
2024-11-07 17:38:08 +08:00
非法操作
d4608f0571 chore: remove an unnecessary link (#10088) 2024-11-07 17:38:08 +08:00
非法操作
9f27b5bb12 feat: enhance comfyui workflow (#10085) 2024-11-07 17:38:07 +08:00
AkaraChen
fb9c54e35f build: update docker login action (#10050) 2024-11-07 17:38:07 +08:00
Kota-Yamaguchi
dea45682bc chore: update type definition to resolve lint error in Base usage at text-editor.tsx (#10083) 2024-11-07 17:38:06 +08:00
Bowen Liang
a0abd5d077 improve: significantly speed up the server launching time by async preloading tool providers (#9146) 2024-11-07 17:38:05 +08:00
Charlie.Wei
924dbc128d fix azure chatgpt o1 parameter error (#10067) 2024-11-07 17:38:05 +08:00
crazywoola
b76aa11919 Revert "chore: improve validation and handler of logging timezone with TimezoneName" (#10077) 2024-11-07 17:38:05 +08:00
sacryu
7971efd23e fix the typos in the hit testing template (#10072) 2024-11-07 17:38:04 +08:00
JasonVV
b8c2e5359b Fixed the issue where recall the knowledge base in the iteration of the workflow and report errors when executing (#10060) 2024-11-07 17:38:04 +08:00
Hiroshi Fujita
952847ed29 chore: Set file size limits for video and audio uploads from docker env (#10063) 2024-11-07 17:38:03 +08:00
Fog3211
4e4a8a327b fix: prevent onChange during IME composition (#10059) 2024-11-07 17:38:03 +08:00
22mSqRi
8d1591e5d5 fix: fix poetry install command in devcontainer (#9507) 2024-11-07 17:38:03 +08:00
-LAN-
4b8896e034 fix(workflow): refine variable type checks in LLMNode (#10051) 2024-11-07 17:38:02 +08:00
非法操作
c2d3464a17 chore: mount config file of sandbox (#8576) 2024-11-07 17:38:02 +08:00
zhuhao
0886c6f224 fix: resolve the incorrect model name of hunyuan-standard-256k (#10052) 2024-11-07 17:38:01 +08:00
zhuhao
1ee4c13758 chore: use dify_config.TIDB_SPEND_LIMIT instead of constant value (#10038) 2024-11-07 17:38:01 +08:00
郭伟伟
c293aceec1 feat: /conversations api response add 'update_at' field,and update api docs add sort_by parameter (#10043) 2024-11-07 17:38:01 +08:00
zhuhao
4d5752fc94 feat: add YAML type in document extractor node (#9997) 2024-11-07 17:38:00 +08:00
Xiao Ley
c615ed57b9 add PROMPT_GENERATION_MAX_TOKENS and CODE_GENERATION_MAX_TOKENS in docker enviromment (#10040) 2024-11-07 17:38:00 +08:00
Yeuoly
fe677cc5f9 Merge branch 'main' into fix/chore-fix 2024-11-07 17:06:29 +08:00
twwu
020d4baf92 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-07 16:52:26 +08:00
twwu
3f8a10613d refactor: remove unused fetchInstalledPluginList function and integrate useInstalledPluginList hook 2024-11-07 16:52:22 +08:00
AkaraChen
53fa13f007 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-07 16:44:46 +08:00
AkaraChen
d00e1067bf fix: develop page docs style 2024-11-07 16:44:05 +08:00
Joel
2dd9c64d34 chore: use query 2024-11-07 16:42:44 +08:00
AkaraChen
b7c40579b2 build: update tailwind 2024-11-07 16:41:35 +08:00
twwu
c7f8a0fc7b Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-07 16:06:13 +08:00
twwu
de24d9c145 fix: handle empty fetched releases and update locale usage in plugin item 2024-11-07 16:06:08 +08:00
AkaraChen
6357e1516e build: update react-hook-form 2024-11-07 15:47:07 +08:00
StyleZhang
b83dc5ab99 fix: marketplace 2024-11-07 15:37:39 +08:00
Yi
65285965b6 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-11-07 15:31:42 +08:00
Yi
035c9eb147 fix: propagation from closing tag in filters 2024-11-07 15:31:11 +08:00
Joel
91b3aec292 feat: add use tools 2024-11-07 15:24:17 +08:00
AkaraChen
d3a9747bbd build: update @floating-ui/react 2024-11-07 15:22:00 +08:00
StyleZhang
6a99fab92f fix: marketplace 2024-11-07 15:07:07 +08:00
Yi
2a590f6d2b Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-11-07 13:42:45 +08:00
Yi
117b0f20dd chore: update the plugin install dropdown styling 2024-11-07 13:42:34 +08:00
StyleZhang
c445f747b7 fix: prompt editor 2024-11-07 12:11:26 +08:00
AkaraChen
8ed0963c6b Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-07 11:46:32 +08:00
Yi
6c47e0b5d1 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-11-07 11:37:21 +08:00
Yi
e99e87269e chore: update the selectPackage component 2024-11-07 11:37:05 +08:00
AkaraChen
0a1319548a build: update react markdown
build: update react markdown

build: update react markdown
2024-11-07 11:34:55 +08:00
AkaraChen
b1242ba1ac build: init @tanstack/react-query 2024-11-07 09:44:36 +08:00
twwu
fde0e6c7f9 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-06 18:43:31 +08:00
twwu
92153328ea feat: add loading state for installed plugin list in context and update PluginsPanel to display loading indicator 2024-11-06 18:43:27 +08:00
Yeuoly
56f2464a4f Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-06 18:30:02 +08:00
Joel
e66ba6ffdd chore: fill repo url 2024-11-06 18:13:15 +08:00
Yeuoly
28c9ec3f4f feat: support fetch tool provider info 2024-11-06 17:30:50 +08:00
Yeuoly
6baa98f166 feat: support app-selector, model-selector and tool-selector as parameters 2024-11-06 17:13:05 +08:00
twwu
a7e320dc25 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-06 16:58:56 +08:00
twwu
5008d9f4a0 feat: add onSuccess callback to InstallFromGitHub and update plugin list on install actions 2024-11-06 16:58:52 +08:00
Yi
912f84777b Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-11-06 16:49:29 +08:00
Yi
4c0e4e490a chore: update the 'Update plugin from GitHub' 2024-11-06 16:49:16 +08:00
Joel
306843fe6a chore: plugin info 2024-11-06 16:42:32 +08:00
twwu
b6a4af4041 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-06 16:18:25 +08:00
twwu
cce39b85e9 feat: enhance plugin filtering with tags support 2024-11-06 16:18:18 +08:00
Joel
057d380119 feat: add install model plugin 2024-11-06 15:57:50 +08:00
Joel
4cf9ff6132 chore: remove log 2024-11-06 15:44:49 +08:00
Joel
4cfbcd9c79 feat: add install 2024-11-06 15:42:48 +08:00
StyleZhang
fcde5b5c9e fix: detail 2024-11-06 15:37:12 +08:00
StyleZhang
21b3703bd8 fix: i18n 2024-11-06 15:23:38 +08:00
StyleZhang
9025e85ca5 locale 2024-11-06 15:00:37 +08:00
StyleZhang
bc43e3a9fe card locale 2024-11-06 14:52:47 +08:00
StyleZhang
319a54aa2f i18n 2024-11-06 14:37:20 +08:00
StyleZhang
7c2ab21c9c i18n 2024-11-06 11:55:19 +08:00
twwu
0d08b6cf51 fix: enhance plugin installation and update handling 2024-11-06 09:50:05 +08:00
Yeuoly
e9d69f020a feat: cast files into correct type while invoking 2024-11-05 20:30:13 +08:00
Novice
3c89d45a2d fix: iteration none output error (#10295) 2024-11-05 20:30:13 +08:00
-LAN-
baab81714e fix(http_request): improve parameter initialization and reorganize tests (#10297) 2024-11-05 20:30:13 +08:00
Matsuda
507bb3549a fix typo: writeOpner to writeOpener (#10290) 2024-11-05 20:30:13 +08:00
pinsily
2d1e5fb4e0 fix: handle KeyError when accessing rules in CleanProcessor.clean (#10258) 2024-11-05 20:30:12 +08:00
eux
b9198639e2 fix: borken faq url in CONTRIBUTING.md (#10275) 2024-11-05 20:30:12 +08:00
非法操作
43c7739b88 feat: add xAI model provider (#10272) 2024-11-05 20:30:12 +08:00
Matsuda
f65d577f54 fix(model_runtime): fix wrong max_tokens for Claude 3.5 Haiku on Amazon Bedrock (#10286) 2024-11-05 20:30:00 +08:00
-LAN-
b88145096f feat(model): add validation for custom disclaimer length (#10287) 2024-11-05 20:30:00 +08:00
-LAN-
33219e850a fix(node): correct file property name in function switch (#10284) 2024-11-05 20:30:00 +08:00
NFish
3040d538f7 refactor the logic of refreshing access_token (#10068) 2024-11-05 20:30:00 +08:00
github-actions[bot]
4e1af81e11 chore: translate i18n files (#10273)
Co-authored-by: laipz8200 <16485841+laipz8200@users.noreply.github.com>
Co-authored-by: crazywoola <100913391+crazywoola@users.noreply.github.com>
2024-11-05 20:30:00 +08:00
Benjamin
56e19fd8f5 Updates: Add mplfonts library for customizing matplotlib fonts and Va… (#9903) 2024-11-05 20:30:00 +08:00
Novice
d330d31ee5 feat: Iteration node support parallel mode (#9493) 2024-11-05 20:29:59 +08:00
GeorgeCaoJ
0858108423 fix(workflow): handle else condition branch addition error in if-else node (#10257) 2024-11-05 20:29:59 +08:00
-LAN-
2cd976846a feat(document_extractor): support tool file in document extractor (#10217) 2024-11-05 20:29:59 +08:00
Matsuda
5d2c88ef59 feat: support Claude 3.5 Haiku on Amazon Bedrock (#10265) 2024-11-05 20:29:59 +08:00
-LAN-
fe3cde973e refactor(parameter_extractor): implement custom error classes (#10260) 2024-11-05 20:29:59 +08:00
-LAN-
794f495ef2 fix(validation): allow to use 0 in the inputs form (#10255) 2024-11-05 20:29:32 +08:00
-LAN-
0dda682033 chore(Dockerfile): upgrade zlib arm64 (#10244) 2024-11-05 20:29:31 +08:00
方程
01d8d10f1c Using a dedicated interface to obtain the token credential for the gitee.ai provider (#10243) 2024-11-05 20:29:12 +08:00
-LAN-
c711c5e36e feat(workflow): add configurable workflow file upload limit (#10176)
Co-authored-by: JzoNg <jzongcode@gmail.com>
2024-11-05 20:29:09 +08:00
shisaru292
1e27557865 fix: missing working directory parameter in script (#10226) 2024-11-05 20:28:29 +08:00
-LAN-
2d9632d8b9 refactor(list_operator): replace ValueError with InvalidKeyError (#10222) 2024-11-05 20:28:29 +08:00
-LAN-
7e42de1e7b refactor(workflow): introduce specific error handling for LLM nodes (#10221) 2024-11-05 20:28:29 +08:00
-LAN-
bd674d27be refactor(http_request): add custom exception handling for HTTP request nodes (#10219) 2024-11-05 20:28:29 +08:00
-LAN-
5735761920 refactor(workflow): introduce specific exceptions for code validation (#10218) 2024-11-05 20:28:29 +08:00
-LAN-
405b704f02 chore(llm_node): remove unnecessary type ignore for context assignment (#10216) 2024-11-05 20:28:29 +08:00
Jyong
f38abaaa6a fix the ssrf of docx file extractor external images (#10237) 2024-11-05 20:28:28 +08:00
Hanqing Zhao
c8a5fee622 Modify translation (#10213) 2024-11-05 20:28:28 +08:00
Jiang
fe1c0ac602 Add Lindorm as a VDB choice (#10202)
Co-authored-by: jiangzhijie <jiangzhijie.jzj@alibaba-inc.com>
2024-11-05 20:28:28 +08:00
crazywoola
e79c3e4531 Fix/10199 application error a client side exception has occurred see the browser console for more information (#10211) 2024-11-05 20:28:28 +08:00
-LAN-
3ea3df7189 refactor(validation): improve input validation logic (#10175) 2024-11-05 20:28:28 +08:00
-LAN-
b01e7d778e chore(list_operator): refine exception handling for error specificity (#10206) 2024-11-05 20:28:28 +08:00
-LAN-
7c45859594 fix(document_extractor): update base exception class (#10208) 2024-11-05 20:28:27 +08:00
Kota-Yamaguchi
aa9fd76072 Feat : add LLM model indicator in prompt generator (#10187) 2024-11-05 20:28:27 +08:00
Kota-Yamaguchi
e7d947379f chore : code generator preview hint (#10188) 2024-11-05 20:28:17 +08:00
zxhlyh
8cd386f2c1 fix: webapp upload file (#10195) 2024-11-05 20:28:17 +08:00
-LAN-
987e1b9ced fix(api): replace current_user with end_user in file upload (#10194) 2024-11-05 20:28:17 +08:00
-LAN-
81a77d0623 feat(document_extractor): integrate unstructured API for PPTX extraction (#10180) 2024-11-05 20:28:17 +08:00
Cling_o3
ac1f93e3d5 [fix] fix the bug that modify document name not effective (#10154) 2024-11-05 20:27:58 +08:00
-LAN-
0d5c0b4fe4 fix(workflow model): ensure consistent timestamp updating (#10172) 2024-11-05 20:27:57 +08:00
jiangbo721
d1c480a7d8 fix: Cannot find declaration to go to CLEAN_DAY_SETTING (#10157)
Co-authored-by: 刘江波 <liujiangbo1@xiaomi.com>
2024-11-05 20:27:57 +08:00
Lawrence Li
007b561e32 feat: add gpustack model provider (#10158) 2024-11-05 20:27:57 +08:00
Yi
61a70e7a71 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-11-05 17:53:03 +08:00
Yi
bde1261b8c chore: update installFromGitHub component 2024-11-05 17:52:47 +08:00
StyleZhang
08bb6bf858 fix: tags 2024-11-05 17:35:47 +08:00
twwu
1003190dc0 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-05 16:54:57 +08:00
twwu
4c516a50b8 fix: update type from InstalledPlugin to PluginDetail in detail-header component 2024-11-05 16:53:54 +08:00
Joel
8058a1dbe4 feat: handle update 2024-11-05 16:47:26 +08:00
Yi
8533ded335 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-11-05 16:36:55 +08:00
twwu
1a547b0db9 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-05 16:25:38 +08:00
twwu
0b90625e57 feat: integrate GitHub API for plugin version check and add access token support 2024-11-05 16:25:20 +08:00
Joel
e989c1f3aa feat: fill update install payload 2024-11-05 16:04:52 +08:00
Joel
da15a25cf5 feat: add update from github modal content 2024-11-05 15:27:08 +08:00
Joel
43254ceeb0 chore: temp types 2024-11-05 15:22:48 +08:00
Yi
faf550164d Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-11-05 15:21:54 +08:00
Yi
1a4234347a chore: update the installFromGitHub logic 2024-11-05 15:21:45 +08:00
Joel
85947efcfa temp: change payload types 2024-11-05 15:21:07 +08:00
Joel
474ea97fc7 feat: add update to modal context 2024-11-05 15:11:55 +08:00
StyleZhang
a3becde6d8 feat: plugin tags 2024-11-05 15:07:24 +08:00
Yi
c40544a134 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-11-05 11:41:03 +08:00
Yi
4028bb4f58 chore: update installPluginFromGitHub component 2024-11-05 11:40:52 +08:00
twwu
52268460a1 fix: update dependency in Empty component to improve rendering logic 2024-11-05 11:19:04 +08:00
twwu
b64298c458 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-11-05 11:05:20 +08:00
twwu
16dee11589 feat: add Empty component to installed plugin list 2024-11-05 11:05:14 +08:00
Yi
691dbf9d17 chore: update plugin from GitHub 2024-11-05 11:02:57 +08:00
JzoNg
ebebbb684b endpoints list 2024-11-02 15:36:38 +08:00
JzoNg
cee51ac084 need author judgement 2024-11-02 15:36:38 +08:00
JzoNg
ef00ad0417 action list 2024-11-02 15:36:38 +08:00
JzoNg
c37615cd33 plugin detail delete handler 2024-11-02 15:36:38 +08:00
JzoNg
a387cfbc9a model list in plugin detail 2024-11-02 15:36:38 +08:00
JzoNg
04fdb4af0f plugin header operation 2024-11-02 15:36:38 +08:00
JzoNg
57f9a41e7f plugin detail selecting 2024-11-02 15:36:38 +08:00
JzoNg
eb8b827906 verified tag 2024-11-02 15:36:38 +08:00
takatost
c100f24f7d compatible model daemon request exception 2024-11-01 19:20:26 -07:00
Joel
99a9bf6d56 feat: support search from marketplace list 2024-11-01 18:36:24 +08:00
takatost
d92cb994a9 fix voice list 2024-11-01 01:56:15 -07:00
Yeuoly
02a296bbec Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-01 16:55:45 +08:00
Yeuoly
413326905e rebase migrations 2024-11-01 16:55:07 +08:00
Yi
ceae69b773 chore: update the workspace selector 2024-11-01 16:48:40 +08:00
Yeuoly
7cea6c1713 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-01 16:46:40 +08:00
Yeuoly
5605ff9803 fix voice list 2024-11-01 16:42:32 +08:00
Yeuoly
84b7a4607a fix: setup_required 2024-11-01 16:28:17 +08:00
Yeuoly
10cc4e758c Merge branch 'main' into fix/chore-fix 2024-11-01 16:23:04 +08:00
Joel
3c8548c562 feat: create tool model 2024-11-01 16:14:01 +08:00
StyleZhang
8874837dc3 feat: plugin tasks 2024-11-01 16:08:31 +08:00
Yi
40e171c2c6 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-11-01 15:40:06 +08:00
Yi
824ed7d6c2 chore: plugin button 2024-11-01 15:39:55 +08:00
Yeuoly
7e7d02ee15 fix: missing 'follow_redirects' argument while download plugin packages 2024-11-01 15:39:36 +08:00
Yeuoly
8070be9b76 fix: missing 'follow_redirects' argument while download plugin packages 2024-11-01 15:38:45 +08:00
JzoNg
4caa8f38bc hide plugin detail 2024-11-01 15:33:15 +08:00
Joel
5d5db7c6c1 fix: key too long breaks ui 2024-11-01 15:28:10 +08:00
Joel
ca50522f80 feat: set tool params 2024-11-01 15:21:38 +08:00
takatost
01632bda70 fix 2024-11-01 00:07:41 -07:00
takatost
b75dce5d0a compatible with original provider name 2024-11-01 00:07:41 -07:00
Yeuoly
f1f1baae9c feat: support plugin tags 2024-11-01 15:07:11 +08:00
Yeuoly
d0c53fabca Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-11-01 15:05:31 +08:00
Yeuoly
9a455949ad feat: support plugin tags 2024-11-01 15:05:23 +08:00
takatost
f20c9ef763 fix 2024-11-01 00:01:05 -07:00
takatost
f798add31c compatible with original provider name 2024-11-01 00:00:53 -07:00
Yi
2fd4b6e6d2 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-11-01 14:56:11 +08:00
Yi
c503e8ebc9 chore: install package from GitHub 2024-11-01 14:55:56 +08:00
Joel
245bb02c88 chore: add on start to install 2024-11-01 14:51:35 +08:00
Joel
9f08206503 feat: can choose tool in agent page 2024-11-01 14:41:27 +08:00
Yeuoly
ed042862f8 fix: dockerfile 2024-11-01 14:39:11 +08:00
Yeuoly
b0d33487df fix: custom tool parser 2024-11-01 14:27:28 +08:00
Yeuoly
8c2dbe876f fix: custom tool parser 2024-11-01 14:26:56 +08:00
Joel
66be03f622 fix: search tools ui and some ui problem 2024-11-01 14:02:10 +08:00
Joel
04ba0a3500 Merge branch 'feat/plugins' into dev/plugin-deploy 2024-11-01 12:39:07 +08:00
Joel
a273ae35f9 merge feat/plugins 2024-11-01 12:37:42 +08:00
JzoNg
1a92064260 remove unused components 2024-11-01 12:09:17 +08:00
JzoNg
7752f374e5 Revert "update model provider api responses"
This reverts commit c8dc5e4849.
2024-11-01 12:00:54 +08:00
JzoNg
e7dcc53b55 Revert "load balance"
This reverts commit 378a9dd850.
2024-11-01 12:00:54 +08:00
JzoNg
22766c27c7 Revert "model list of provider"
This reverts commit 766ac3e255.
2024-11-01 12:00:54 +08:00
JzoNg
c82b641357 Revert "get credentials of provider"
This reverts commit 72ef04d3e4.
2024-11-01 12:00:54 +08:00
JzoNg
1d871dae0d Revert "credentials of models"
This reverts commit 2ed73b763d.
2024-11-01 12:00:54 +08:00
JzoNg
c39be7852f Revert "parameters and rules"
This reverts commit 22696fa75b.
2024-11-01 12:00:54 +08:00
JzoNg
f2a5da918b Revert "other providers"
This reverts commit 339dfe5e02.
2024-11-01 12:00:54 +08:00
JzoNg
930425b896 Revert "annotation config"
This reverts commit 633768cd2a.
2024-11-01 12:00:54 +08:00
JzoNg
32e4efb524 Revert "logs"
This reverts commit 06729f6d9d.
2024-11-01 12:00:54 +08:00
JzoNg
96c3ec91af click handle of provider card 2024-11-01 12:00:54 +08:00
JzoNg
f257184b00 provider card & link 2024-11-01 12:00:54 +08:00
JzoNg
581d09895e search model in provider settings 2024-11-01 12:00:54 +08:00
StyleZhang
197f1b3957 feat: search box 2024-11-01 11:26:36 +08:00
Joel
207b589458 chore: toolpicker add trigger 2024-11-01 11:22:18 +08:00
StyleZhang
b5be6bacef fix: marketplace list 2024-10-31 18:54:33 +08:00
Joel
bca99cf4f8 feat: tool picker 2024-10-31 18:37:50 +08:00
twwu
0e873223d7 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-10-31 18:32:32 +08:00
twwu
133b487566 feat: Enhance plugin item links and increase value display width 2024-10-31 18:32:25 +08:00
StyleZhang
a9e8eb1c7e fix: marketplace list 2024-10-31 18:31:36 +08:00
twwu
bf2b9bb898 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-10-31 16:44:08 +08:00
twwu
837990cb80 feat: Add loading to delete confirmation dialog 2024-10-31 16:44:04 +08:00
StyleZhang
4be2edd934 feat: plugin list tasks 2024-10-31 16:27:24 +08:00
twwu
7d4f8e0082 Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-10-31 16:20:31 +08:00
twwu
36ab121b87 feat: plugin uninstall & plugin list filtering 2024-10-31 16:20:25 +08:00
Joel
7f2980fbc0 chore: fix index show 2024-10-31 16:10:48 +08:00
Joel
ae21d48132 feat: list flat view 2024-10-31 15:59:39 +08:00
StyleZhang
8af8a0f46d fix: tool list 2024-10-31 15:41:02 +08:00
Yeuoly
9a20c18869 fix: delete temp dependencies 2024-10-31 15:40:29 +08:00
Yeuoly
5ee9577d39 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-10-31 15:33:40 +08:00
Yeuoly
6fd0a55b00 fix: correct dockerfile dependencies 2024-10-31 15:32:25 +08:00
Yeuoly
a196de195e Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-10-31 15:19:49 +08:00
Yeuoly
bb58f5c6e5 fix: avoid None to be assigned to WorkflowToolProviderController as provider id 2024-10-31 15:18:45 +08:00
twwu
4adb61d6c7 refactor: Update marketplace API prefix in layout.tsx 2024-10-31 13:45:46 +08:00
Joel
7dd7f06f7d chore: handle icon toggle fold 2024-10-31 12:00:11 +08:00
Joel
074e660a67 feat: can add tree view 2024-10-31 11:37:55 +08:00
takatost
18edeb8e0a integrate model provider with plugin daemon 2024-10-30 18:56:52 -07:00
JzoNg
06729f6d9d logs 2024-10-31 09:06:10 +08:00
JzoNg
633768cd2a annotation config 2024-10-31 08:43:12 +08:00
JzoNg
339dfe5e02 other providers 2024-10-31 08:22:14 +08:00
JzoNg
22696fa75b parameters and rules 2024-10-31 08:22:14 +08:00
JzoNg
2ed73b763d credentials of models 2024-10-31 08:22:14 +08:00
JzoNg
72ef04d3e4 get credentials of provider 2024-10-31 08:22:14 +08:00
JzoNg
766ac3e255 model list of provider 2024-10-31 08:22:14 +08:00
JzoNg
378a9dd850 load balance 2024-10-31 08:22:14 +08:00
JzoNg
c8dc5e4849 update model provider api responses 2024-10-31 08:22:14 +08:00
JzoNg
1387c6bd1c update style of agent tool list 2024-10-31 08:22:14 +08:00
JzoNg
fda21f6b05 fix size of icon 2024-10-31 08:22:14 +08:00
JzoNg
8c25915d2b action panel tabs 2024-10-31 08:22:14 +08:00
JzoNg
aba48749da action panel header 2024-10-31 08:22:14 +08:00
JzoNg
35a66ffe9f tool actions 2024-10-31 08:22:14 +08:00
StyleZhang
3db9174f55 fix: marketplace list 2024-10-30 17:24:46 +08:00
StyleZhang
02854b273f fix: marketplace 2024-10-30 16:36:08 +08:00
Yeuoly
fb3d03b790 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-10-30 16:09:33 +08:00
Yeuoly
459cb9dd72 fix: transform plugin icon incorrect 2024-10-30 16:09:17 +08:00
StyleZhang
fd0a830816 feat: marketplace list 2024-10-30 15:27:38 +08:00
StyleZhang
e7fb92e169 feat: marketplace list 2024-10-30 15:16:13 +08:00
Joel
9c4e809799 chore: tiny css and i18n 2024-10-30 14:27:39 +08:00
Joel
169eb32662 chore: toolpicker ui 2024-10-30 14:24:00 +08:00
StyleZhang
0f4291bd36 merge main 2024-10-30 11:20:20 +08:00
StyleZhang
14b641557a feat: marketplace sort 2024-10-30 11:07:13 +08:00
AkaraChen
9c963d6f69 build: echarts update 2024-10-30 10:29:10 +08:00
AkaraChen
96abeda2e7 build: echarts update 2024-10-30 10:28:22 +08:00
StyleZhang
62fa90e30e feat: marketplace sort 2024-10-29 18:14:05 +08:00
Joel
7e378e219c chore: add missing i18n 2024-10-29 18:11:09 +08:00
Joel
34652010f5 feat: add market url prefix 2024-10-29 18:09:59 +08:00
AkaraChen
082f6f6a5f build: update deps 2024-10-29 17:47:06 +08:00
Joel
6f52edb157 feat: plugin permission 2024-10-29 17:18:23 +08:00
Yeuoly
60f707e5f4 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-10-29 17:16:48 +08:00
Yeuoly
f9e2c738b0 fix: permission change api should not wraps a permission decorator 2024-10-29 17:16:32 +08:00
Joel
0dcbb34cab feat: handle from market install 2024-10-29 16:33:46 +08:00
StyleZhang
0886d7bb8b feat: marketplace list 2024-10-29 15:23:29 +08:00
StyleZhang
e65a47cff7 feat: marketplace list 2024-10-29 15:23:29 +08:00
Joel
36c01d89c9 fix: cros promblem 2024-10-29 15:19:47 +08:00
Joel
6726ca102e feat: add get marketpalce get 2024-10-29 14:53:14 +08:00
Yeuoly
6246cf047b Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-10-29 12:32:25 +08:00
Yeuoly
739e15f88b feat: support tool plugin id 2024-10-29 12:32:11 +08:00
Joel
e135707f88 chore: plugin icon not show 2024-10-29 11:57:21 +08:00
Joel
f2765b9d31 feat: fetch plugin icon 2024-10-29 11:47:23 +08:00
StyleZhang
1e0877dcbf feat: marketplace list 2024-10-29 11:33:52 +08:00
StyleZhang
9a65c3391b feat: marketplace list 2024-10-29 10:51:41 +08:00
Joel
ca9e23d6ea fix: check status 2024-10-28 18:36:23 +08:00
AkaraChen
c4d6f9e179 build: update react-easy-crop 2024-10-28 16:46:35 +08:00
Joel
0cec6195a3 test 2024-10-28 16:33:02 +08:00
Yeuoly
19b9b91943 fix: dockerfile 2024-10-28 16:29:24 +08:00
Yeuoly
e1f773d0d8 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-10-28 16:23:04 +08:00
Yeuoly
5bf86ff66d feat: support latest package identifier 2024-10-28 15:56:15 +08:00
Yeuoly
c657378d06 feat: support plugin permission management 2024-10-28 15:54:34 +08:00
Joel
966d42a4db Merge branch 'main' into feat/plugins 2024-10-28 15:53:39 +08:00
AkaraChen
15c33ba7f3 build: update lexical deps 2024-10-28 15:33:22 +08:00
AkaraChen
ed7f74c99c build: update i18n pkg 2024-10-28 15:32:39 +08:00
AkaraChen
1db4139b5a build: update deps
build: update classnames

build: update types

build: update uuid

build: update emoji-mart

build: update use-context-selector

build: update ui component deps
2024-10-28 15:24:44 +08:00
Yeuoly
685e8cdc7d refactor: document segment query 2024-10-28 15:07:33 +08:00
StyleZhang
0d85d44de5 feat: marketplace list 2024-10-28 11:50:45 +08:00
AkaraChen
f0f1bfa5d9 build: fix eslint 2024-10-28 11:03:43 +08:00
Joel
9161ce481e Merge branch 'feat/plugins' of https://github.com/langgenius/dify into feat/plugins 2024-10-28 10:59:39 +08:00
Joel
c760902e72 chore: remove useless rule 2024-10-28 10:56:52 +08:00
Joel
7c8c15ef1a test no use rule 2024-10-28 10:56:31 +08:00
Joel
765eb282f3 merge main 2024-10-28 10:51:02 +08:00
Yeuoly
d36dece0af feat: support upgrade interfaces 2024-10-25 18:56:38 +08:00
AkaraChen
0e2b38dddc build: update qrcode.react 2024-10-25 18:03:25 +08:00
AkaraChen
92e4b3304c build: update deps
build: update sass

build: update lodash-es

build: update qs & js-cookie
2024-10-25 17:58:19 +08:00
Joel
c777d55a1c feat: marketplace install 2024-10-25 16:46:02 +08:00
Yeuoly
5f61aa85db feat: add latest version 2024-10-25 13:52:33 +08:00
Yeuoly
e5837b88e0 fix: add subpath 2024-10-25 13:26:32 +08:00
Yeuoly
ffdc6f5c60 feat: support remove single item from installation task 2024-10-25 13:22:37 +08:00
AkaraChen
cd27ae4319 build: update testing-library 2024-10-25 13:01:39 +08:00
AkaraChen
bd82c7edac build: update storybook 2024-10-25 13:01:39 +08:00
AkaraChen
d5043c6628 build: update husky & lint-staged 2024-10-25 13:01:39 +08:00
AkaraChen
d9a0584052 build: update eslint & fix some case 2024-10-25 12:51:11 +08:00
Joel
3e011109ad merge main 2024-10-25 11:26:49 +08:00
Joel
bdb990eb90 merge main 2024-10-25 11:26:48 +08:00
StyleZhang
ae00211691 feat: marketplace types 2024-10-25 11:15:32 +08:00
StyleZhang
0ef35a0ee0 fix: enable_marketplace 2024-10-25 10:41:25 +08:00
Joel
9a9d90ad7f feat: can install 2024-10-24 17:24:46 +08:00
Joel
606fc7be0c feat: support upload pkg 2024-10-24 17:14:17 +08:00
Joel
d7def41acc feat: fetch debug key api 2024-10-24 16:07:46 +08:00
AkaraChen
b6a560ce86 style: lint 2024-10-24 14:52:07 +08:00
StyleZhang
25f34f6703 fix: marketplace plugin type icon 2024-10-24 14:21:12 +08:00
Yeuoly
f87eeba310 Merge branch 'fix/chore-fix' into dev/plugin-deploy 2024-10-24 13:21:17 +08:00
Yeuoly
99c8f364ae fix: temp fix for empty redis password 2024-10-24 13:20:26 +08:00
Joel
7daa365564 chore: to common install comp 2024-10-24 11:10:44 +08:00
Joel
13ccd294cb fix: install error title not update 2024-10-23 17:55:25 +08:00
Yeuoly
c2c07b0f4b depoly: support auto deploy 2024-10-23 17:55:11 +08:00
Joel
d357f359ab feat: support install failed 2024-10-23 17:52:39 +08:00
Joel
474cedf653 feat: debug info api 2024-10-23 17:19:54 +08:00
nite-knite
5d3c88a0b3 chore: bump mermaid from 10.4.0 to 10.9.3 2024-10-23 17:02:38 +08:00
Joel
ae2c76bda2 feat: install from marketplace 2024-10-23 16:42:24 +08:00
Joel
c46b5f2fd0 feat: handle install search params and hide 2024-10-23 15:26:31 +08:00
Joel
2cb7b73ee7 feat: handle import from marketplace 2024-10-23 15:00:31 +08:00
Joel
8d8d5b5235 chore: handle verified 2024-10-23 11:45:36 +08:00
Joel
15acfffd60 chore: some ui and mock data 2024-10-23 11:40:56 +08:00
Yi
18a266eac2 chore: i18n for install from GitHub section 2024-10-22 18:39:23 +08:00
Joel
7751070da8 chore: install from local i18n 2024-10-22 18:11:54 +08:00
Yi
fa8c3d0d7b Resolved merge conflicts by removing conflicting files 2024-10-22 17:58:41 +08:00
Yeuoly
a0a1243c90 cleanup: remove hacked code 2024-10-22 17:56:13 +08:00
Yi
a567cff809 chore: update the install from GitHub component 2024-10-22 17:51:14 +08:00
Yeuoly
b916b4064a Merge remote-tracking branch 'origin/fix/tool-use-file' into fix/chore-fix 2024-10-22 17:47:01 +08:00
Yeuoly
dea2962a79 Merge main into feat/plugin 2024-10-22 17:35:11 +08:00
Joel
583b0e9f97 chore: remove replicated types 2024-10-22 17:29:58 +08:00
Yeuoly
1450e5d5cb feat: add supports for multimodal 2024-10-22 17:26:00 +08:00
Joel
5fddb23516 feat: install progress 2024-10-22 17:21:44 +08:00
Joel
43a2d4335b fix: tool use file caused error 2024-10-22 16:51:11 +08:00
Yi
0e52971997 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-10-22 16:40:50 +08:00
Yi
1387f406a3 fix: log format 2024-10-22 16:40:27 +08:00
AkaraChen
ff31f0540a style: lint 2024-10-22 15:32:58 +08:00
AkaraChen
4873e6e2a1 build: fix eslint stylistic 2024-10-22 15:32:48 +08:00
nite-knite
510ce057f7 chore: add package manager setting to vscode setting example 2024-10-22 14:18:55 +08:00
AkaraChen
0e53cc0e8c fix: eslint indent 2024-10-22 14:15:22 +08:00
Yi
0b8c896481 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-10-22 13:43:15 +08:00
Yi
15fe635465 chore: install package from GitHub 2024-10-22 13:43:01 +08:00
AkaraChen
f8c3189f4d build: fix eslint undef 2024-10-22 11:43:23 +08:00
AkaraChen
f215db87e3 build: fix eslint undef 2024-10-22 11:36:42 +08:00
Joel
67d02212b4 chore: pnpm 2024-10-22 11:18:30 +08:00
Joel
cff9adaf8e chore: tools ts problems 2024-10-22 11:06:28 +08:00
AkaraChen
cdd2a40086 style: minimium codemod 2024-10-22 02:24:59 +00:00
AkaraChen
024028bc52 build: sync eslint rule 2024-10-22 10:24:10 +08:00
AkaraChen
0ae085b48a build: add eslint common rule 2024-10-22 10:24:10 +08:00
AkaraChen
2094c54951 build: update eslint config antfu 2024-10-22 10:24:10 +08:00
AkaraChen
f4f11135d3 build: using eslint flat config 2024-10-22 10:24:10 +08:00
Yeuoly
11270a7ef2 Migrate to DeclarativeBaseModel 2024-10-21 20:38:27 +08:00
Yeuoly
53e1b45d40 fix: remove .query reference of db.Model 2024-10-21 20:23:27 +08:00
Yeuoly
bedbd658fe Merge main into fix/chore-fix 2024-10-21 20:01:49 +08:00
Yeuoly
7b62b5578e refactor: add manifest into upload interfaces 2024-10-21 18:48:03 +08:00
Joel
8e9d7a229d feat: scroll to view and fix action hidden 2024-10-21 18:21:45 +08:00
Joel
8f49572f85 chore: from marketplace tilte ui 2024-10-21 15:07:18 +08:00
JzoNg
5aa7696cc3 update style of action list 2024-10-21 11:34:21 +08:00
JzoNg
15dd79e822 provider detail data binding 2024-10-21 11:34:21 +08:00
JzoNg
4651ab4195 new style of provider detail 2024-10-21 11:34:21 +08:00
JzoNg
5e3160e6f6 fix title & description of tool provider 2024-10-21 11:34:21 +08:00
JzoNg
973cd126bb create & update endpoint 2024-10-21 11:34:21 +08:00
JzoNg
ebaf8766ef endpoint form 2024-10-21 11:34:21 +08:00
JzoNg
d2190e9c3a remove endpoint 2024-10-21 11:34:21 +08:00
JzoNg
37f55098fe switch endpoint service state 2024-10-21 11:34:21 +08:00
JzoNg
b1771194cc servise of endpoints 2024-10-21 11:34:21 +08:00
JzoNg
0279bd8c75 endpoint card databing 2024-10-21 11:34:21 +08:00
JzoNg
5e077e4ce8 endpoints data binding 2024-10-21 11:34:21 +08:00
JzoNg
64067e1f20 plugin detail header operations 2024-10-21 11:34:21 +08:00
JzoNg
5295c72ca1 endpoints mock data 2024-10-21 11:34:21 +08:00
JzoNg
1ecea62052 add verified tag 2024-10-21 11:34:21 +08:00
JzoNg
307af29b65 add plugin description 2024-10-21 11:34:21 +08:00
JzoNg
10190a9aa5 plugin detail header data binding 2024-10-21 11:34:21 +08:00
JzoNg
7c5c35600c plugin detail type 2024-10-21 11:34:21 +08:00
JzoNg
63b333cdb1 modify plugin detail panel 2024-10-21 11:34:21 +08:00
JzoNg
a6776190bd chore: update remix icon 2024-10-21 11:34:19 +08:00
AkaraChen
9577cbac27 build: docker use pnpm 2024-10-21 11:27:01 +08:00
AkaraChen
f6ae13abad ci: migrate to pnpm 2024-10-21 11:14:30 +08:00
AkaraChen
f3d501e7d5 fix: gen-icon script phantom deps 2024-10-21 10:43:52 +08:00
AkaraChen
2eab8fcc33 build: switch to pnpm 2024-10-21 10:43:52 +08:00
Joel
bdb81fe20d feat: choose tool sticky 2024-10-18 18:18:59 +08:00
Yi
0f60fe7f2a chore: update workspace name (truncated for long name) 2024-10-18 14:17:53 +08:00
Yi
425f624de5 chore: add plugin panel 2024-10-18 14:02:40 +08:00
Yi
b1919745e2 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-10-18 14:01:34 +08:00
twwu
9a242bcac9 Merge branch 'main' into feat/plugins 2024-10-18 09:59:43 +08:00
Yeuoly
ccbe42eb5f feat: add plugin id into tool api entities 2024-10-17 20:46:29 +08:00
Yeuoly
45f8651a3d feat: support backwards invoke summary 2024-10-17 19:44:30 +08:00
Yeuoly
7754431a34 feat: support plugin max package size 2024-10-17 18:44:16 +08:00
Yi
a6109a60b8 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-10-17 15:22:08 +08:00
Yi
28f7bbf83a chore: installation progress bar 2024-10-17 15:21:56 +08:00
Joel
cac04c5f3c refactor: chagne card to client component 2024-10-17 15:06:06 +08:00
Yeuoly
fa7215cfea Merge branch 'main' into fix/chore-fix 2024-10-17 13:46:43 +08:00
Yeuoly
678c89891a feat: support verified 2024-10-17 13:40:33 +08:00
Yeuoly
beebcbd962 feat: add description 2024-10-17 12:59:11 +08:00
Joel
18f5f9cc37 feat: plugin upgrade 2024-10-16 18:05:55 +08:00
Joel
1787c5c93f chore: handle tag name too long 2024-10-16 16:39:47 +08:00
Joel
f981494613 feat: plugin support emoji icon 2024-10-16 16:28:19 +08:00
Joel
fbc853af92 feat: remove config 2024-10-16 16:28:18 +08:00
StyleZhang
1a64c660ba enable marketplace 2024-10-16 15:50:18 +08:00
Yeuoly
8495ed3348 add conversation id, app id and message id into plugin session 2024-10-16 15:10:50 +08:00
Yeuoly
31cca4a849 fix: add marketplace switch 2024-10-16 14:47:48 +08:00
Yeuoly
43ffccc8fd fix: install plugins 2024-10-16 14:02:05 +08:00
Yeuoly
a81293cf5a feat: add category for plugins 2024-10-16 13:03:50 +08:00
Joel
846555af1b fix: action buttion ui 2024-10-16 11:45:25 +08:00
Joel
bca94854f7 feat: plugin info 2024-10-16 11:30:04 +08:00
Joel
1bd70bd8bf chore: copy button 2024-10-16 11:05:51 +08:00
Joel
d1dcd39191 feat: add debug info i18n and extract common to components 2024-10-16 10:52:16 +08:00
Joel
35384bda41 chore: refactor card loading 2024-10-15 22:52:57 +08:00
Joel
89fb6eb648 chore: set hideCornerMark to optional 2024-10-15 21:45:30 +08:00
Joel
aa61a890b2 chore: change downloadCount to optional 2024-10-15 21:43:20 +08:00
Joel
31ece363c3 chore: chagne mangament attr name 2024-10-15 21:35:56 +08:00
Joel
70a5d78cc5 chore: priviege i18n 2024-10-15 21:31:06 +08:00
Joel
57f4dfdb6f feat: add permission data logic 2024-10-15 19:20:59 +08:00
Yi
aa9028a607 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-10-15 15:48:05 +08:00
Yi
d83f94c55c fix: set constrain for uploading packages only works in the Plugins tab 2024-10-15 15:47:54 +08:00
StyleZhang
a8c5e0b0b0 tool list item click 2024-10-15 15:13:00 +08:00
Yi
177e8cbf73 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-10-15 14:57:37 +08:00
Yi
23828fd15a Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-10-15 14:57:11 +08:00
StyleZhang
2cc37ac8e5 tool list 2024-10-15 14:57:00 +08:00
Yi
c9ee1e9ff2 feat: install difypkg ui 2024-10-15 14:56:59 +08:00
Joel
4f10f5d5f4 chore: hover show action 2024-10-15 11:57:44 +08:00
Yi
c48c84674e Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-10-15 11:02:45 +08:00
Yi
1e9fbbf41b fix: dynamic sub header color 2024-10-15 11:02:25 +08:00
StyleZhang
4dd144ce43 tools list 2024-10-15 10:41:10 +08:00
Yi
a387ff1c38 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-10-14 18:43:24 +08:00
Yi
a9e367e6de feat: use-uploader hook 2024-10-14 18:43:08 +08:00
Joel
e2fec587f8 feat: from marketplace 2024-10-14 18:35:13 +08:00
Yeuoly
276701e1b7 refactor: plugin installation 2024-10-14 17:52:29 +08:00
Yeuoly
8e1cf3233c fix: missing openai moderation 2024-10-14 16:42:36 +08:00
Yeuoly
dd551e6ca8 Ruff: reformatter 2024-10-14 16:25:51 +08:00
Yeuoly
ae1eeb9b2a Mergin main into fix/chore-fix 2024-10-14 16:22:12 +08:00
StyleZhang
39a6f0943d marketplace 2024-10-14 12:38:53 +08:00
JzoNg
684896d100 merge main 2024-10-14 10:29:52 +08:00
JzoNg
54f911f6cd endpoints 2024-10-13 10:49:55 +08:00
Joel
0e5c16d0c2 feat: view to ui and fix some ui promblem 2024-10-12 18:15:11 +08:00
Joel
b8cd6ea478 feat: support view choose 2024-10-12 17:36:35 +08:00
JzoNg
fc61fd0f50 action list 2024-10-12 17:08:45 +08:00
JzoNg
2fbfc988c4 plugin panel detail 2024-10-12 16:37:57 +08:00
JzoNg
99f5fea001 plugin detail panel header 2024-10-12 16:37:57 +08:00
StyleZhang
ecd2a1be9f marketplace 2024-10-12 16:34:18 +08:00
Joel
49ee9ca5f1 feat: tool item support action 2024-10-12 16:04:16 +08:00
Joel
6d0eef12b1 feat: split tools data to out and add demo 2024-10-12 14:30:46 +08:00
StyleZhang
c1e0a939b0 marketplace 2024-10-12 12:46:49 +08:00
JzoNg
060a894bd1 interaction of plugin detail panel 2024-10-12 12:36:29 +08:00
JzoNg
c75e02b5b2 update provider card 2024-10-12 12:36:29 +08:00
StyleZhang
fcf43ee845 plugin page context 2024-10-12 11:33:12 +08:00
StyleZhang
466f61d044 relocate file 2024-10-12 11:05:03 +08:00
StyleZhang
27ae74af50 hook 2024-10-12 11:03:00 +08:00
Joel
8dd941e3d2 chore: instal plug add tag 2024-10-11 18:18:32 +08:00
Joel
dec4bf6b98 fix: install modal item server 2024-10-11 18:06:23 +08:00
Joel
e2c33fc40f fix: plugin item i18n 2024-10-11 18:05:45 +08:00
Yi
c74e59d1f4 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-10-11 17:28:27 +08:00
Yi
1fcb902715 feat: add cards to "install from marketplace" 2024-10-11 17:25:33 +08:00
JzoNg
c08f98218c hide search in other pages 2024-10-11 17:13:28 +08:00
Yi
c6377f6e38 fix: naming styles 2024-10-11 16:29:07 +08:00
Yi
3cb0a5bd68 Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-10-11 16:28:04 +08:00
Yi
95777d23e0 fix: naming styles 2024-10-11 16:27:31 +08:00
JzoNg
e7dc16fd08 provider card 2024-10-11 16:21:19 +08:00
JzoNg
495dec143c unconfigured provider 2024-10-11 16:21:19 +08:00
JzoNg
4cc6dfa232 new style of provider card 2024-10-11 16:21:18 +08:00
JzoNg
d1452d4af4 no provider installed 2024-10-11 16:21:18 +08:00
JzoNg
d68ca56b3a system default model 2024-10-11 16:21:18 +08:00
JzoNg
49856d8d17 setting content header & close button 2024-10-11 16:21:18 +08:00
JzoNg
902de72cc0 new style of settings 2024-10-11 16:21:18 +08:00
StyleZhang
76f6b8d104 marketplace 2024-10-11 16:15:24 +08:00
StyleZhang
f111e605c4 marketplace 2024-10-11 15:27:14 +08:00
Joel
b358ed3a5b fix: init workflow image crash 2024-10-11 14:31:14 +08:00
Joel
88dbf639e0 chore: enchance locale props 2024-10-11 14:24:43 +08:00
Joel
aa8b525b48 fix: icon tsx to router problem 2024-10-11 14:10:24 +08:00
Yi
c990bc61db feat: install plugins (partial) 2024-10-11 12:39:27 +08:00
Junyan Qin
b58f8dd7b4 feat: download pkg from marketplace (#9184) 2024-10-11 02:00:02 +08:00
Yeuoly
118fa66567 feat: backwards invoke tools 2024-10-10 18:09:06 +08:00
Joel
6d7588f236 chore: fix ui 2024-10-10 17:53:13 +08:00
Joel
8257c7bf02 chore: remove useless data 2024-10-10 17:49:23 +08:00
Joel
946068967b feat: finish card components 2024-10-10 17:47:04 +08:00
Yeuoly
699d41deec fix: add source to plugin entity 2024-10-10 16:47:25 +08:00
Yeuoly
dd0462c1dc feat: support two install source 2024-10-10 16:35:36 +08:00
Joel
19f5684960 feat: add label and fix some ui problem 2024-10-10 11:29:11 +08:00
Joel
6d62840aff chore: split card component 2024-10-10 10:40:26 +08:00
Joel
ab868ac979 fix: error igm 2024-10-10 10:25:25 +08:00
Joel
1d74e693ea chore: fix imge name 2024-10-10 10:22:18 +08:00
Yeuoly
a470e0e60e fix: missing detailed paths of endpoints 2024-10-10 00:12:46 +08:00
Yeuoly
2622159763 feat: support verify signature 2024-10-09 23:13:01 +08:00
Yeuoly
dfaf639790 feat: support endpoint url template 2024-10-09 22:58:36 +08:00
Yeuoly
ae96f66a08 feat: support list endpoints for single plugin, fix: failed to clear endpoint credentials 2024-10-09 22:33:18 +08:00
Joel
fa43d4202f feat: plugin item 2024-10-09 18:36:15 +08:00
Joel
6b29860788 feat: add installed 2024-10-09 18:12:14 +08:00
Joel
36800eeaba feat: base card component 2024-10-09 17:51:54 +08:00
Yi
67acd174ac add different styles to plugins and discover 2024-10-09 15:55:33 +08:00
StyleZhang
b5edc64b2a plugin type switch 2024-10-09 15:06:09 +08:00
Yi
d00b2724cc Merge branch 'feat/plugins' of github.com:langgenius/dify into feat/plugins 2024-10-09 12:53:56 +08:00
Yi
43f87c0b86 make the drop plugin only appears when the user selects "plugins" 2024-10-09 12:53:43 +08:00
Joel
7a43f48c95 chore: add test page 2024-10-09 11:35:16 +08:00
Yeuoly
570b7d18ac fix: endpoint apis 2024-10-08 23:48:38 +08:00
Yeuoly
a9c21ef929 feat: uninstall plugins 2024-10-08 22:38:33 +08:00
Yeuoly
e27a03ae15 feat: support install plugin 2024-10-08 21:28:59 +08:00
StyleZhang
58a913b09d marketplace 2024-10-08 17:58:05 +08:00
Joel
cd03795f2c chore: add endpoint types 2024-10-08 15:44:52 +08:00
Yeuoly
56b7853afe feat: compat tool provider credentials to updated data 2024-09-30 23:22:23 +08:00
takatost
e12f4009d3 feat: optimize icon url 2024-09-30 17:46:40 +08:00
Yeuoly
6dfc31a542 refactor: credentials schemas to array 2024-09-30 17:39:13 +08:00
Yeuoly
c9f80b46a1 fix: add endpoint name 2024-09-30 16:57:09 +08:00
Joel
36f8b5711d feat: plugin types 2024-09-30 15:29:53 +08:00
Yeuoly
0025b27200 fix: tool invocation logs 2024-09-29 21:09:01 +08:00
Yeuoly
0dd05d7b6d feat: tool output schema 2024-09-29 20:58:07 +08:00
takatost
7c83d5ce76 feat: add dockerignore items 2024-09-29 20:16:21 +08:00
takatost
a57f60a6e0 feat: remove unused codes 2024-09-29 19:47:47 +08:00
Yeuoly
2f36692bf9 fix: get tool runtime parameters 2024-09-29 19:37:03 +08:00
Joel
f9c48e9ea9 fix: eslint to find top dir 2024-09-29 18:27:36 +08:00
takatost
bcdb407be8 feat: remove unused codes 2024-09-29 18:24:33 +08:00
Yeuoly
d4e007f9db feat: support get tool runtime parameters 2024-09-29 18:19:03 +08:00
takatost
8563155d1b feat: remove unused codes 2024-09-29 18:18:01 +08:00
takatost
8236373498 feat: remove unused codes 2024-09-29 18:16:21 +08:00
Yeuoly
196bfeaaf4 Merge branch 'main' into fix/chore-fix 2024-09-29 17:14:10 +08:00
Yeuoly
957ab093c9 enhancement: reduce requests to plugin daemon 2024-09-29 17:07:40 +08:00
Yeuoly
e9e5c8806a refactor: using DeclarativeBase as parent class of models, refactored tools 2024-09-29 17:00:58 +08:00
Yeuoly
c8bc3892b3 refactor: invoke tool from dify 2024-09-29 14:44:22 +08:00
Yeuoly
735e57b73a fix: transform generic error message into correct type 2024-09-29 13:46:16 +08:00
Yeuoly
635a53ea38 fix: import undefined types 2024-09-29 13:23:14 +08:00
Yeuoly
7b76b1ff82 Merge fix/chore-fix into fix/chore-fix 2024-09-29 13:12:22 +08:00
takatost
47c8824be6 feat: move model request to plugin daemon 2024-09-29 00:15:17 +08:00
takatost
1c3213184e feat: move model request to plugin daemon 2024-09-29 00:15:14 +08:00
Yeuoly
d9cced8419 Merge branch 'main' into fix/chore-fix 2024-09-28 20:18:28 +08:00
Yeuoly
c3359a9291 refactor: using plugin id to dispatch request instead 2024-09-27 21:48:48 +08:00
JzoNg
3b48f8c98e Merge branch 'main' into tp 2024-09-27 16:47:57 +08:00
JzoNg
cef1010cb5 style update 2024-09-27 16:47:01 +08:00
Yeuoly
2da32e49d0 fix: tests 2024-09-26 17:51:13 +08:00
Yeuoly
1837692a66 fix: sse error message 2024-09-26 17:40:27 +08:00
Yeuoly
5dcd25a613 fix: missing error message 2024-09-26 17:22:39 +08:00
Yeuoly
507fff0259 fix: tts file was deleted before invocation 2024-09-26 15:47:16 +08:00
Yeuoly
0ad9dbea63 feat: backwards invoke model 2024-09-26 15:38:22 +08:00
Joel
cb4875a3a7 chore: split the common tailwind config 2024-09-26 15:06:36 +08:00
Yeuoly
4c28034224 refactor: encryption 2024-09-26 14:51:10 +08:00
Yeuoly
1d575524c3 fix: missing user id 2024-09-26 14:20:05 +08:00
Yeuoly
dc255cc154 Merge main into feat/plugin 2024-09-26 12:59:06 +08:00
Yeuoly
ea497f828f feat: endpoint management 2024-09-26 12:49:00 +08:00
Yeuoly
153dc5b3f3 feat: endpoint apis 2024-09-26 10:26:45 +08:00
Yeuoly
a91951b374 feat: invoke node 2024-09-24 20:15:13 +08:00
Yeuoly
68c10a1672 feat: add backwards invoke node api 2024-09-24 18:03:48 +08:00
Yeuoly
592f85f7a9 formatter 2024-09-24 16:40:42 +08:00
Yeuoly
cda9f6ec6b Merge main into fix/chore-fix 2024-09-24 16:38:38 +08:00
Yeuoly
64706c709c fix 2024-09-24 16:35:01 +08:00
Yeuoly
9722e6bcb1 fix: allow duplicate tool providers 2024-09-24 16:33:19 +08:00
Yeuoly
1907d791e1 enhance: add gzip 2024-09-24 16:15:50 +08:00
Yeuoly
fb3a701c86 fix: stream with empty line 2024-09-24 16:02:01 +08:00
StyleZhang
bbca708832 add marketplace card 2024-09-24 11:18:34 +08:00
Yeuoly
947bfdc807 feat: validate credentials 2024-09-23 21:13:02 +08:00
Yeuoly
7a3e756020 refactor: list tools 2024-09-23 18:06:16 +08:00
Yeuoly
435e71eb60 refactor 2024-09-23 13:09:46 +08:00
JzoNg
05aec43ee3 Merge branch 'main' into tp 2024-09-23 11:39:46 +08:00
Yeuoly
91cb80f795 refactor: tool 2024-09-20 23:48:48 +08:00
Yeuoly
3c1d32e3ac feat: uninstall plugin 2024-09-20 21:50:44 +08:00
Yeuoly
eef79a5196 feat: support install plugin 2024-09-20 21:35:19 +08:00
Yeuoly
2223dfb266 feat: get debugging key 2024-09-20 15:08:39 +08:00
Yeuoly
9693b5ad0c feat: debugging key 2024-09-20 14:43:01 +08:00
Yeuoly
d4bf575d0a impl: basic plugin manager 2024-09-20 13:55:09 +08:00
Yeuoly
73ce692e24 feat: add inner api key 2024-09-20 13:32:11 +08:00
Yeuoly
661392eaef refactor: tool 2024-09-20 02:25:14 +08:00
Yeuoly
c472ea6c67 fix: pydantic 2024-09-19 18:02:24 +08:00
Yeuoly
4eaba3049a Merge main 2024-09-19 17:54:08 +08:00
Yi
e8127756e0 Merge branch 'main' of github.com:langgenius/dify into feat/plugins 2024-09-18 20:57:52 +08:00
Yi
792595a46f update page header 2024-09-18 18:32:33 +08:00
Yi
d7d7281c93 feat: plugin homepage 2024-09-16 18:58:39 +08:00
Yi
21193c2fbf update the plugins page 2024-09-14 17:09:25 +08:00
Yeuoly
00d1c45518 Merge main 2024-09-14 02:47:01 +08:00
Yeuoly
87c746f6bb tmp 2024-09-14 01:26:22 +08:00
Yeuoly
70c001436e support variable 2024-09-10 18:13:33 +08:00
Yeuoly
cf73374c1b refactor: stream output 2024-09-10 17:16:55 +08:00
Yeuoly
b0d53c0ac4 Merge main 2024-09-10 15:42:59 +08:00
Yeuoly
9c7bcd5abc Merge main 2024-09-10 14:05:20 +08:00
Yeuoly
b7c5abc5dd reformatter 2024-08-30 23:29:04 +08:00
Yeuoly
de01ca8d55 feat: inner api encrypt 2024-08-30 21:25:58 +08:00
Yeuoly
60e75dc748 fix: linter 2024-08-30 21:11:39 +08:00
Yeuoly
279dee485d feat: type 2024-08-30 21:10:19 +08:00
Yeuoly
db8bf2a85e Merge branch 'main' into feat/plugin 2024-08-30 18:21:22 +08:00
Yeuoly
46ba16fe90 fix: reformatter 2024-08-30 18:21:03 +08:00
Yeuoly
886a160115 fix: invoke tool streamingly 2024-08-30 18:11:38 +08:00
Yeuoly
cf4e9f317e refactor: tool models 2024-08-30 15:55:10 +08:00
Yeuoly
1fa3b9cfd8 refactor tools 2024-08-30 14:23:14 +08:00
Yeuoly
50a5cfe56a fix: endpoint using default user 2024-08-29 21:48:20 +08:00
Yeuoly
ece82b87bf feat: invoke app 2024-08-29 21:14:23 +08:00
Yeuoly
12ea085e22 feat: implement invoke app args 2024-08-29 20:50:36 +08:00
Yeuoly
41ed2e0cc2 feat: backwards invoke app 2024-08-29 20:17:17 +08:00
Yeuoly
113ff27d07 fix: types 2024-08-29 20:06:14 +08:00
Yeuoly
ec711d094d refactor: enforce return object in app generator 2024-08-29 19:49:57 +08:00
Yeuoly
a073de44e9 Merge branch 'main' into feat/plugin 2024-08-29 17:08:44 +08:00
Yeuoly
6ce02b07d3 feat: add type annatation 2024-08-29 14:23:19 +08:00
Yeuoly
f47712beae feat: add type annatation 2024-08-29 14:18:00 +08:00
Yeuoly
4a8d3c54ca fix: workflow as tool type 2024-08-29 14:09:47 +08:00
Yeuoly
c8b0160ea9 fix: tool type 2024-08-29 14:06:10 +08:00
Yeuoly
531ffaec4f fix: tool node 2024-08-29 13:56:48 +08:00
Yeuoly
c28998a6f0 refactor: tool message transformer 2024-08-29 13:42:31 +08:00
Yeuoly
4b4741f7ed Merge main into feat/plugin 2024-08-29 13:09:13 +08:00
Yeuoly
25b8a512bf feat: invoke app 2024-08-29 12:55:00 +08:00
Yeuoly
02d26818ad Merge branch 'main' into feat/plugin 2024-07-31 14:51:36 +08:00
Yeuoly
31e8b134d1 feat: backwards invoke llm 2024-07-29 22:08:14 +08:00
Yeuoly
d52476c1c9 feat: support backwards invocation 2024-07-29 18:57:34 +08:00
Yeuoly
f29b44acd8 feat: support plugin inner api 2024-07-29 16:40:04 +08:00
Yeuoly
ed7fcc5f7d Merge branch 'main' into feat/plugin 2024-07-29 16:07:19 +08:00
Yeuoly
c6f34f5c17 Merge branch 'main' into feat/plugin 2024-07-15 16:03:11 +08:00
Yeuoly
e1db77eec2 fix 2024-07-15 16:00:11 +08:00
Yeuoly
563d81277b refactor: tool response to generator 2024-07-09 15:37:56 +08:00
Yeuoly
364df36ac4 feat: plugin call dify 2024-07-08 22:37:20 +08:00
8202 changed files with 258002 additions and 976723 deletions

View File

@@ -1 +0,0 @@
../.claude/skills

View File

@@ -1,20 +0,0 @@
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "npx -y block-no-verify@1.1.1"
}
]
}
]
},
"enabledPlugins": {
"feature-dev@claude-plugins-official": true,
"context7@claude-plugins-official": true,
"ralph-loop@claude-plugins-official": true
}
}

View File

@@ -1,483 +0,0 @@
---
name: component-refactoring
description: Refactor high-complexity React components in Dify frontend. Use when `pnpm analyze-component --json` shows complexity > 50 or lineCount > 300, when the user asks for code splitting, hook extraction, or complexity reduction, or when `pnpm analyze-component` warns to refactor before testing; avoid for simple/well-structured components, third-party wrappers, or when the user explicitly wants testing without refactoring.
---
# Dify Component Refactoring Skill
Refactor high-complexity React components in the Dify frontend codebase with the patterns and workflow below.
> **Complexity Threshold**: Components with complexity > 50 (measured by `pnpm analyze-component`) should be refactored before testing.
## Quick Reference
### Commands (run from `web/`)
Use paths relative to `web/` (e.g., `app/components/...`).
Use `refactor-component` for refactoring prompts and `analyze-component` for testing prompts and metrics.
```bash
cd web
# Generate refactoring prompt
pnpm refactor-component <path>
# Output refactoring analysis as JSON
pnpm refactor-component <path> --json
# Generate testing prompt (after refactoring)
pnpm analyze-component <path>
# Output testing analysis as JSON
pnpm analyze-component <path> --json
```
### Complexity Analysis
```bash
# Analyze component complexity
pnpm analyze-component <path> --json
# Key metrics to check:
# - complexity: normalized score 0-100 (target < 50)
# - maxComplexity: highest single function complexity
# - lineCount: total lines (target < 300)
```
### Complexity Score Interpretation
| Score | Level | Action |
|-------|-------|--------|
| 0-25 | 🟢 Simple | Ready for testing |
| 26-50 | 🟡 Medium | Consider minor refactoring |
| 51-75 | 🟠 Complex | **Refactor before testing** |
| 76-100 | 🔴 Very Complex | **Must refactor** |
## Core Refactoring Patterns
### Pattern 1: Extract Custom Hooks
**When**: Component has complex state management, multiple `useState`/`useEffect`, or business logic mixed with UI.
**Dify Convention**: Place hooks in a `hooks/` subdirectory or alongside the component as `use-<feature>.ts`.
```typescript
// ❌ Before: Complex state logic in component
const Configuration: FC = () => {
const [modelConfig, setModelConfig] = useState<ModelConfig>(...)
const [datasetConfigs, setDatasetConfigs] = useState<DatasetConfigs>(...)
const [completionParams, setCompletionParams] = useState<FormValue>({})
// 50+ lines of state management logic...
return <div>...</div>
}
// ✅ After: Extract to custom hook
// hooks/use-model-config.ts
export const useModelConfig = (appId: string) => {
const [modelConfig, setModelConfig] = useState<ModelConfig>(...)
const [completionParams, setCompletionParams] = useState<FormValue>({})
// Related state management logic here
return { modelConfig, setModelConfig, completionParams, setCompletionParams }
}
// Component becomes cleaner
const Configuration: FC = () => {
const { modelConfig, setModelConfig } = useModelConfig(appId)
return <div>...</div>
}
```
**Dify Examples**:
- `web/app/components/app/configuration/hooks/use-advanced-prompt-config.ts`
- `web/app/components/app/configuration/debug/hooks.tsx`
- `web/app/components/workflow/hooks/use-workflow.ts`
### Pattern 2: Extract Sub-Components
**When**: Single component has multiple UI sections, conditional rendering blocks, or repeated patterns.
**Dify Convention**: Place sub-components in subdirectories or as separate files in the same directory.
```typescript
// ❌ Before: Monolithic JSX with multiple sections
const AppInfo = () => {
return (
<div>
{/* 100 lines of header UI */}
{/* 100 lines of operations UI */}
{/* 100 lines of modals */}
</div>
)
}
// ✅ After: Split into focused components
// app-info/
// ├── index.tsx (orchestration only)
// ├── app-header.tsx (header UI)
// ├── app-operations.tsx (operations UI)
// └── app-modals.tsx (modal management)
const AppInfo = () => {
const { showModal, setShowModal } = useAppInfoModals()
return (
<div>
<AppHeader appDetail={appDetail} />
<AppOperations onAction={handleAction} />
<AppModals show={showModal} onClose={() => setShowModal(null)} />
</div>
)
}
```
**Dify Examples**:
- `web/app/components/app/configuration/` directory structure
- `web/app/components/workflow/nodes/` per-node organization
### Pattern 3: Simplify Conditional Logic
**When**: Deep nesting (> 3 levels), complex ternaries, or multiple `if/else` chains.
```typescript
// ❌ Before: Deeply nested conditionals
const Template = useMemo(() => {
if (appDetail?.mode === AppModeEnum.CHAT) {
switch (locale) {
case LanguagesSupported[1]:
return <TemplateChatZh />
case LanguagesSupported[7]:
return <TemplateChatJa />
default:
return <TemplateChatEn />
}
}
if (appDetail?.mode === AppModeEnum.ADVANCED_CHAT) {
// Another 15 lines...
}
// More conditions...
}, [appDetail, locale])
// ✅ After: Use lookup tables + early returns
const TEMPLATE_MAP = {
[AppModeEnum.CHAT]: {
[LanguagesSupported[1]]: TemplateChatZh,
[LanguagesSupported[7]]: TemplateChatJa,
default: TemplateChatEn,
},
[AppModeEnum.ADVANCED_CHAT]: {
[LanguagesSupported[1]]: TemplateAdvancedChatZh,
// ...
},
}
const Template = useMemo(() => {
const modeTemplates = TEMPLATE_MAP[appDetail?.mode]
if (!modeTemplates) return null
const TemplateComponent = modeTemplates[locale] || modeTemplates.default
return <TemplateComponent appDetail={appDetail} />
}, [appDetail, locale])
```
### Pattern 4: Extract API/Data Logic
**When**: Component directly handles API calls, data transformation, or complex async operations.
**Dify Convention**: Use `@tanstack/react-query` hooks from `web/service/use-*.ts` or create custom data hooks.
```typescript
// ❌ Before: API logic in component
const MCPServiceCard = () => {
const [basicAppConfig, setBasicAppConfig] = useState({})
useEffect(() => {
if (isBasicApp && appId) {
(async () => {
const res = await fetchAppDetail({ url: '/apps', id: appId })
setBasicAppConfig(res?.model_config || {})
})()
}
}, [appId, isBasicApp])
// More API-related logic...
}
// ✅ After: Extract to data hook using React Query
// use-app-config.ts
import { useQuery } from '@tanstack/react-query'
import { get } from '@/service/base'
const NAME_SPACE = 'appConfig'
export const useAppConfig = (appId: string, isBasicApp: boolean) => {
return useQuery({
enabled: isBasicApp && !!appId,
queryKey: [NAME_SPACE, 'detail', appId],
queryFn: () => get<AppDetailResponse>(`/apps/${appId}`),
select: data => data?.model_config || {},
})
}
// Component becomes cleaner
const MCPServiceCard = () => {
const { data: config, isLoading } = useAppConfig(appId, isBasicApp)
// UI only
}
```
**React Query Best Practices in Dify**:
- Define `NAME_SPACE` for query key organization
- Use `enabled` option for conditional fetching
- Use `select` for data transformation
- Export invalidation hooks: `useInvalidXxx`
**Dify Examples**:
- `web/service/use-workflow.ts`
- `web/service/use-common.ts`
- `web/service/knowledge/use-dataset.ts`
- `web/service/knowledge/use-document.ts`
### Pattern 5: Extract Modal/Dialog Management
**When**: Component manages multiple modals with complex open/close states.
**Dify Convention**: Modals should be extracted with their state management.
```typescript
// ❌ Before: Multiple modal states in component
const AppInfo = () => {
const [showEditModal, setShowEditModal] = useState(false)
const [showDuplicateModal, setShowDuplicateModal] = useState(false)
const [showConfirmDelete, setShowConfirmDelete] = useState(false)
const [showSwitchModal, setShowSwitchModal] = useState(false)
const [showImportDSLModal, setShowImportDSLModal] = useState(false)
// 5+ more modal states...
}
// ✅ After: Extract to modal management hook
type ModalType = 'edit' | 'duplicate' | 'delete' | 'switch' | 'import' | null
const useAppInfoModals = () => {
const [activeModal, setActiveModal] = useState<ModalType>(null)
const openModal = useCallback((type: ModalType) => setActiveModal(type), [])
const closeModal = useCallback(() => setActiveModal(null), [])
return {
activeModal,
openModal,
closeModal,
isOpen: (type: ModalType) => activeModal === type,
}
}
```
### Pattern 6: Extract Form Logic
**When**: Complex form validation, submission handling, or field transformation.
**Dify Convention**: Use `@tanstack/react-form` patterns from `web/app/components/base/form/`.
```typescript
// ✅ Use existing form infrastructure
import { useAppForm } from '@/app/components/base/form'
const ConfigForm = () => {
const form = useAppForm({
defaultValues: { name: '', description: '' },
onSubmit: handleSubmit,
})
return <form.Provider>...</form.Provider>
}
```
## Dify-Specific Refactoring Guidelines
### 1. Context Provider Extraction
**When**: Component provides complex context values with multiple states.
```typescript
// ❌ Before: Large context value object
const value = {
appId, isAPIKeySet, isTrailFinished, mode, modelModeType,
promptMode, isAdvancedMode, isAgent, isOpenAI, isFunctionCall,
// 50+ more properties...
}
return <ConfigContext.Provider value={value}>...</ConfigContext.Provider>
// ✅ After: Split into domain-specific contexts
<ModelConfigProvider value={modelConfigValue}>
<DatasetConfigProvider value={datasetConfigValue}>
<UIConfigProvider value={uiConfigValue}>
{children}
</UIConfigProvider>
</DatasetConfigProvider>
</ModelConfigProvider>
```
**Dify Reference**: `web/context/` directory structure
### 2. Workflow Node Components
**When**: Refactoring workflow node components (`web/app/components/workflow/nodes/`).
**Conventions**:
- Keep node logic in `use-interactions.ts`
- Extract panel UI to separate files
- Use `_base` components for common patterns
```
nodes/<node-type>/
├── index.tsx # Node registration
├── node.tsx # Node visual component
├── panel.tsx # Configuration panel
├── use-interactions.ts # Node-specific hooks
└── types.ts # Type definitions
```
### 3. Configuration Components
**When**: Refactoring app configuration components.
**Conventions**:
- Separate config sections into subdirectories
- Use existing patterns from `web/app/components/app/configuration/`
- Keep feature toggles in dedicated components
### 4. Tool/Plugin Components
**When**: Refactoring tool-related components (`web/app/components/tools/`).
**Conventions**:
- Follow existing modal patterns
- Use service hooks from `web/service/use-tools.ts`
- Keep provider-specific logic isolated
## Refactoring Workflow
### Step 1: Generate Refactoring Prompt
```bash
pnpm refactor-component <path>
```
This command will:
- Analyze component complexity and features
- Identify specific refactoring actions needed
- Generate a prompt for AI assistant (auto-copied to clipboard on macOS)
- Provide detailed requirements based on detected patterns
### Step 2: Analyze Details
```bash
pnpm analyze-component <path> --json
```
Identify:
- Total complexity score
- Max function complexity
- Line count
- Features detected (state, effects, API, etc.)
### Step 3: Plan
Create a refactoring plan based on detected features:
| Detected Feature | Refactoring Action |
|------------------|-------------------|
| `hasState: true` + `hasEffects: true` | Extract custom hook |
| `hasAPI: true` | Extract data/service hook |
| `hasEvents: true` (many) | Extract event handlers |
| `lineCount > 300` | Split into sub-components |
| `maxComplexity > 50` | Simplify conditional logic |
### Step 4: Execute Incrementally
1. **Extract one piece at a time**
2. **Run lint, type-check, and tests after each extraction**
3. **Verify functionality before next step**
```
For each extraction:
┌────────────────────────────────────────┐
│ 1. Extract code │
│ 2. Run: pnpm lint:fix │
│ 3. Run: pnpm type-check:tsgo │
│ 4. Run: pnpm test │
│ 5. Test functionality manually │
│ 6. PASS? → Next extraction │
│ FAIL? → Fix before continuing │
└────────────────────────────────────────┘
```
### Step 5: Verify
After refactoring:
```bash
# Re-run refactor command to verify improvements
pnpm refactor-component <path>
# If complexity < 25 and lines < 200, you'll see:
# ✅ COMPONENT IS WELL-STRUCTURED
# For detailed metrics:
pnpm analyze-component <path> --json
# Target metrics:
# - complexity < 50
# - lineCount < 300
# - maxComplexity < 30
```
## Common Mistakes to Avoid
### ❌ Over-Engineering
```typescript
// ❌ Too many tiny hooks
const useButtonText = () => useState('Click')
const useButtonDisabled = () => useState(false)
const useButtonLoading = () => useState(false)
// ✅ Cohesive hook with related state
const useButtonState = () => {
const [text, setText] = useState('Click')
const [disabled, setDisabled] = useState(false)
const [loading, setLoading] = useState(false)
return { text, setText, disabled, setDisabled, loading, setLoading }
}
```
### ❌ Breaking Existing Patterns
- Follow existing directory structures
- Maintain naming conventions
- Preserve export patterns for compatibility
### ❌ Premature Abstraction
- Only extract when there's clear complexity benefit
- Don't create abstractions for single-use code
- Keep refactored code in the same domain area
## References
### Dify Codebase Examples
- **Hook extraction**: `web/app/components/app/configuration/hooks/`
- **Component splitting**: `web/app/components/app/configuration/`
- **Service hooks**: `web/service/use-*.ts`
- **Workflow patterns**: `web/app/components/workflow/hooks/`
- **Form patterns**: `web/app/components/base/form/`
### Related Skills
- `frontend-testing` - For testing refactored components
- `web/testing/testing.md` - Testing specification

View File

@@ -1,493 +0,0 @@
# Complexity Reduction Patterns
This document provides patterns for reducing cognitive complexity in Dify React components.
## Understanding Complexity
### SonarJS Cognitive Complexity
The `pnpm analyze-component` tool uses SonarJS cognitive complexity metrics:
- **Total Complexity**: Sum of all functions' complexity in the file
- **Max Complexity**: Highest single function complexity
### What Increases Complexity
| Pattern | Complexity Impact |
|---------|-------------------|
| `if/else` | +1 per branch |
| Nested conditions | +1 per nesting level |
| `switch/case` | +1 per case |
| `for/while/do` | +1 per loop |
| `&&`/`||` chains | +1 per operator |
| Nested callbacks | +1 per nesting level |
| `try/catch` | +1 per catch |
| Ternary expressions | +1 per nesting |
## Pattern 1: Replace Conditionals with Lookup Tables
**Before** (complexity: ~15):
```typescript
const Template = useMemo(() => {
if (appDetail?.mode === AppModeEnum.CHAT) {
switch (locale) {
case LanguagesSupported[1]:
return <TemplateChatZh appDetail={appDetail} />
case LanguagesSupported[7]:
return <TemplateChatJa appDetail={appDetail} />
default:
return <TemplateChatEn appDetail={appDetail} />
}
}
if (appDetail?.mode === AppModeEnum.ADVANCED_CHAT) {
switch (locale) {
case LanguagesSupported[1]:
return <TemplateAdvancedChatZh appDetail={appDetail} />
case LanguagesSupported[7]:
return <TemplateAdvancedChatJa appDetail={appDetail} />
default:
return <TemplateAdvancedChatEn appDetail={appDetail} />
}
}
if (appDetail?.mode === AppModeEnum.WORKFLOW) {
// Similar pattern...
}
return null
}, [appDetail, locale])
```
**After** (complexity: ~3):
```typescript
// Define lookup table outside component
const TEMPLATE_MAP: Record<AppModeEnum, Record<string, FC<TemplateProps>>> = {
[AppModeEnum.CHAT]: {
[LanguagesSupported[1]]: TemplateChatZh,
[LanguagesSupported[7]]: TemplateChatJa,
default: TemplateChatEn,
},
[AppModeEnum.ADVANCED_CHAT]: {
[LanguagesSupported[1]]: TemplateAdvancedChatZh,
[LanguagesSupported[7]]: TemplateAdvancedChatJa,
default: TemplateAdvancedChatEn,
},
[AppModeEnum.WORKFLOW]: {
[LanguagesSupported[1]]: TemplateWorkflowZh,
[LanguagesSupported[7]]: TemplateWorkflowJa,
default: TemplateWorkflowEn,
},
// ...
}
// Clean component logic
const Template = useMemo(() => {
if (!appDetail?.mode) return null
const templates = TEMPLATE_MAP[appDetail.mode]
if (!templates) return null
const TemplateComponent = templates[locale] ?? templates.default
return <TemplateComponent appDetail={appDetail} />
}, [appDetail, locale])
```
## Pattern 2: Use Early Returns
**Before** (complexity: ~10):
```typescript
const handleSubmit = () => {
if (isValid) {
if (hasChanges) {
if (isConnected) {
submitData()
} else {
showConnectionError()
}
} else {
showNoChangesMessage()
}
} else {
showValidationError()
}
}
```
**After** (complexity: ~4):
```typescript
const handleSubmit = () => {
if (!isValid) {
showValidationError()
return
}
if (!hasChanges) {
showNoChangesMessage()
return
}
if (!isConnected) {
showConnectionError()
return
}
submitData()
}
```
## Pattern 3: Extract Complex Conditions
**Before** (complexity: high):
```typescript
const canPublish = (() => {
if (mode !== AppModeEnum.COMPLETION) {
if (!isAdvancedMode)
return true
if (modelModeType === ModelModeType.completion) {
if (!hasSetBlockStatus.history || !hasSetBlockStatus.query)
return false
return true
}
return true
}
return !promptEmpty
})()
```
**After** (complexity: lower):
```typescript
// Extract to named functions
const canPublishInCompletionMode = () => !promptEmpty
const canPublishInChatMode = () => {
if (!isAdvancedMode) return true
if (modelModeType !== ModelModeType.completion) return true
return hasSetBlockStatus.history && hasSetBlockStatus.query
}
// Clean main logic
const canPublish = mode === AppModeEnum.COMPLETION
? canPublishInCompletionMode()
: canPublishInChatMode()
```
## Pattern 4: Replace Chained Ternaries
**Before** (complexity: ~5):
```typescript
const statusText = serverActivated
? t('status.running')
: serverPublished
? t('status.inactive')
: appUnpublished
? t('status.unpublished')
: t('status.notConfigured')
```
**After** (complexity: ~2):
```typescript
const getStatusText = () => {
if (serverActivated) return t('status.running')
if (serverPublished) return t('status.inactive')
if (appUnpublished) return t('status.unpublished')
return t('status.notConfigured')
}
const statusText = getStatusText()
```
Or use lookup:
```typescript
const STATUS_TEXT_MAP = {
running: 'status.running',
inactive: 'status.inactive',
unpublished: 'status.unpublished',
notConfigured: 'status.notConfigured',
} as const
const getStatusKey = (): keyof typeof STATUS_TEXT_MAP => {
if (serverActivated) return 'running'
if (serverPublished) return 'inactive'
if (appUnpublished) return 'unpublished'
return 'notConfigured'
}
const statusText = t(STATUS_TEXT_MAP[getStatusKey()])
```
## Pattern 5: Flatten Nested Loops
**Before** (complexity: high):
```typescript
const processData = (items: Item[]) => {
const results: ProcessedItem[] = []
for (const item of items) {
if (item.isValid) {
for (const child of item.children) {
if (child.isActive) {
for (const prop of child.properties) {
if (prop.value !== null) {
results.push({
itemId: item.id,
childId: child.id,
propValue: prop.value,
})
}
}
}
}
}
}
return results
}
```
**After** (complexity: lower):
```typescript
// Use functional approach
const processData = (items: Item[]) => {
return items
.filter(item => item.isValid)
.flatMap(item =>
item.children
.filter(child => child.isActive)
.flatMap(child =>
child.properties
.filter(prop => prop.value !== null)
.map(prop => ({
itemId: item.id,
childId: child.id,
propValue: prop.value,
}))
)
)
}
```
## Pattern 6: Extract Event Handler Logic
**Before** (complexity: high in component):
```typescript
const Component = () => {
const handleSelect = (data: DataSet[]) => {
if (isEqual(data.map(item => item.id), dataSets.map(item => item.id))) {
hideSelectDataSet()
return
}
formattingChangedDispatcher()
let newDatasets = data
if (data.find(item => !item.name)) {
const newSelected = produce(data, (draft) => {
data.forEach((item, index) => {
if (!item.name) {
const newItem = dataSets.find(i => i.id === item.id)
if (newItem)
draft[index] = newItem
}
})
})
setDataSets(newSelected)
newDatasets = newSelected
}
else {
setDataSets(data)
}
hideSelectDataSet()
// 40 more lines of logic...
}
return <div>...</div>
}
```
**After** (complexity: lower):
```typescript
// Extract to hook or utility
const useDatasetSelection = (dataSets: DataSet[], setDataSets: SetState<DataSet[]>) => {
const normalizeSelection = (data: DataSet[]) => {
const hasUnloadedItem = data.some(item => !item.name)
if (!hasUnloadedItem) return data
return produce(data, (draft) => {
data.forEach((item, index) => {
if (!item.name) {
const existing = dataSets.find(i => i.id === item.id)
if (existing) draft[index] = existing
}
})
})
}
const hasSelectionChanged = (newData: DataSet[]) => {
return !isEqual(
newData.map(item => item.id),
dataSets.map(item => item.id)
)
}
return { normalizeSelection, hasSelectionChanged }
}
// Component becomes cleaner
const Component = () => {
const { normalizeSelection, hasSelectionChanged } = useDatasetSelection(dataSets, setDataSets)
const handleSelect = (data: DataSet[]) => {
if (!hasSelectionChanged(data)) {
hideSelectDataSet()
return
}
formattingChangedDispatcher()
const normalized = normalizeSelection(data)
setDataSets(normalized)
hideSelectDataSet()
}
return <div>...</div>
}
```
## Pattern 7: Reduce Boolean Logic Complexity
**Before** (complexity: ~8):
```typescript
const toggleDisabled = hasInsufficientPermissions
|| appUnpublished
|| missingStartNode
|| triggerModeDisabled
|| (isAdvancedApp && !currentWorkflow?.graph)
|| (isBasicApp && !basicAppConfig.updated_at)
```
**After** (complexity: ~3):
```typescript
// Extract meaningful boolean functions
const isAppReady = () => {
if (isAdvancedApp) return !!currentWorkflow?.graph
return !!basicAppConfig.updated_at
}
const hasRequiredPermissions = () => {
return isCurrentWorkspaceEditor && !hasInsufficientPermissions
}
const canToggle = () => {
if (!hasRequiredPermissions()) return false
if (!isAppReady()) return false
if (missingStartNode) return false
if (triggerModeDisabled) return false
return true
}
const toggleDisabled = !canToggle()
```
## Pattern 8: Simplify useMemo/useCallback Dependencies
**Before** (complexity: multiple recalculations):
```typescript
const payload = useMemo(() => {
let parameters: Parameter[] = []
let outputParameters: OutputParameter[] = []
if (!published) {
parameters = (inputs || []).map((item) => ({
name: item.variable,
description: '',
form: 'llm',
required: item.required,
type: item.type,
}))
outputParameters = (outputs || []).map((item) => ({
name: item.variable,
description: '',
type: item.value_type,
}))
}
else if (detail && detail.tool) {
parameters = (inputs || []).map((item) => ({
// Complex transformation...
}))
outputParameters = (outputs || []).map((item) => ({
// Complex transformation...
}))
}
return {
icon: detail?.icon || icon,
label: detail?.label || name,
// ...more fields
}
}, [detail, published, workflowAppId, icon, name, description, inputs, outputs])
```
**After** (complexity: separated concerns):
```typescript
// Separate transformations
const useParameterTransform = (inputs: InputVar[], detail?: ToolDetail, published?: boolean) => {
return useMemo(() => {
if (!published) {
return inputs.map(item => ({
name: item.variable,
description: '',
form: 'llm',
required: item.required,
type: item.type,
}))
}
if (!detail?.tool) return []
return inputs.map(item => ({
name: item.variable,
required: item.required,
type: item.type === 'paragraph' ? 'string' : item.type,
description: detail.tool.parameters.find(p => p.name === item.variable)?.llm_description || '',
form: detail.tool.parameters.find(p => p.name === item.variable)?.form || 'llm',
}))
}, [inputs, detail, published])
}
// Component uses hook
const parameters = useParameterTransform(inputs, detail, published)
const outputParameters = useOutputTransform(outputs, detail, published)
const payload = useMemo(() => ({
icon: detail?.icon || icon,
label: detail?.label || name,
parameters,
outputParameters,
// ...
}), [detail, icon, name, parameters, outputParameters])
```
## Target Metrics After Refactoring
| Metric | Target |
|--------|--------|
| Total Complexity | < 50 |
| Max Function Complexity | < 30 |
| Function Length | < 30 lines |
| Nesting Depth | ≤ 3 levels |
| Conditional Chains | ≤ 3 conditions |

View File

@@ -1,477 +0,0 @@
# Component Splitting Patterns
This document provides detailed guidance on splitting large components into smaller, focused components in Dify.
## When to Split Components
Split a component when you identify:
1. **Multiple UI sections** - Distinct visual areas with minimal coupling that can be composed independently
1. **Conditional rendering blocks** - Large `{condition && <JSX />}` blocks
1. **Repeated patterns** - Similar UI structures used multiple times
1. **300+ lines** - Component exceeds manageable size
1. **Modal clusters** - Multiple modals rendered in one component
## Splitting Strategies
### Strategy 1: Section-Based Splitting
Identify visual sections and extract each as a component.
```typescript
// ❌ Before: Monolithic component (500+ lines)
const ConfigurationPage = () => {
return (
<div>
{/* Header Section - 50 lines */}
<div className="header">
<h1>{t('configuration.title')}</h1>
<div className="actions">
{isAdvancedMode && <Badge>Advanced</Badge>}
<ModelParameterModal ... />
<AppPublisher ... />
</div>
</div>
{/* Config Section - 200 lines */}
<div className="config">
<Config />
</div>
{/* Debug Section - 150 lines */}
<div className="debug">
<Debug ... />
</div>
{/* Modals Section - 100 lines */}
{showSelectDataSet && <SelectDataSet ... />}
{showHistoryModal && <EditHistoryModal ... />}
{showUseGPT4Confirm && <Confirm ... />}
</div>
)
}
// ✅ After: Split into focused components
// configuration/
// ├── index.tsx (orchestration)
// ├── configuration-header.tsx
// ├── configuration-content.tsx
// ├── configuration-debug.tsx
// └── configuration-modals.tsx
// configuration-header.tsx
interface ConfigurationHeaderProps {
isAdvancedMode: boolean
onPublish: () => void
}
const ConfigurationHeader: FC<ConfigurationHeaderProps> = ({
isAdvancedMode,
onPublish,
}) => {
const { t } = useTranslation()
return (
<div className="header">
<h1>{t('configuration.title')}</h1>
<div className="actions">
{isAdvancedMode && <Badge>Advanced</Badge>}
<ModelParameterModal ... />
<AppPublisher onPublish={onPublish} />
</div>
</div>
)
}
// index.tsx (orchestration only)
const ConfigurationPage = () => {
const { modelConfig, setModelConfig } = useModelConfig()
const { activeModal, openModal, closeModal } = useModalState()
return (
<div>
<ConfigurationHeader
isAdvancedMode={isAdvancedMode}
onPublish={handlePublish}
/>
<ConfigurationContent
modelConfig={modelConfig}
onConfigChange={setModelConfig}
/>
{!isMobile && (
<ConfigurationDebug
inputs={inputs}
onSetting={handleSetting}
/>
)}
<ConfigurationModals
activeModal={activeModal}
onClose={closeModal}
/>
</div>
)
}
```
### Strategy 2: Conditional Block Extraction
Extract large conditional rendering blocks.
```typescript
// ❌ Before: Large conditional blocks
const AppInfo = () => {
return (
<div>
{expand ? (
<div className="expanded">
{/* 100 lines of expanded view */}
</div>
) : (
<div className="collapsed">
{/* 50 lines of collapsed view */}
</div>
)}
</div>
)
}
// ✅ After: Separate view components
const AppInfoExpanded: FC<AppInfoViewProps> = ({ appDetail, onAction }) => {
return (
<div className="expanded">
{/* Clean, focused expanded view */}
</div>
)
}
const AppInfoCollapsed: FC<AppInfoViewProps> = ({ appDetail, onAction }) => {
return (
<div className="collapsed">
{/* Clean, focused collapsed view */}
</div>
)
}
const AppInfo = () => {
return (
<div>
{expand
? <AppInfoExpanded appDetail={appDetail} onAction={handleAction} />
: <AppInfoCollapsed appDetail={appDetail} onAction={handleAction} />
}
</div>
)
}
```
### Strategy 3: Modal Extraction
Extract modals with their trigger logic.
```typescript
// ❌ Before: Multiple modals in one component
const AppInfo = () => {
const [showEdit, setShowEdit] = useState(false)
const [showDuplicate, setShowDuplicate] = useState(false)
const [showDelete, setShowDelete] = useState(false)
const [showSwitch, setShowSwitch] = useState(false)
const onEdit = async (data) => { /* 20 lines */ }
const onDuplicate = async (data) => { /* 20 lines */ }
const onDelete = async () => { /* 15 lines */ }
return (
<div>
{/* Main content */}
{showEdit && <EditModal onConfirm={onEdit} onClose={() => setShowEdit(false)} />}
{showDuplicate && <DuplicateModal onConfirm={onDuplicate} onClose={() => setShowDuplicate(false)} />}
{showDelete && <DeleteConfirm onConfirm={onDelete} onClose={() => setShowDelete(false)} />}
{showSwitch && <SwitchModal ... />}
</div>
)
}
// ✅ After: Modal manager component
// app-info-modals.tsx
type ModalType = 'edit' | 'duplicate' | 'delete' | 'switch' | null
interface AppInfoModalsProps {
appDetail: AppDetail
activeModal: ModalType
onClose: () => void
onSuccess: () => void
}
const AppInfoModals: FC<AppInfoModalsProps> = ({
appDetail,
activeModal,
onClose,
onSuccess,
}) => {
const handleEdit = async (data) => { /* logic */ }
const handleDuplicate = async (data) => { /* logic */ }
const handleDelete = async () => { /* logic */ }
return (
<>
{activeModal === 'edit' && (
<EditModal
appDetail={appDetail}
onConfirm={handleEdit}
onClose={onClose}
/>
)}
{activeModal === 'duplicate' && (
<DuplicateModal
appDetail={appDetail}
onConfirm={handleDuplicate}
onClose={onClose}
/>
)}
{activeModal === 'delete' && (
<DeleteConfirm
onConfirm={handleDelete}
onClose={onClose}
/>
)}
{activeModal === 'switch' && (
<SwitchModal
appDetail={appDetail}
onClose={onClose}
/>
)}
</>
)
}
// Parent component
const AppInfo = () => {
const { activeModal, openModal, closeModal } = useModalState()
return (
<div>
{/* Main content with openModal triggers */}
<Button onClick={() => openModal('edit')}>Edit</Button>
<AppInfoModals
appDetail={appDetail}
activeModal={activeModal}
onClose={closeModal}
onSuccess={handleSuccess}
/>
</div>
)
}
```
### Strategy 4: List Item Extraction
Extract repeated item rendering.
```typescript
// ❌ Before: Inline item rendering
const OperationsList = () => {
return (
<div>
{operations.map(op => (
<div key={op.id} className="operation-item">
<span className="icon">{op.icon}</span>
<span className="title">{op.title}</span>
<span className="description">{op.description}</span>
<button onClick={() => op.onClick()}>
{op.actionLabel}
</button>
{op.badge && <Badge>{op.badge}</Badge>}
{/* More complex rendering... */}
</div>
))}
</div>
)
}
// ✅ After: Extracted item component
interface OperationItemProps {
operation: Operation
onAction: (id: string) => void
}
const OperationItem: FC<OperationItemProps> = ({ operation, onAction }) => {
return (
<div className="operation-item">
<span className="icon">{operation.icon}</span>
<span className="title">{operation.title}</span>
<span className="description">{operation.description}</span>
<button onClick={() => onAction(operation.id)}>
{operation.actionLabel}
</button>
{operation.badge && <Badge>{operation.badge}</Badge>}
</div>
)
}
const OperationsList = () => {
const handleAction = useCallback((id: string) => {
const op = operations.find(o => o.id === id)
op?.onClick()
}, [operations])
return (
<div>
{operations.map(op => (
<OperationItem
key={op.id}
operation={op}
onAction={handleAction}
/>
))}
</div>
)
}
```
## Directory Structure Patterns
### Pattern A: Flat Structure (Simple Components)
For components with 2-3 sub-components:
```
component-name/
├── index.tsx # Main component
├── sub-component-a.tsx
├── sub-component-b.tsx
└── types.ts # Shared types
```
### Pattern B: Nested Structure (Complex Components)
For components with many sub-components:
```
component-name/
├── index.tsx # Main orchestration
├── types.ts # Shared types
├── hooks/
│ ├── use-feature-a.ts
│ └── use-feature-b.ts
├── components/
│ ├── header/
│ │ └── index.tsx
│ ├── content/
│ │ └── index.tsx
│ └── modals/
│ └── index.tsx
└── utils/
└── helpers.ts
```
### Pattern C: Feature-Based Structure (Dify Standard)
Following Dify's existing patterns:
```
configuration/
├── index.tsx # Main page component
├── base/ # Base/shared components
│ ├── feature-panel/
│ ├── group-name/
│ └── operation-btn/
├── config/ # Config section
│ ├── index.tsx
│ ├── agent/
│ └── automatic/
├── dataset-config/ # Dataset section
│ ├── index.tsx
│ ├── card-item/
│ └── params-config/
├── debug/ # Debug section
│ ├── index.tsx
│ └── hooks.tsx
└── hooks/ # Shared hooks
└── use-advanced-prompt-config.ts
```
## Props Design
### Minimal Props Principle
Pass only what's needed:
```typescript
// ❌ Bad: Passing entire objects when only some fields needed
<ConfigHeader appDetail={appDetail} modelConfig={modelConfig} />
// ✅ Good: Destructure to minimum required
<ConfigHeader
appName={appDetail.name}
isAdvancedMode={modelConfig.isAdvanced}
onPublish={handlePublish}
/>
```
### Callback Props Pattern
Use callbacks for child-to-parent communication:
```typescript
// Parent
const Parent = () => {
const [value, setValue] = useState('')
return (
<Child
value={value}
onChange={setValue}
onSubmit={handleSubmit}
/>
)
}
// Child
interface ChildProps {
value: string
onChange: (value: string) => void
onSubmit: () => void
}
const Child: FC<ChildProps> = ({ value, onChange, onSubmit }) => {
return (
<div>
<input value={value} onChange={e => onChange(e.target.value)} />
<button onClick={onSubmit}>Submit</button>
</div>
)
}
```
### Render Props for Flexibility
When sub-components need parent context:
```typescript
interface ListProps<T> {
items: T[]
renderItem: (item: T, index: number) => React.ReactNode
renderEmpty?: () => React.ReactNode
}
function List<T>({ items, renderItem, renderEmpty }: ListProps<T>) {
if (items.length === 0 && renderEmpty) {
return <>{renderEmpty()}</>
}
return (
<div>
{items.map((item, index) => renderItem(item, index))}
</div>
)
}
// Usage
<List
items={operations}
renderItem={(op, i) => <OperationItem key={i} operation={op} />}
renderEmpty={() => <EmptyState message="No operations" />}
/>
```

View File

@@ -1,317 +0,0 @@
# Hook Extraction Patterns
This document provides detailed guidance on extracting custom hooks from complex components in Dify.
## When to Extract Hooks
Extract a custom hook when you identify:
1. **Coupled state groups** - Multiple `useState` hooks that are always used together
1. **Complex effects** - `useEffect` with multiple dependencies or cleanup logic
1. **Business logic** - Data transformations, validations, or calculations
1. **Reusable patterns** - Logic that appears in multiple components
## Extraction Process
### Step 1: Identify State Groups
Look for state variables that are logically related:
```typescript
// ❌ These belong together - extract to hook
const [modelConfig, setModelConfig] = useState<ModelConfig>(...)
const [completionParams, setCompletionParams] = useState<FormValue>({})
const [modelModeType, setModelModeType] = useState<ModelModeType>(...)
// These are model-related state that should be in useModelConfig()
```
### Step 2: Identify Related Effects
Find effects that modify the grouped state:
```typescript
// ❌ These effects belong with the state above
useEffect(() => {
if (hasFetchedDetail && !modelModeType) {
const mode = currModel?.model_properties.mode
if (mode) {
const newModelConfig = produce(modelConfig, (draft) => {
draft.mode = mode
})
setModelConfig(newModelConfig)
}
}
}, [textGenerationModelList, hasFetchedDetail, modelModeType, currModel])
```
### Step 3: Create the Hook
```typescript
// hooks/use-model-config.ts
import type { FormValue } from '@/app/components/header/account-setting/model-provider-page/declarations'
import type { ModelConfig } from '@/models/debug'
import { produce } from 'immer'
import { useEffect, useState } from 'react'
import { ModelModeType } from '@/types/app'
interface UseModelConfigParams {
initialConfig?: Partial<ModelConfig>
currModel?: { model_properties?: { mode?: ModelModeType } }
hasFetchedDetail: boolean
}
interface UseModelConfigReturn {
modelConfig: ModelConfig
setModelConfig: (config: ModelConfig) => void
completionParams: FormValue
setCompletionParams: (params: FormValue) => void
modelModeType: ModelModeType
}
export const useModelConfig = ({
initialConfig,
currModel,
hasFetchedDetail,
}: UseModelConfigParams): UseModelConfigReturn => {
const [modelConfig, setModelConfig] = useState<ModelConfig>({
provider: 'langgenius/openai/openai',
model_id: 'gpt-3.5-turbo',
mode: ModelModeType.unset,
// ... default values
...initialConfig,
})
const [completionParams, setCompletionParams] = useState<FormValue>({})
const modelModeType = modelConfig.mode
// Fill old app data missing model mode
useEffect(() => {
if (hasFetchedDetail && !modelModeType) {
const mode = currModel?.model_properties?.mode
if (mode) {
setModelConfig(produce(modelConfig, (draft) => {
draft.mode = mode
}))
}
}
}, [hasFetchedDetail, modelModeType, currModel])
return {
modelConfig,
setModelConfig,
completionParams,
setCompletionParams,
modelModeType,
}
}
```
### Step 4: Update Component
```typescript
// Before: 50+ lines of state management
const Configuration: FC = () => {
const [modelConfig, setModelConfig] = useState<ModelConfig>(...)
// ... lots of related state and effects
}
// After: Clean component
const Configuration: FC = () => {
const {
modelConfig,
setModelConfig,
completionParams,
setCompletionParams,
modelModeType,
} = useModelConfig({
currModel,
hasFetchedDetail,
})
// Component now focuses on UI
}
```
## Naming Conventions
### Hook Names
- Use `use` prefix: `useModelConfig`, `useDatasetConfig`
- Be specific: `useAdvancedPromptConfig` not `usePrompt`
- Include domain: `useWorkflowVariables`, `useMCPServer`
### File Names
- Kebab-case: `use-model-config.ts`
- Place in `hooks/` subdirectory when multiple hooks exist
- Place alongside component for single-use hooks
### Return Type Names
- Suffix with `Return`: `UseModelConfigReturn`
- Suffix params with `Params`: `UseModelConfigParams`
## Common Hook Patterns in Dify
### 1. Data Fetching Hook (React Query)
```typescript
// Pattern: Use @tanstack/react-query for data fetching
import { useQuery, useQueryClient } from '@tanstack/react-query'
import { get } from '@/service/base'
import { useInvalid } from '@/service/use-base'
const NAME_SPACE = 'appConfig'
// Query keys for cache management
export const appConfigQueryKeys = {
detail: (appId: string) => [NAME_SPACE, 'detail', appId] as const,
}
// Main data hook
export const useAppConfig = (appId: string) => {
return useQuery({
enabled: !!appId,
queryKey: appConfigQueryKeys.detail(appId),
queryFn: () => get<AppDetailResponse>(`/apps/${appId}`),
select: data => data?.model_config || null,
})
}
// Invalidation hook for refreshing data
export const useInvalidAppConfig = () => {
return useInvalid([NAME_SPACE])
}
// Usage in component
const Component = () => {
const { data: config, isLoading, error, refetch } = useAppConfig(appId)
const invalidAppConfig = useInvalidAppConfig()
const handleRefresh = () => {
invalidAppConfig() // Invalidates cache and triggers refetch
}
return <div>...</div>
}
```
### 2. Form State Hook
```typescript
// Pattern: Form state + validation + submission
export const useConfigForm = (initialValues: ConfigFormValues) => {
const [values, setValues] = useState(initialValues)
const [errors, setErrors] = useState<Record<string, string>>({})
const [isSubmitting, setIsSubmitting] = useState(false)
const validate = useCallback(() => {
const newErrors: Record<string, string> = {}
if (!values.name) newErrors.name = 'Name is required'
setErrors(newErrors)
return Object.keys(newErrors).length === 0
}, [values])
const handleChange = useCallback((field: string, value: any) => {
setValues(prev => ({ ...prev, [field]: value }))
}, [])
const handleSubmit = useCallback(async (onSubmit: (values: ConfigFormValues) => Promise<void>) => {
if (!validate()) return
setIsSubmitting(true)
try {
await onSubmit(values)
} finally {
setIsSubmitting(false)
}
}, [values, validate])
return { values, errors, isSubmitting, handleChange, handleSubmit }
}
```
### 3. Modal State Hook
```typescript
// Pattern: Multiple modal management
type ModalType = 'edit' | 'delete' | 'duplicate' | null
export const useModalState = () => {
const [activeModal, setActiveModal] = useState<ModalType>(null)
const [modalData, setModalData] = useState<any>(null)
const openModal = useCallback((type: ModalType, data?: any) => {
setActiveModal(type)
setModalData(data)
}, [])
const closeModal = useCallback(() => {
setActiveModal(null)
setModalData(null)
}, [])
return {
activeModal,
modalData,
openModal,
closeModal,
isOpen: useCallback((type: ModalType) => activeModal === type, [activeModal]),
}
}
```
### 4. Toggle/Boolean Hook
```typescript
// Pattern: Boolean state with convenience methods
export const useToggle = (initialValue = false) => {
const [value, setValue] = useState(initialValue)
const toggle = useCallback(() => setValue(v => !v), [])
const setTrue = useCallback(() => setValue(true), [])
const setFalse = useCallback(() => setValue(false), [])
return [value, { toggle, setTrue, setFalse, set: setValue }] as const
}
// Usage
const [isExpanded, { toggle, setTrue: expand, setFalse: collapse }] = useToggle()
```
## Testing Extracted Hooks
After extraction, test hooks in isolation:
```typescript
// use-model-config.spec.ts
import { renderHook, act } from '@testing-library/react'
import { useModelConfig } from './use-model-config'
describe('useModelConfig', () => {
it('should initialize with default values', () => {
const { result } = renderHook(() => useModelConfig({
hasFetchedDetail: false,
}))
expect(result.current.modelConfig.provider).toBe('langgenius/openai/openai')
expect(result.current.modelModeType).toBe(ModelModeType.unset)
})
it('should update model config', () => {
const { result } = renderHook(() => useModelConfig({
hasFetchedDetail: true,
}))
act(() => {
result.current.setModelConfig({
...result.current.modelConfig,
model_id: 'gpt-4',
})
})
expect(result.current.modelConfig.model_id).toBe('gpt-4')
})
})
```

View File

@@ -1,73 +0,0 @@
---
name: frontend-code-review
description: "Trigger when the user requests a review of frontend files (e.g., `.tsx`, `.ts`, `.js`). Support both pending-change reviews and focused file reviews while applying the checklist rules."
---
# Frontend Code Review
## Intent
Use this skill whenever the user asks to review frontend code (especially `.tsx`, `.ts`, or `.js` files). Support two review modes:
1. **Pending-change review** inspect staged/working-tree files slated for commit and flag checklist violations before submission.
2. **File-targeted review** review the specific file(s) the user names and report the relevant checklist findings.
Stick to the checklist below for every applicable file and mode.
## Checklist
See [references/code-quality.md](references/code-quality.md), [references/performance.md](references/performance.md), [references/business-logic.md](references/business-logic.md) for the living checklist split by category—treat it as the canonical set of rules to follow.
Flag each rule violation with urgency metadata so future reviewers can prioritize fixes.
## Review Process
1. Open the relevant component/module. Gather lines that relate to class names, React Flow hooks, prop memoization, and styling.
2. For each rule in the review point, note where the code deviates and capture a representative snippet.
3. Compose the review section per the template below. Group violations first by **Urgent** flag, then by category order (Code Quality, Performance, Business Logic).
## Required output
When invoked, the response must exactly follow one of the two templates:
### Template A (any findings)
```
# Code review
Found <N> urgent issues need to be fixed:
## 1 <brief description of bug>
FilePath: <path> line <line>
<relevant code snippet or pointer>
### Suggested fix
<brief description of suggested fix>
---
... (repeat for each urgent issue) ...
Found <M> suggestions for improvement:
## 1 <brief description of suggestion>
FilePath: <path> line <line>
<relevant code snippet or pointer>
### Suggested fix
<brief description of suggested fix>
---
... (repeat for each suggestion) ...
```
If there are no urgent issues, omit that section. If there are no suggestions, omit that section.
If the issue number is more than 10, summarize as "10+ urgent issues" or "10+ suggestions" and just output the first 10 issues.
Don't compress the blank lines between sections; keep them as-is for readability.
If you use Template A (i.e., there are issues to fix) and at least one issue requires code changes, append a brief follow-up question after the structured output asking whether the user wants you to apply the suggested fix(es). For example: "Would you like me to use the Suggested fix section to address these issues?"
### Template B (no issues)
```
## Code review
No issues found.
```

View File

@@ -1,15 +0,0 @@
# Rule Catalog — Business Logic
## Can't use workflowStore in Node components
IsUrgent: True
### Description
File path pattern of node components: `web/app/components/workflow/nodes/[nodeName]/node.tsx`
Node components are also used when creating a RAG Pipe from a template, but in that context there is no workflowStore Provider, which results in a blank screen. [This Issue](https://github.com/langgenius/dify/issues/29168) was caused by exactly this reason.
### Suggested Fix
Use `import { useNodes } from 'reactflow'` instead of `import useNodes from '@/app/components/workflow/store/workflow/use-nodes'`.

View File

@@ -1,44 +0,0 @@
# Rule Catalog — Code Quality
## Conditional class names use utility function
IsUrgent: True
Category: Code Quality
### Description
Ensure conditional CSS is handled via the shared `classNames` instead of custom ternaries, string concatenation, or template strings. Centralizing class logic keeps components consistent and easier to maintain.
### Suggested Fix
```ts
import { cn } from '@/utils/classnames'
const classNames = cn(isActive ? 'text-primary-600' : 'text-gray-500')
```
## Tailwind-first styling
IsUrgent: True
Category: Code Quality
### Description
Favor Tailwind CSS utility classes instead of adding new `.module.css` files unless a Tailwind combination cannot achieve the required styling. Keeping styles in Tailwind improves consistency and reduces maintenance overhead.
Update this file when adding, editing, or removing Code Quality rules so the catalog remains accurate.
## Classname ordering for easy overrides
### Description
When writing components, always place the incoming `className` prop after the components own class values so that downstream consumers can override or extend the styling. This keeps your components defaults but still lets external callers change or remove specific styles.
Example:
```tsx
import { cn } from '@/utils/classnames'
const Button = ({ className }) => {
return <div className={cn('bg-primary-600', className)}></div>
}
```

View File

@@ -1,45 +0,0 @@
# Rule Catalog — Performance
## React Flow data usage
IsUrgent: True
Category: Performance
### Description
When rendering React Flow, prefer `useNodes`/`useEdges` for UI consumption and rely on `useStoreApi` inside callbacks that mutate or read node/edge state. Avoid manually pulling Flow data outside of these hooks.
## Complex prop memoization
IsUrgent: True
Category: Performance
### Description
Wrap complex prop values (objects, arrays, maps) in `useMemo` prior to passing them into child components to guarantee stable references and prevent unnecessary renders.
Update this file when adding, editing, or removing Performance rules so the catalog remains accurate.
Wrong:
```tsx
<HeavyComp
config={{
provider: ...,
detail: ...
}}
/>
```
Right:
```tsx
const config = useMemo(() => ({
provider: ...,
detail: ...
}), [provider, detail]);
<HeavyComp
config={config}
/>
```

View File

@@ -1,325 +0,0 @@
---
name: frontend-testing
description: Generate Vitest + React Testing Library tests for Dify frontend components, hooks, and utilities. Triggers on testing, spec files, coverage, Vitest, RTL, unit tests, integration tests, or write/review test requests.
---
# Dify Frontend Testing Skill
This skill enables Claude to generate high-quality, comprehensive frontend tests for the Dify project following established conventions and best practices.
> **⚠️ Authoritative Source**: This skill is derived from `web/testing/testing.md`. Use Vitest mock/timer APIs (`vi.*`).
## When to Apply This Skill
Apply this skill when the user:
- Asks to **write tests** for a component, hook, or utility
- Asks to **review existing tests** for completeness
- Mentions **Vitest**, **React Testing Library**, **RTL**, or **spec files**
- Requests **test coverage** improvement
- Uses `pnpm analyze-component` output as context
- Mentions **testing**, **unit tests**, or **integration tests** for frontend code
- Wants to understand **testing patterns** in the Dify codebase
**Do NOT apply** when:
- User is asking about backend/API tests (Python/pytest)
- User is asking about E2E tests (Playwright/Cypress)
- User is only asking conceptual questions without code context
## Quick Reference
### Tech Stack
| Tool | Version | Purpose |
|------|---------|---------|
| Vitest | 4.0.16 | Test runner |
| React Testing Library | 16.0 | Component testing |
| jsdom | - | Test environment |
| nock | 14.0 | HTTP mocking |
| TypeScript | 5.x | Type safety |
### Key Commands
```bash
# Run all tests
pnpm test
# Watch mode
pnpm test:watch
# Run specific file
pnpm test path/to/file.spec.tsx
# Generate coverage report
pnpm test:coverage
# Analyze component complexity
pnpm analyze-component <path>
# Review existing test
pnpm analyze-component <path> --review
```
### File Naming
- Test files: `ComponentName.spec.tsx` (same directory as component)
- Integration tests: `web/__tests__/` directory
## Test Structure Template
```typescript
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import Component from './index'
// ✅ Import real project components (DO NOT mock these)
// import Loading from '@/app/components/base/loading'
// import { ChildComponent } from './child-component'
// ✅ Mock external dependencies only
vi.mock('@/service/api')
vi.mock('next/navigation', () => ({
useRouter: () => ({ push: vi.fn() }),
usePathname: () => '/test',
}))
// ✅ Zustand stores: Use real stores (auto-mocked globally)
// Set test state with: useAppStore.setState({ ... })
// Shared state for mocks (if needed)
let mockSharedState = false
describe('ComponentName', () => {
beforeEach(() => {
vi.clearAllMocks() // ✅ Reset mocks BEFORE each test
mockSharedState = false // ✅ Reset shared state
})
// Rendering tests (REQUIRED)
describe('Rendering', () => {
it('should render without crashing', () => {
// Arrange
const props = { title: 'Test' }
// Act
render(<Component {...props} />)
// Assert
expect(screen.getByText('Test')).toBeInTheDocument()
})
})
// Props tests (REQUIRED)
describe('Props', () => {
it('should apply custom className', () => {
render(<Component className="custom" />)
expect(screen.getByRole('button')).toHaveClass('custom')
})
})
// User Interactions
describe('User Interactions', () => {
it('should handle click events', () => {
const handleClick = vi.fn()
render(<Component onClick={handleClick} />)
fireEvent.click(screen.getByRole('button'))
expect(handleClick).toHaveBeenCalledTimes(1)
})
})
// Edge Cases (REQUIRED)
describe('Edge Cases', () => {
it('should handle null data', () => {
render(<Component data={null} />)
expect(screen.getByText(/no data/i)).toBeInTheDocument()
})
it('should handle empty array', () => {
render(<Component items={[]} />)
expect(screen.getByText(/empty/i)).toBeInTheDocument()
})
})
})
```
## Testing Workflow (CRITICAL)
### ⚠️ Incremental Approach Required
**NEVER generate all test files at once.** For complex components or multi-file directories:
1. **Analyze & Plan**: List all files, order by complexity (simple → complex)
1. **Process ONE at a time**: Write test → Run test → Fix if needed → Next
1. **Verify before proceeding**: Do NOT continue to next file until current passes
```
For each file:
┌────────────────────────────────────────┐
│ 1. Write test │
│ 2. Run: pnpm test <file>.spec.tsx │
│ 3. PASS? → Mark complete, next file │
│ FAIL? → Fix first, then continue │
└────────────────────────────────────────┘
```
### Complexity-Based Order
Process in this order for multi-file testing:
1. 🟢 Utility functions (simplest)
1. 🟢 Custom hooks
1. 🟡 Simple components (presentational)
1. 🟡 Medium components (state, effects)
1. 🔴 Complex components (API, routing)
1. 🔴 Integration tests (index files - last)
### When to Refactor First
- **Complexity > 50**: Break into smaller pieces before testing
- **500+ lines**: Consider splitting before testing
- **Many dependencies**: Extract logic into hooks first
> 📖 See `references/workflow.md` for complete workflow details and todo list format.
## Testing Strategy
### Path-Level Testing (Directory Testing)
When assigned to test a directory/path, test **ALL content** within that path:
- Test all components, hooks, utilities in the directory (not just `index` file)
- Use incremental approach: one file at a time, verify each before proceeding
- Goal: 100% coverage of ALL files in the directory
### Integration Testing First
**Prefer integration testing** when writing tests for a directory:
-**Import real project components** directly (including base components and siblings)
-**Only mock**: API services (`@/service/*`), `next/navigation`, complex context providers
-**DO NOT mock** base components (`@/app/components/base/*`)
-**DO NOT mock** sibling/child components in the same directory
> See [Test Structure Template](#test-structure-template) for correct import/mock patterns.
## Core Principles
### 1. AAA Pattern (Arrange-Act-Assert)
Every test should clearly separate:
- **Arrange**: Setup test data and render component
- **Act**: Perform user actions
- **Assert**: Verify expected outcomes
### 2. Black-Box Testing
- Test observable behavior, not implementation details
- Use semantic queries (getByRole, getByLabelText)
- Avoid testing internal state directly
- **Prefer pattern matching over hardcoded strings** in assertions:
```typescript
// ❌ Avoid: hardcoded text assertions
expect(screen.getByText('Loading...')).toBeInTheDocument()
// ✅ Better: role-based queries
expect(screen.getByRole('status')).toBeInTheDocument()
// ✅ Better: pattern matching
expect(screen.getByText(/loading/i)).toBeInTheDocument()
```
### 3. Single Behavior Per Test
Each test verifies ONE user-observable behavior:
```typescript
// ✅ Good: One behavior
it('should disable button when loading', () => {
render(<Button loading />)
expect(screen.getByRole('button')).toBeDisabled()
})
// ❌ Bad: Multiple behaviors
it('should handle loading state', () => {
render(<Button loading />)
expect(screen.getByRole('button')).toBeDisabled()
expect(screen.getByText('Loading...')).toBeInTheDocument()
expect(screen.getByRole('button')).toHaveClass('loading')
})
```
### 4. Semantic Naming
Use `should <behavior> when <condition>`:
```typescript
it('should show error message when validation fails')
it('should call onSubmit when form is valid')
it('should disable input when isReadOnly is true')
```
## Required Test Scenarios
### Always Required (All Components)
1. **Rendering**: Component renders without crashing
1. **Props**: Required props, optional props, default values
1. **Edge Cases**: null, undefined, empty values, boundary conditions
### Conditional (When Present)
| Feature | Test Focus |
|---------|-----------|
| `useState` | Initial state, transitions, cleanup |
| `useEffect` | Execution, dependencies, cleanup |
| Event handlers | All onClick, onChange, onSubmit, keyboard |
| API calls | Loading, success, error states |
| Routing | Navigation, params, query strings |
| `useCallback`/`useMemo` | Referential equality |
| Context | Provider values, consumer behavior |
| Forms | Validation, submission, error display |
## Coverage Goals (Per File)
For each test file generated, aim for:
-**100%** function coverage
-**100%** statement coverage
-**>95%** branch coverage
-**>95%** line coverage
> **Note**: For multi-file directories, process one file at a time with full coverage each. See `references/workflow.md`.
## Detailed Guides
For more detailed information, refer to:
- `references/workflow.md` - **Incremental testing workflow** (MUST READ for multi-file testing)
- `references/mocking.md` - Mock patterns, Zustand store testing, and best practices
- `references/async-testing.md` - Async operations and API calls
- `references/domain-components.md` - Workflow, Dataset, Configuration testing
- `references/common-patterns.md` - Frequently used testing patterns
- `references/checklist.md` - Test generation checklist and validation steps
## Authoritative References
### Primary Specification (MUST follow)
- **`web/testing/testing.md`** - The canonical testing specification. This skill is derived from this document.
### Reference Examples in Codebase
- `web/utils/classnames.spec.ts` - Utility function tests
- `web/app/components/base/button/index.spec.tsx` - Component tests
- `web/__mocks__/provider-context.ts` - Mock factory example
### Project Configuration
- `web/vitest.config.ts` - Vitest configuration
- `web/vitest.setup.ts` - Test environment setup
- `web/scripts/analyze-component.js` - Component analysis tool
- Modules are not mocked automatically. Global mocks live in `web/vitest.setup.ts` (for example `react-i18next`, `next/image`); mock other modules like `ky` or `mime` locally in test files.

View File

@@ -1,293 +0,0 @@
/**
* Test Template for React Components
*
* WHY THIS STRUCTURE?
* - Organized sections make tests easy to navigate and maintain
* - Mocks at top ensure consistent test isolation
* - Factory functions reduce duplication and improve readability
* - describe blocks group related scenarios for better debugging
*
* INSTRUCTIONS:
* 1. Replace `ComponentName` with your component name
* 2. Update import path
* 3. Add/remove test sections based on component features (use analyze-component)
* 4. Follow AAA pattern: Arrange → Act → Assert
*
* RUN FIRST: pnpm analyze-component <path> to identify required test scenarios
*/
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
// import ComponentName from './index'
// ============================================================================
// Mocks
// ============================================================================
// WHY: Mocks must be hoisted to top of file (Vitest requirement).
// They run BEFORE imports, so keep them before component imports.
// i18n (automatically mocked)
// WHY: Global mock in web/vitest.setup.ts is auto-loaded by Vitest setup
// The global mock provides: useTranslation, Trans, useMixedTranslation, useGetLanguage
// No explicit mock needed for most tests
//
// Override only if custom translations are required:
// import { createReactI18nextMock } from '@/test/i18n-mock'
// vi.mock('react-i18next', () => createReactI18nextMock({
// 'my.custom.key': 'Custom Translation',
// 'button.save': 'Save',
// }))
// Router (if component uses useRouter, usePathname, useSearchParams)
// WHY: Isolates tests from Next.js routing, enables testing navigation behavior
// const mockPush = vi.fn()
// vi.mock('next/navigation', () => ({
// useRouter: () => ({ push: mockPush }),
// usePathname: () => '/test-path',
// }))
// API services (if component fetches data)
// WHY: Prevents real network calls, enables testing all states (loading/success/error)
// vi.mock('@/service/api')
// import * as api from '@/service/api'
// const mockedApi = vi.mocked(api)
// Shared mock state (for portal/dropdown components)
// WHY: Portal components like PortalToFollowElem need shared state between
// parent and child mocks to correctly simulate open/close behavior
// let mockOpenState = false
// ============================================================================
// Test Data Factories
// ============================================================================
// WHY FACTORIES?
// - Avoid hard-coded test data scattered across tests
// - Easy to create variations with overrides
// - Type-safe when using actual types from source
// - Single source of truth for default test values
// const createMockProps = (overrides = {}) => ({
// // Default props that make component render successfully
// ...overrides,
// })
// const createMockItem = (overrides = {}) => ({
// id: 'item-1',
// name: 'Test Item',
// ...overrides,
// })
// ============================================================================
// Test Helpers
// ============================================================================
// const renderComponent = (props = {}) => {
// return render(<ComponentName {...createMockProps(props)} />)
// }
// ============================================================================
// Tests
// ============================================================================
describe('ComponentName', () => {
// WHY beforeEach with clearAllMocks?
// - Ensures each test starts with clean slate
// - Prevents mock call history from leaking between tests
// - MUST be beforeEach (not afterEach) to reset BEFORE assertions like toHaveBeenCalledTimes
beforeEach(() => {
vi.clearAllMocks()
// Reset shared mock state if used (CRITICAL for portal/dropdown tests)
// mockOpenState = false
})
// --------------------------------------------------------------------------
// Rendering Tests (REQUIRED - Every component MUST have these)
// --------------------------------------------------------------------------
// WHY: Catches import errors, missing providers, and basic render issues
describe('Rendering', () => {
it('should render without crashing', () => {
// Arrange - Setup data and mocks
// const props = createMockProps()
// Act - Render the component
// render(<ComponentName {...props} />)
// Assert - Verify expected output
// Prefer getByRole for accessibility; it's what users "see"
// expect(screen.getByRole('...')).toBeInTheDocument()
})
it('should render with default props', () => {
// WHY: Verifies component works without optional props
// render(<ComponentName />)
// expect(screen.getByText('...')).toBeInTheDocument()
})
})
// --------------------------------------------------------------------------
// Props Tests (REQUIRED - Every component MUST test prop behavior)
// --------------------------------------------------------------------------
// WHY: Props are the component's API contract. Test them thoroughly.
describe('Props', () => {
it('should apply custom className', () => {
// WHY: Common pattern in Dify - components should merge custom classes
// render(<ComponentName className="custom-class" />)
// expect(screen.getByTestId('component')).toHaveClass('custom-class')
})
it('should use default values for optional props', () => {
// WHY: Verifies TypeScript defaults work at runtime
// render(<ComponentName />)
// expect(screen.getByRole('...')).toHaveAttribute('...', 'default-value')
})
})
// --------------------------------------------------------------------------
// User Interactions (if component has event handlers - on*, handle*)
// --------------------------------------------------------------------------
// WHY: Event handlers are core functionality. Test from user's perspective.
describe('User Interactions', () => {
it('should call onClick when clicked', async () => {
// WHY userEvent over fireEvent?
// - userEvent simulates real user behavior (focus, hover, then click)
// - fireEvent is lower-level, doesn't trigger all browser events
// const user = userEvent.setup()
// const handleClick = vi.fn()
// render(<ComponentName onClick={handleClick} />)
//
// await user.click(screen.getByRole('button'))
//
// expect(handleClick).toHaveBeenCalledTimes(1)
})
it('should call onChange when value changes', async () => {
// const user = userEvent.setup()
// const handleChange = vi.fn()
// render(<ComponentName onChange={handleChange} />)
//
// await user.type(screen.getByRole('textbox'), 'new value')
//
// expect(handleChange).toHaveBeenCalled()
})
})
// --------------------------------------------------------------------------
// State Management (if component uses useState/useReducer)
// --------------------------------------------------------------------------
// WHY: Test state through observable UI changes, not internal state values
describe('State Management', () => {
it('should update state on interaction', async () => {
// WHY test via UI, not state?
// - State is implementation detail; UI is what users see
// - If UI works correctly, state must be correct
// const user = userEvent.setup()
// render(<ComponentName />)
//
// // Initial state - verify what user sees
// expect(screen.getByText('Initial')).toBeInTheDocument()
//
// // Trigger state change via user action
// await user.click(screen.getByRole('button'))
//
// // New state - verify UI updated
// expect(screen.getByText('Updated')).toBeInTheDocument()
})
})
// --------------------------------------------------------------------------
// Async Operations (if component fetches data - useQuery, fetch)
// --------------------------------------------------------------------------
// WHY: Async operations have 3 states users experience: loading, success, error
describe('Async Operations', () => {
it('should show loading state', () => {
// WHY never-resolving promise?
// - Keeps component in loading state for assertion
// - Alternative: use fake timers
// mockedApi.fetchData.mockImplementation(() => new Promise(() => {}))
// render(<ComponentName />)
//
// expect(screen.getByText(/loading/i)).toBeInTheDocument()
})
it('should show data on success', async () => {
// WHY waitFor?
// - Component updates asynchronously after fetch resolves
// - waitFor retries assertion until it passes or times out
// mockedApi.fetchData.mockResolvedValue({ items: ['Item 1'] })
// render(<ComponentName />)
//
// await waitFor(() => {
// expect(screen.getByText('Item 1')).toBeInTheDocument()
// })
})
it('should show error on failure', async () => {
// mockedApi.fetchData.mockRejectedValue(new Error('Network error'))
// render(<ComponentName />)
//
// await waitFor(() => {
// expect(screen.getByText(/error/i)).toBeInTheDocument()
// })
})
})
// --------------------------------------------------------------------------
// Edge Cases (REQUIRED - Every component MUST handle edge cases)
// --------------------------------------------------------------------------
// WHY: Real-world data is messy. Components must handle:
// - Null/undefined from API failures or optional fields
// - Empty arrays/strings from user clearing data
// - Boundary values (0, MAX_INT, special characters)
describe('Edge Cases', () => {
it('should handle null value', () => {
// WHY test null specifically?
// - API might return null for missing data
// - Prevents "Cannot read property of null" in production
// render(<ComponentName value={null} />)
// expect(screen.getByText(/no data/i)).toBeInTheDocument()
})
it('should handle undefined value', () => {
// WHY test undefined separately from null?
// - TypeScript treats them differently
// - Optional props are undefined, not null
// render(<ComponentName value={undefined} />)
// expect(screen.getByText(/no data/i)).toBeInTheDocument()
})
it('should handle empty array', () => {
// WHY: Empty state often needs special UI (e.g., "No items yet")
// render(<ComponentName items={[]} />)
// expect(screen.getByText(/empty/i)).toBeInTheDocument()
})
it('should handle empty string', () => {
// WHY: Empty strings are truthy in JS but visually empty
// render(<ComponentName text="" />)
// expect(screen.getByText(/placeholder/i)).toBeInTheDocument()
})
})
// --------------------------------------------------------------------------
// Accessibility (optional but recommended for Dify's enterprise users)
// --------------------------------------------------------------------------
// WHY: Dify has enterprise customers who may require accessibility compliance
describe('Accessibility', () => {
it('should have accessible name', () => {
// WHY getByRole with name?
// - Tests that screen readers can identify the element
// - Enforces proper labeling practices
// render(<ComponentName label="Test Label" />)
// expect(screen.getByRole('button', { name: /test label/i })).toBeInTheDocument()
})
it('should support keyboard navigation', async () => {
// WHY: Some users can't use a mouse
// const user = userEvent.setup()
// render(<ComponentName />)
//
// await user.tab()
// expect(screen.getByRole('button')).toHaveFocus()
})
})
})

View File

@@ -1,207 +0,0 @@
/**
* Test Template for Custom Hooks
*
* Instructions:
* 1. Replace `useHookName` with your hook name
* 2. Update import path
* 3. Add/remove test sections based on hook features
*/
import { renderHook, act, waitFor } from '@testing-library/react'
// import { useHookName } from './use-hook-name'
// ============================================================================
// Mocks
// ============================================================================
// API services (if hook fetches data)
// vi.mock('@/service/api')
// import * as api from '@/service/api'
// const mockedApi = vi.mocked(api)
// ============================================================================
// Test Helpers
// ============================================================================
// Wrapper for hooks that need context
// const createWrapper = (contextValue = {}) => {
// return ({ children }: { children: React.ReactNode }) => (
// <SomeContext.Provider value={contextValue}>
// {children}
// </SomeContext.Provider>
// )
// }
// ============================================================================
// Tests
// ============================================================================
describe('useHookName', () => {
beforeEach(() => {
vi.clearAllMocks()
})
// --------------------------------------------------------------------------
// Initial State
// --------------------------------------------------------------------------
describe('Initial State', () => {
it('should return initial state', () => {
// const { result } = renderHook(() => useHookName())
//
// expect(result.current.value).toBe(initialValue)
// expect(result.current.isLoading).toBe(false)
})
it('should accept initial value from props', () => {
// const { result } = renderHook(() => useHookName({ initialValue: 'custom' }))
//
// expect(result.current.value).toBe('custom')
})
})
// --------------------------------------------------------------------------
// State Updates
// --------------------------------------------------------------------------
describe('State Updates', () => {
it('should update value when setValue is called', () => {
// const { result } = renderHook(() => useHookName())
//
// act(() => {
// result.current.setValue('new value')
// })
//
// expect(result.current.value).toBe('new value')
})
it('should reset to initial value', () => {
// const { result } = renderHook(() => useHookName({ initialValue: 'initial' }))
//
// act(() => {
// result.current.setValue('changed')
// })
// expect(result.current.value).toBe('changed')
//
// act(() => {
// result.current.reset()
// })
// expect(result.current.value).toBe('initial')
})
})
// --------------------------------------------------------------------------
// Async Operations
// --------------------------------------------------------------------------
describe('Async Operations', () => {
it('should fetch data on mount', async () => {
// mockedApi.fetchData.mockResolvedValue({ data: 'test' })
//
// const { result } = renderHook(() => useHookName())
//
// // Initially loading
// expect(result.current.isLoading).toBe(true)
//
// // Wait for data
// await waitFor(() => {
// expect(result.current.isLoading).toBe(false)
// })
//
// expect(result.current.data).toEqual({ data: 'test' })
})
it('should handle fetch error', async () => {
// mockedApi.fetchData.mockRejectedValue(new Error('Network error'))
//
// const { result } = renderHook(() => useHookName())
//
// await waitFor(() => {
// expect(result.current.error).toBeTruthy()
// })
//
// expect(result.current.error?.message).toBe('Network error')
})
it('should refetch when dependency changes', async () => {
// mockedApi.fetchData.mockResolvedValue({ data: 'test' })
//
// const { result, rerender } = renderHook(
// ({ id }) => useHookName(id),
// { initialProps: { id: '1' } }
// )
//
// await waitFor(() => {
// expect(mockedApi.fetchData).toHaveBeenCalledWith('1')
// })
//
// rerender({ id: '2' })
//
// await waitFor(() => {
// expect(mockedApi.fetchData).toHaveBeenCalledWith('2')
// })
})
})
// --------------------------------------------------------------------------
// Side Effects
// --------------------------------------------------------------------------
describe('Side Effects', () => {
it('should call callback when value changes', () => {
// const callback = vi.fn()
// const { result } = renderHook(() => useHookName({ onChange: callback }))
//
// act(() => {
// result.current.setValue('new value')
// })
//
// expect(callback).toHaveBeenCalledWith('new value')
})
it('should cleanup on unmount', () => {
// const cleanup = vi.fn()
// vi.spyOn(window, 'addEventListener')
// vi.spyOn(window, 'removeEventListener')
//
// const { unmount } = renderHook(() => useHookName())
//
// expect(window.addEventListener).toHaveBeenCalled()
//
// unmount()
//
// expect(window.removeEventListener).toHaveBeenCalled()
})
})
// --------------------------------------------------------------------------
// Edge Cases
// --------------------------------------------------------------------------
describe('Edge Cases', () => {
it('should handle null input', () => {
// const { result } = renderHook(() => useHookName(null))
//
// expect(result.current.value).toBeNull()
})
it('should handle rapid updates', () => {
// const { result } = renderHook(() => useHookName())
//
// act(() => {
// result.current.setValue('1')
// result.current.setValue('2')
// result.current.setValue('3')
// })
//
// expect(result.current.value).toBe('3')
})
})
// --------------------------------------------------------------------------
// With Context (if hook uses context)
// --------------------------------------------------------------------------
describe('With Context', () => {
it('should use context value', () => {
// const wrapper = createWrapper({ someValue: 'context-value' })
// const { result } = renderHook(() => useHookName(), { wrapper })
//
// expect(result.current.contextValue).toBe('context-value')
})
})
})

View File

@@ -1,154 +0,0 @@
/**
* Test Template for Utility Functions
*
* Instructions:
* 1. Replace `utilityFunction` with your function name
* 2. Update import path
* 3. Use test.each for data-driven tests
*/
// import { utilityFunction } from './utility'
// ============================================================================
// Tests
// ============================================================================
describe('utilityFunction', () => {
// --------------------------------------------------------------------------
// Basic Functionality
// --------------------------------------------------------------------------
describe('Basic Functionality', () => {
it('should return expected result for valid input', () => {
// expect(utilityFunction('input')).toBe('expected-output')
})
it('should handle multiple arguments', () => {
// expect(utilityFunction('a', 'b', 'c')).toBe('abc')
})
})
// --------------------------------------------------------------------------
// Data-Driven Tests
// --------------------------------------------------------------------------
describe('Input/Output Mapping', () => {
test.each([
// [input, expected]
['input1', 'output1'],
['input2', 'output2'],
['input3', 'output3'],
])('should return %s for input %s', (input, expected) => {
// expect(utilityFunction(input)).toBe(expected)
})
})
// --------------------------------------------------------------------------
// Edge Cases
// --------------------------------------------------------------------------
describe('Edge Cases', () => {
it('should handle empty string', () => {
// expect(utilityFunction('')).toBe('')
})
it('should handle null', () => {
// expect(utilityFunction(null)).toBe(null)
// or
// expect(() => utilityFunction(null)).toThrow()
})
it('should handle undefined', () => {
// expect(utilityFunction(undefined)).toBe(undefined)
// or
// expect(() => utilityFunction(undefined)).toThrow()
})
it('should handle empty array', () => {
// expect(utilityFunction([])).toEqual([])
})
it('should handle empty object', () => {
// expect(utilityFunction({})).toEqual({})
})
})
// --------------------------------------------------------------------------
// Boundary Conditions
// --------------------------------------------------------------------------
describe('Boundary Conditions', () => {
it('should handle minimum value', () => {
// expect(utilityFunction(0)).toBe(0)
})
it('should handle maximum value', () => {
// expect(utilityFunction(Number.MAX_SAFE_INTEGER)).toBe(...)
})
it('should handle negative numbers', () => {
// expect(utilityFunction(-1)).toBe(...)
})
})
// --------------------------------------------------------------------------
// Type Coercion (if applicable)
// --------------------------------------------------------------------------
describe('Type Handling', () => {
it('should handle numeric string', () => {
// expect(utilityFunction('123')).toBe(123)
})
it('should handle boolean', () => {
// expect(utilityFunction(true)).toBe(...)
})
})
// --------------------------------------------------------------------------
// Error Cases
// --------------------------------------------------------------------------
describe('Error Handling', () => {
it('should throw for invalid input', () => {
// expect(() => utilityFunction('invalid')).toThrow('Error message')
})
it('should throw with specific error type', () => {
// expect(() => utilityFunction('invalid')).toThrow(ValidationError)
})
})
// --------------------------------------------------------------------------
// Complex Objects (if applicable)
// --------------------------------------------------------------------------
describe('Object Handling', () => {
it('should preserve object structure', () => {
// const input = { a: 1, b: 2 }
// expect(utilityFunction(input)).toEqual({ a: 1, b: 2 })
})
it('should handle nested objects', () => {
// const input = { nested: { deep: 'value' } }
// expect(utilityFunction(input)).toEqual({ nested: { deep: 'transformed' } })
})
it('should not mutate input', () => {
// const input = { a: 1 }
// const inputCopy = { ...input }
// utilityFunction(input)
// expect(input).toEqual(inputCopy)
})
})
// --------------------------------------------------------------------------
// Array Handling (if applicable)
// --------------------------------------------------------------------------
describe('Array Handling', () => {
it('should process all elements', () => {
// expect(utilityFunction([1, 2, 3])).toEqual([2, 4, 6])
})
it('should handle single element array', () => {
// expect(utilityFunction([1])).toEqual([2])
})
it('should preserve order', () => {
// expect(utilityFunction(['c', 'a', 'b'])).toEqual(['c', 'a', 'b'])
})
})
})

View File

@@ -1,345 +0,0 @@
# Async Testing Guide
## Core Async Patterns
### 1. waitFor - Wait for Condition
```typescript
import { render, screen, waitFor } from '@testing-library/react'
it('should load and display data', async () => {
render(<DataComponent />)
// Wait for element to appear
await waitFor(() => {
expect(screen.getByText('Loaded Data')).toBeInTheDocument()
})
})
it('should hide loading spinner after load', async () => {
render(<DataComponent />)
// Wait for element to disappear
await waitFor(() => {
expect(screen.queryByText('Loading...')).not.toBeInTheDocument()
})
})
```
### 2. findBy\* - Async Queries
```typescript
it('should show user name after fetch', async () => {
render(<UserProfile />)
// findBy returns a promise, auto-waits up to 1000ms
const userName = await screen.findByText('John Doe')
expect(userName).toBeInTheDocument()
// findByRole with options
const button = await screen.findByRole('button', { name: /submit/i })
expect(button).toBeEnabled()
})
```
### 3. userEvent for Async Interactions
```typescript
import userEvent from '@testing-library/user-event'
it('should submit form', async () => {
const user = userEvent.setup()
const onSubmit = vi.fn()
render(<Form onSubmit={onSubmit} />)
// userEvent methods are async
await user.type(screen.getByLabelText('Email'), 'test@example.com')
await user.click(screen.getByRole('button', { name: /submit/i }))
await waitFor(() => {
expect(onSubmit).toHaveBeenCalledWith({ email: 'test@example.com' })
})
})
```
## Fake Timers
### When to Use Fake Timers
- Testing components with `setTimeout`/`setInterval`
- Testing debounce/throttle behavior
- Testing animations or delayed transitions
- Testing polling or retry logic
### Basic Fake Timer Setup
```typescript
describe('Debounced Search', () => {
beforeEach(() => {
vi.useFakeTimers()
})
afterEach(() => {
vi.useRealTimers()
})
it('should debounce search input', async () => {
const onSearch = vi.fn()
render(<SearchInput onSearch={onSearch} debounceMs={300} />)
// Type in the input
fireEvent.change(screen.getByRole('textbox'), { target: { value: 'query' } })
// Search not called immediately
expect(onSearch).not.toHaveBeenCalled()
// Advance timers
vi.advanceTimersByTime(300)
// Now search is called
expect(onSearch).toHaveBeenCalledWith('query')
})
})
```
### Fake Timers with Async Code
```typescript
it('should retry on failure', async () => {
vi.useFakeTimers()
const fetchData = vi.fn()
.mockRejectedValueOnce(new Error('Network error'))
.mockResolvedValueOnce({ data: 'success' })
render(<RetryComponent fetchData={fetchData} retryDelayMs={1000} />)
// First call fails
await waitFor(() => {
expect(fetchData).toHaveBeenCalledTimes(1)
})
// Advance timer for retry
vi.advanceTimersByTime(1000)
// Second call succeeds
await waitFor(() => {
expect(fetchData).toHaveBeenCalledTimes(2)
expect(screen.getByText('success')).toBeInTheDocument()
})
vi.useRealTimers()
})
```
### Common Fake Timer Utilities
```typescript
// Run all pending timers
vi.runAllTimers()
// Run only pending timers (not new ones created during execution)
vi.runOnlyPendingTimers()
// Advance by specific time
vi.advanceTimersByTime(1000)
// Get current fake time
Date.now()
// Clear all timers
vi.clearAllTimers()
```
## API Testing Patterns
### Loading → Success → Error States
```typescript
describe('DataFetcher', () => {
beforeEach(() => {
vi.clearAllMocks()
})
it('should show loading state', () => {
mockedApi.fetchData.mockImplementation(() => new Promise(() => {})) // Never resolves
render(<DataFetcher />)
expect(screen.getByTestId('loading-spinner')).toBeInTheDocument()
})
it('should show data on success', async () => {
mockedApi.fetchData.mockResolvedValue({ items: ['Item 1', 'Item 2'] })
render(<DataFetcher />)
// Use findBy* for multiple async elements (better error messages than waitFor with multiple assertions)
const item1 = await screen.findByText('Item 1')
const item2 = await screen.findByText('Item 2')
expect(item1).toBeInTheDocument()
expect(item2).toBeInTheDocument()
expect(screen.queryByTestId('loading-spinner')).not.toBeInTheDocument()
})
it('should show error on failure', async () => {
mockedApi.fetchData.mockRejectedValue(new Error('Failed to fetch'))
render(<DataFetcher />)
await waitFor(() => {
expect(screen.getByText(/failed to fetch/i)).toBeInTheDocument()
})
})
it('should retry on error', async () => {
mockedApi.fetchData.mockRejectedValue(new Error('Network error'))
render(<DataFetcher />)
await waitFor(() => {
expect(screen.getByRole('button', { name: /retry/i })).toBeInTheDocument()
})
mockedApi.fetchData.mockResolvedValue({ items: ['Item 1'] })
fireEvent.click(screen.getByRole('button', { name: /retry/i }))
await waitFor(() => {
expect(screen.getByText('Item 1')).toBeInTheDocument()
})
})
})
```
### Testing Mutations
```typescript
it('should submit form and show success', async () => {
const user = userEvent.setup()
mockedApi.createItem.mockResolvedValue({ id: '1', name: 'New Item' })
render(<CreateItemForm />)
await user.type(screen.getByLabelText('Name'), 'New Item')
await user.click(screen.getByRole('button', { name: /create/i }))
// Button should be disabled during submission
expect(screen.getByRole('button', { name: /creating/i })).toBeDisabled()
await waitFor(() => {
expect(screen.getByText(/created successfully/i)).toBeInTheDocument()
})
expect(mockedApi.createItem).toHaveBeenCalledWith({ name: 'New Item' })
})
```
## useEffect Testing
### Testing Effect Execution
```typescript
it('should fetch data on mount', async () => {
const fetchData = vi.fn().mockResolvedValue({ data: 'test' })
render(<ComponentWithEffect fetchData={fetchData} />)
await waitFor(() => {
expect(fetchData).toHaveBeenCalledTimes(1)
})
})
```
### Testing Effect Dependencies
```typescript
it('should refetch when id changes', async () => {
const fetchData = vi.fn().mockResolvedValue({ data: 'test' })
const { rerender } = render(<ComponentWithEffect id="1" fetchData={fetchData} />)
await waitFor(() => {
expect(fetchData).toHaveBeenCalledWith('1')
})
rerender(<ComponentWithEffect id="2" fetchData={fetchData} />)
await waitFor(() => {
expect(fetchData).toHaveBeenCalledWith('2')
expect(fetchData).toHaveBeenCalledTimes(2)
})
})
```
### Testing Effect Cleanup
```typescript
it('should cleanup subscription on unmount', () => {
const subscribe = vi.fn()
const unsubscribe = vi.fn()
subscribe.mockReturnValue(unsubscribe)
const { unmount } = render(<SubscriptionComponent subscribe={subscribe} />)
expect(subscribe).toHaveBeenCalledTimes(1)
unmount()
expect(unsubscribe).toHaveBeenCalledTimes(1)
})
```
## Common Async Pitfalls
### ❌ Don't: Forget to await
```typescript
// Bad - test may pass even if assertion fails
it('should load data', () => {
render(<Component />)
waitFor(() => {
expect(screen.getByText('Data')).toBeInTheDocument()
})
})
// Good - properly awaited
it('should load data', async () => {
render(<Component />)
await waitFor(() => {
expect(screen.getByText('Data')).toBeInTheDocument()
})
})
```
### ❌ Don't: Use multiple assertions in single waitFor
```typescript
// Bad - if first assertion fails, won't know about second
await waitFor(() => {
expect(screen.getByText('Title')).toBeInTheDocument()
expect(screen.getByText('Description')).toBeInTheDocument()
})
// Good - separate waitFor or use findBy
const title = await screen.findByText('Title')
const description = await screen.findByText('Description')
expect(title).toBeInTheDocument()
expect(description).toBeInTheDocument()
```
### ❌ Don't: Mix fake timers with real async
```typescript
// Bad - fake timers don't work well with real Promises
vi.useFakeTimers()
await waitFor(() => {
expect(screen.getByText('Data')).toBeInTheDocument()
}) // May timeout!
// Good - use runAllTimers or advanceTimersByTime
vi.useFakeTimers()
render(<Component />)
vi.runAllTimers()
expect(screen.getByText('Data')).toBeInTheDocument()
```

View File

@@ -1,205 +0,0 @@
# Test Generation Checklist
Use this checklist when generating or reviewing tests for Dify frontend components.
## Pre-Generation
- [ ] Read the component source code completely
- [ ] Identify component type (component, hook, utility, page)
- [ ] Run `pnpm analyze-component <path>` if available
- [ ] Note complexity score and features detected
- [ ] Check for existing tests in the same directory
- [ ] **Identify ALL files in the directory** that need testing (not just index)
## Testing Strategy
### ⚠️ Incremental Workflow (CRITICAL for Multi-File)
- [ ] **NEVER generate all tests at once** - process one file at a time
- [ ] Order files by complexity: utilities → hooks → simple → complex → integration
- [ ] Create a todo list to track progress before starting
- [ ] For EACH file: write → run test → verify pass → then next
- [ ] **DO NOT proceed** to next file until current one passes
### Path-Level Coverage
- [ ] **Test ALL files** in the assigned directory/path
- [ ] List all components, hooks, utilities that need coverage
- [ ] Decide: single spec file (integration) or multiple spec files (unit)
### Complexity Assessment
- [ ] Run `pnpm analyze-component <path>` for complexity score
- [ ] **Complexity > 50**: Consider refactoring before testing
- [ ] **500+ lines**: Consider splitting before testing
- [ ] **30-50 complexity**: Use multiple describe blocks, organized structure
### Integration vs Mocking
- [ ] **DO NOT mock base components** (`Loading`, `Button`, `Tooltip`, etc.)
- [ ] Import real project components instead of mocking
- [ ] Only mock: API calls, complex context providers, third-party libs with side effects
- [ ] Prefer integration testing when using single spec file
## Required Test Sections
### All Components MUST Have
- [ ] **Rendering tests** - Component renders without crashing
- [ ] **Props tests** - Required props, optional props, default values
- [ ] **Edge cases** - null, undefined, empty values, boundaries
### Conditional Sections (Add When Feature Present)
| Feature | Add Tests For |
|---------|---------------|
| `useState` | Initial state, transitions, cleanup |
| `useEffect` | Execution, dependencies, cleanup |
| Event handlers | onClick, onChange, onSubmit, keyboard |
| API calls | Loading, success, error states |
| Routing | Navigation, params, query strings |
| `useCallback`/`useMemo` | Referential equality |
| Context | Provider values, consumer behavior |
| Forms | Validation, submission, error display |
## Code Quality Checklist
### Structure
- [ ] Uses `describe` blocks to group related tests
- [ ] Test names follow `should <behavior> when <condition>` pattern
- [ ] AAA pattern (Arrange-Act-Assert) is clear
- [ ] Comments explain complex test scenarios
### Mocks
- [ ] **DO NOT mock base components** (`@/app/components/base/*`)
- [ ] `vi.clearAllMocks()` in `beforeEach` (not `afterEach`)
- [ ] Shared mock state reset in `beforeEach`
- [ ] i18n uses global mock (auto-loaded in `web/vitest.setup.ts`); only override locally for custom translations
- [ ] Router mocks match actual Next.js API
- [ ] Mocks reflect actual component conditional behavior
- [ ] Only mock: API services, complex context providers, third-party libs
### Queries
- [ ] Prefer semantic queries (`getByRole`, `getByLabelText`)
- [ ] Use `queryBy*` for absence assertions
- [ ] Use `findBy*` for async elements
- [ ] `getByTestId` only as last resort
### Async
- [ ] All async tests use `async/await`
- [ ] `waitFor` wraps async assertions
- [ ] Fake timers properly setup/teardown
- [ ] No floating promises
### TypeScript
- [ ] No `any` types without justification
- [ ] Mock data uses actual types from source
- [ ] Factory functions have proper return types
## Coverage Goals (Per File)
For the current file being tested:
- [ ] 100% function coverage
- [ ] 100% statement coverage
- [ ] >95% branch coverage
- [ ] >95% line coverage
## Post-Generation (Per File)
**Run these checks after EACH test file, not just at the end:**
- [ ] Run `pnpm test path/to/file.spec.tsx` - **MUST PASS before next file**
- [ ] Fix any failures immediately
- [ ] Mark file as complete in todo list
- [ ] Only then proceed to next file
### After All Files Complete
- [ ] Run full directory test: `pnpm test path/to/directory/`
- [ ] Check coverage report: `pnpm test:coverage`
- [ ] Run `pnpm lint:fix` on all test files
- [ ] Run `pnpm type-check:tsgo`
## Common Issues to Watch
### False Positives
```typescript
// ❌ Mock doesn't match actual behavior
vi.mock('./Component', () => () => <div>Mocked</div>)
// ✅ Mock matches actual conditional logic
vi.mock('./Component', () => ({ isOpen }: any) =>
isOpen ? <div>Content</div> : null
)
```
### State Leakage
```typescript
// ❌ Shared state not reset
let mockState = false
vi.mock('./useHook', () => () => mockState)
// ✅ Reset in beforeEach
beforeEach(() => {
mockState = false
})
```
### Async Race Conditions
```typescript
// ❌ Not awaited
it('loads data', () => {
render(<Component />)
expect(screen.getByText('Data')).toBeInTheDocument()
})
// ✅ Properly awaited
it('loads data', async () => {
render(<Component />)
await waitFor(() => {
expect(screen.getByText('Data')).toBeInTheDocument()
})
})
```
### Missing Edge Cases
Always test these scenarios:
- `null` / `undefined` inputs
- Empty strings / arrays / objects
- Boundary values (0, -1, MAX_INT)
- Error states
- Loading states
- Disabled states
## Quick Commands
```bash
# Run specific test
pnpm test path/to/file.spec.tsx
# Run with coverage
pnpm test:coverage path/to/file.spec.tsx
# Watch mode
pnpm test:watch path/to/file.spec.tsx
# Update snapshots (use sparingly)
pnpm test -u path/to/file.spec.tsx
# Analyze component
pnpm analyze-component path/to/component.tsx
# Review existing test
pnpm analyze-component path/to/component.tsx --review
```

View File

@@ -1,449 +0,0 @@
# Common Testing Patterns
## Query Priority
Use queries in this order (most to least preferred):
```typescript
// 1. getByRole - Most recommended (accessibility)
screen.getByRole('button', { name: /submit/i })
screen.getByRole('textbox', { name: /email/i })
screen.getByRole('heading', { level: 1 })
// 2. getByLabelText - Form fields
screen.getByLabelText('Email address')
screen.getByLabelText(/password/i)
// 3. getByPlaceholderText - When no label
screen.getByPlaceholderText('Search...')
// 4. getByText - Non-interactive elements
screen.getByText('Welcome to Dify')
screen.getByText(/loading/i)
// 5. getByDisplayValue - Current input value
screen.getByDisplayValue('current value')
// 6. getByAltText - Images
screen.getByAltText('Company logo')
// 7. getByTitle - Tooltip elements
screen.getByTitle('Close')
// 8. getByTestId - Last resort only!
screen.getByTestId('custom-element')
```
## Event Handling Patterns
### Click Events
```typescript
// Basic click
fireEvent.click(screen.getByRole('button'))
// With userEvent (preferred for realistic interaction)
const user = userEvent.setup()
await user.click(screen.getByRole('button'))
// Double click
await user.dblClick(screen.getByRole('button'))
// Right click
await user.pointer({ keys: '[MouseRight]', target: screen.getByRole('button') })
```
### Form Input
```typescript
const user = userEvent.setup()
// Type in input
await user.type(screen.getByRole('textbox'), 'Hello World')
// Clear and type
await user.clear(screen.getByRole('textbox'))
await user.type(screen.getByRole('textbox'), 'New value')
// Select option
await user.selectOptions(screen.getByRole('combobox'), 'option-value')
// Check checkbox
await user.click(screen.getByRole('checkbox'))
// Upload file
const file = new File(['content'], 'test.pdf', { type: 'application/pdf' })
await user.upload(screen.getByLabelText(/upload/i), file)
```
### Keyboard Events
```typescript
const user = userEvent.setup()
// Press Enter
await user.keyboard('{Enter}')
// Press Escape
await user.keyboard('{Escape}')
// Keyboard shortcut
await user.keyboard('{Control>}a{/Control}') // Ctrl+A
// Tab navigation
await user.tab()
// Arrow keys
await user.keyboard('{ArrowDown}')
await user.keyboard('{ArrowUp}')
```
## Component State Testing
### Testing State Transitions
```typescript
describe('Counter', () => {
it('should increment count', async () => {
const user = userEvent.setup()
render(<Counter initialCount={0} />)
// Initial state
expect(screen.getByText('Count: 0')).toBeInTheDocument()
// Trigger transition
await user.click(screen.getByRole('button', { name: /increment/i }))
// New state
expect(screen.getByText('Count: 1')).toBeInTheDocument()
})
})
```
### Testing Controlled Components
```typescript
describe('ControlledInput', () => {
it('should call onChange with new value', async () => {
const user = userEvent.setup()
const handleChange = vi.fn()
render(<ControlledInput value="" onChange={handleChange} />)
await user.type(screen.getByRole('textbox'), 'a')
expect(handleChange).toHaveBeenCalledWith('a')
})
it('should display controlled value', () => {
render(<ControlledInput value="controlled" onChange={vi.fn()} />)
expect(screen.getByRole('textbox')).toHaveValue('controlled')
})
})
```
## Conditional Rendering Testing
```typescript
describe('ConditionalComponent', () => {
it('should show loading state', () => {
render(<DataDisplay isLoading={true} data={null} />)
expect(screen.getByText(/loading/i)).toBeInTheDocument()
expect(screen.queryByTestId('data-content')).not.toBeInTheDocument()
})
it('should show error state', () => {
render(<DataDisplay isLoading={false} data={null} error="Failed to load" />)
expect(screen.getByText(/failed to load/i)).toBeInTheDocument()
})
it('should show data when loaded', () => {
render(<DataDisplay isLoading={false} data={{ name: 'Test' }} />)
expect(screen.getByText('Test')).toBeInTheDocument()
})
it('should show empty state when no data', () => {
render(<DataDisplay isLoading={false} data={[]} />)
expect(screen.getByText(/no data/i)).toBeInTheDocument()
})
})
```
## List Rendering Testing
```typescript
describe('ItemList', () => {
const items = [
{ id: '1', name: 'Item 1' },
{ id: '2', name: 'Item 2' },
{ id: '3', name: 'Item 3' },
]
it('should render all items', () => {
render(<ItemList items={items} />)
expect(screen.getAllByRole('listitem')).toHaveLength(3)
items.forEach(item => {
expect(screen.getByText(item.name)).toBeInTheDocument()
})
})
it('should handle item selection', async () => {
const user = userEvent.setup()
const onSelect = vi.fn()
render(<ItemList items={items} onSelect={onSelect} />)
await user.click(screen.getByText('Item 2'))
expect(onSelect).toHaveBeenCalledWith(items[1])
})
it('should handle empty list', () => {
render(<ItemList items={[]} />)
expect(screen.getByText(/no items/i)).toBeInTheDocument()
})
})
```
## Modal/Dialog Testing
```typescript
describe('Modal', () => {
it('should not render when closed', () => {
render(<Modal isOpen={false} onClose={vi.fn()} />)
expect(screen.queryByRole('dialog')).not.toBeInTheDocument()
})
it('should render when open', () => {
render(<Modal isOpen={true} onClose={vi.fn()} />)
expect(screen.getByRole('dialog')).toBeInTheDocument()
})
it('should call onClose when clicking overlay', async () => {
const user = userEvent.setup()
const handleClose = vi.fn()
render(<Modal isOpen={true} onClose={handleClose} />)
await user.click(screen.getByTestId('modal-overlay'))
expect(handleClose).toHaveBeenCalled()
})
it('should call onClose when pressing Escape', async () => {
const user = userEvent.setup()
const handleClose = vi.fn()
render(<Modal isOpen={true} onClose={handleClose} />)
await user.keyboard('{Escape}')
expect(handleClose).toHaveBeenCalled()
})
it('should trap focus inside modal', async () => {
const user = userEvent.setup()
render(
<Modal isOpen={true} onClose={vi.fn()}>
<button>First</button>
<button>Second</button>
</Modal>
)
// Focus should cycle within modal
await user.tab()
expect(screen.getByText('First')).toHaveFocus()
await user.tab()
expect(screen.getByText('Second')).toHaveFocus()
await user.tab()
expect(screen.getByText('First')).toHaveFocus() // Cycles back
})
})
```
## Form Testing
```typescript
describe('LoginForm', () => {
it('should submit valid form', async () => {
const user = userEvent.setup()
const onSubmit = vi.fn()
render(<LoginForm onSubmit={onSubmit} />)
await user.type(screen.getByLabelText(/email/i), 'test@example.com')
await user.type(screen.getByLabelText(/password/i), 'password123')
await user.click(screen.getByRole('button', { name: /sign in/i }))
expect(onSubmit).toHaveBeenCalledWith({
email: 'test@example.com',
password: 'password123',
})
})
it('should show validation errors', async () => {
const user = userEvent.setup()
render(<LoginForm onSubmit={vi.fn()} />)
// Submit empty form
await user.click(screen.getByRole('button', { name: /sign in/i }))
expect(screen.getByText(/email is required/i)).toBeInTheDocument()
expect(screen.getByText(/password is required/i)).toBeInTheDocument()
})
it('should validate email format', async () => {
const user = userEvent.setup()
render(<LoginForm onSubmit={vi.fn()} />)
await user.type(screen.getByLabelText(/email/i), 'invalid-email')
await user.click(screen.getByRole('button', { name: /sign in/i }))
expect(screen.getByText(/invalid email/i)).toBeInTheDocument()
})
it('should disable submit button while submitting', async () => {
const user = userEvent.setup()
const onSubmit = vi.fn(() => new Promise(resolve => setTimeout(resolve, 100)))
render(<LoginForm onSubmit={onSubmit} />)
await user.type(screen.getByLabelText(/email/i), 'test@example.com')
await user.type(screen.getByLabelText(/password/i), 'password123')
await user.click(screen.getByRole('button', { name: /sign in/i }))
expect(screen.getByRole('button', { name: /signing in/i })).toBeDisabled()
await waitFor(() => {
expect(screen.getByRole('button', { name: /sign in/i })).toBeEnabled()
})
})
})
```
## Data-Driven Tests with test.each
```typescript
describe('StatusBadge', () => {
test.each([
['success', 'bg-green-500'],
['warning', 'bg-yellow-500'],
['error', 'bg-red-500'],
['info', 'bg-blue-500'],
])('should apply correct class for %s status', (status, expectedClass) => {
render(<StatusBadge status={status} />)
expect(screen.getByTestId('status-badge')).toHaveClass(expectedClass)
})
test.each([
{ input: null, expected: 'Unknown' },
{ input: undefined, expected: 'Unknown' },
{ input: '', expected: 'Unknown' },
{ input: 'invalid', expected: 'Unknown' },
])('should show "Unknown" for invalid input: $input', ({ input, expected }) => {
render(<StatusBadge status={input} />)
expect(screen.getByText(expected)).toBeInTheDocument()
})
})
```
## Debugging Tips
```typescript
// Print entire DOM
screen.debug()
// Print specific element
screen.debug(screen.getByRole('button'))
// Log testing playground URL
screen.logTestingPlaygroundURL()
// Pretty print DOM
import { prettyDOM } from '@testing-library/react'
console.log(prettyDOM(screen.getByRole('dialog')))
// Check available roles
import { getRoles } from '@testing-library/react'
console.log(getRoles(container))
```
## Common Mistakes to Avoid
### ❌ Don't Use Implementation Details
```typescript
// Bad - testing implementation
expect(component.state.isOpen).toBe(true)
expect(wrapper.find('.internal-class').length).toBe(1)
// Good - testing behavior
expect(screen.getByRole('dialog')).toBeInTheDocument()
```
### ❌ Don't Forget Cleanup
```typescript
// Bad - may leak state between tests
it('test 1', () => {
render(<Component />)
})
// Good - cleanup is automatic with RTL, but reset mocks
beforeEach(() => {
vi.clearAllMocks()
})
```
### ❌ Don't Use Exact String Matching (Prefer Black-Box Assertions)
```typescript
// ❌ Bad - hardcoded strings are brittle
expect(screen.getByText('Submit Form')).toBeInTheDocument()
expect(screen.getByText('Loading...')).toBeInTheDocument()
// ✅ Good - role-based queries (most semantic)
expect(screen.getByRole('button', { name: /submit/i })).toBeInTheDocument()
expect(screen.getByRole('status')).toBeInTheDocument()
// ✅ Good - pattern matching (flexible)
expect(screen.getByText(/submit/i)).toBeInTheDocument()
expect(screen.getByText(/loading/i)).toBeInTheDocument()
// ✅ Good - test behavior, not exact UI text
expect(screen.getByRole('button')).toBeDisabled()
expect(screen.getByRole('alert')).toBeInTheDocument()
```
**Why prefer black-box assertions?**
- Text content may change (i18n, copy updates)
- Role-based queries test accessibility
- Pattern matching is resilient to minor changes
- Tests focus on behavior, not implementation details
### ❌ Don't Assert on Absence Without Query
```typescript
// Bad - throws if not found
expect(screen.getByText('Error')).not.toBeInTheDocument() // Error!
// Good - use queryBy for absence assertions
expect(screen.queryByText('Error')).not.toBeInTheDocument()
```

View File

@@ -1,523 +0,0 @@
# Domain-Specific Component Testing
This guide covers testing patterns for Dify's domain-specific components.
## Workflow Components (`workflow/`)
Workflow components handle node configuration, data flow, and graph operations.
### Key Test Areas
1. **Node Configuration**
1. **Data Validation**
1. **Variable Passing**
1. **Edge Connections**
1. **Error Handling**
### Example: Node Configuration Panel
```typescript
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import NodeConfigPanel from './node-config-panel'
import { createMockNode, createMockWorkflowContext } from '@/__mocks__/workflow'
// Mock workflow context
vi.mock('@/app/components/workflow/hooks', () => ({
useWorkflowStore: () => mockWorkflowStore,
useNodesInteractions: () => mockNodesInteractions,
}))
let mockWorkflowStore = {
nodes: [],
edges: [],
updateNode: vi.fn(),
}
let mockNodesInteractions = {
handleNodeSelect: vi.fn(),
handleNodeDelete: vi.fn(),
}
describe('NodeConfigPanel', () => {
beforeEach(() => {
vi.clearAllMocks()
mockWorkflowStore = {
nodes: [],
edges: [],
updateNode: vi.fn(),
}
})
describe('Node Configuration', () => {
it('should render node type selector', () => {
const node = createMockNode({ type: 'llm' })
render(<NodeConfigPanel node={node} />)
expect(screen.getByLabelText(/model/i)).toBeInTheDocument()
})
it('should update node config on change', async () => {
const user = userEvent.setup()
const node = createMockNode({ type: 'llm' })
render(<NodeConfigPanel node={node} />)
await user.selectOptions(screen.getByLabelText(/model/i), 'gpt-4')
expect(mockWorkflowStore.updateNode).toHaveBeenCalledWith(
node.id,
expect.objectContaining({ model: 'gpt-4' })
)
})
})
describe('Data Validation', () => {
it('should show error for invalid input', async () => {
const user = userEvent.setup()
const node = createMockNode({ type: 'code' })
render(<NodeConfigPanel node={node} />)
// Enter invalid code
const codeInput = screen.getByLabelText(/code/i)
await user.clear(codeInput)
await user.type(codeInput, 'invalid syntax {{{')
await waitFor(() => {
expect(screen.getByText(/syntax error/i)).toBeInTheDocument()
})
})
it('should validate required fields', async () => {
const node = createMockNode({ type: 'http', data: { url: '' } })
render(<NodeConfigPanel node={node} />)
fireEvent.click(screen.getByRole('button', { name: /save/i }))
await waitFor(() => {
expect(screen.getByText(/url is required/i)).toBeInTheDocument()
})
})
})
describe('Variable Passing', () => {
it('should display available variables from upstream nodes', () => {
const upstreamNode = createMockNode({
id: 'node-1',
type: 'start',
data: { outputs: [{ name: 'user_input', type: 'string' }] },
})
const currentNode = createMockNode({
id: 'node-2',
type: 'llm',
})
mockWorkflowStore.nodes = [upstreamNode, currentNode]
mockWorkflowStore.edges = [{ source: 'node-1', target: 'node-2' }]
render(<NodeConfigPanel node={currentNode} />)
// Variable selector should show upstream variables
fireEvent.click(screen.getByRole('button', { name: /add variable/i }))
expect(screen.getByText('user_input')).toBeInTheDocument()
})
it('should insert variable into prompt template', async () => {
const user = userEvent.setup()
const node = createMockNode({ type: 'llm' })
render(<NodeConfigPanel node={node} />)
// Click variable button
await user.click(screen.getByRole('button', { name: /insert variable/i }))
await user.click(screen.getByText('user_input'))
const promptInput = screen.getByLabelText(/prompt/i)
expect(promptInput).toHaveValue(expect.stringContaining('{{user_input}}'))
})
})
})
```
## Dataset Components (`dataset/`)
Dataset components handle file uploads, data display, and search/filter operations.
### Key Test Areas
1. **File Upload**
1. **File Type Validation**
1. **Pagination**
1. **Search & Filtering**
1. **Data Format Handling**
### Example: Document Uploader
```typescript
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import DocumentUploader from './document-uploader'
vi.mock('@/service/datasets', () => ({
uploadDocument: vi.fn(),
parseDocument: vi.fn(),
}))
import * as datasetService from '@/service/datasets'
const mockedService = vi.mocked(datasetService)
describe('DocumentUploader', () => {
beforeEach(() => {
vi.clearAllMocks()
})
describe('File Upload', () => {
it('should accept valid file types', async () => {
const user = userEvent.setup()
const onUpload = vi.fn()
mockedService.uploadDocument.mockResolvedValue({ id: 'doc-1' })
render(<DocumentUploader onUpload={onUpload} />)
const file = new File(['content'], 'test.pdf', { type: 'application/pdf' })
const input = screen.getByLabelText(/upload/i)
await user.upload(input, file)
await waitFor(() => {
expect(mockedService.uploadDocument).toHaveBeenCalledWith(
expect.any(FormData)
)
})
})
it('should reject invalid file types', async () => {
const user = userEvent.setup()
render(<DocumentUploader />)
const file = new File(['content'], 'test.exe', { type: 'application/x-msdownload' })
const input = screen.getByLabelText(/upload/i)
await user.upload(input, file)
expect(screen.getByText(/unsupported file type/i)).toBeInTheDocument()
expect(mockedService.uploadDocument).not.toHaveBeenCalled()
})
it('should show upload progress', async () => {
const user = userEvent.setup()
// Mock upload with progress
mockedService.uploadDocument.mockImplementation(() => {
return new Promise((resolve) => {
setTimeout(() => resolve({ id: 'doc-1' }), 100)
})
})
render(<DocumentUploader />)
const file = new File(['content'], 'test.pdf', { type: 'application/pdf' })
await user.upload(screen.getByLabelText(/upload/i), file)
expect(screen.getByRole('progressbar')).toBeInTheDocument()
await waitFor(() => {
expect(screen.queryByRole('progressbar')).not.toBeInTheDocument()
})
})
})
describe('Error Handling', () => {
it('should handle upload failure', async () => {
const user = userEvent.setup()
mockedService.uploadDocument.mockRejectedValue(new Error('Upload failed'))
render(<DocumentUploader />)
const file = new File(['content'], 'test.pdf', { type: 'application/pdf' })
await user.upload(screen.getByLabelText(/upload/i), file)
await waitFor(() => {
expect(screen.getByText(/upload failed/i)).toBeInTheDocument()
})
})
it('should allow retry after failure', async () => {
const user = userEvent.setup()
mockedService.uploadDocument
.mockRejectedValueOnce(new Error('Network error'))
.mockResolvedValueOnce({ id: 'doc-1' })
render(<DocumentUploader />)
const file = new File(['content'], 'test.pdf', { type: 'application/pdf' })
await user.upload(screen.getByLabelText(/upload/i), file)
await waitFor(() => {
expect(screen.getByRole('button', { name: /retry/i })).toBeInTheDocument()
})
await user.click(screen.getByRole('button', { name: /retry/i }))
await waitFor(() => {
expect(screen.getByText(/uploaded successfully/i)).toBeInTheDocument()
})
})
})
})
```
### Example: Document List with Pagination
```typescript
describe('DocumentList', () => {
describe('Pagination', () => {
it('should load first page on mount', async () => {
mockedService.getDocuments.mockResolvedValue({
data: [{ id: '1', name: 'Doc 1' }],
total: 50,
page: 1,
pageSize: 10,
})
render(<DocumentList datasetId="ds-1" />)
await waitFor(() => {
expect(screen.getByText('Doc 1')).toBeInTheDocument()
})
expect(mockedService.getDocuments).toHaveBeenCalledWith('ds-1', { page: 1 })
})
it('should navigate to next page', async () => {
const user = userEvent.setup()
mockedService.getDocuments.mockResolvedValue({
data: [{ id: '1', name: 'Doc 1' }],
total: 50,
page: 1,
pageSize: 10,
})
render(<DocumentList datasetId="ds-1" />)
await waitFor(() => {
expect(screen.getByText('Doc 1')).toBeInTheDocument()
})
mockedService.getDocuments.mockResolvedValue({
data: [{ id: '11', name: 'Doc 11' }],
total: 50,
page: 2,
pageSize: 10,
})
await user.click(screen.getByRole('button', { name: /next/i }))
await waitFor(() => {
expect(screen.getByText('Doc 11')).toBeInTheDocument()
})
})
})
describe('Search & Filtering', () => {
it('should filter by search query', async () => {
const user = userEvent.setup()
vi.useFakeTimers()
render(<DocumentList datasetId="ds-1" />)
await user.type(screen.getByPlaceholderText(/search/i), 'test query')
// Debounce
vi.advanceTimersByTime(300)
await waitFor(() => {
expect(mockedService.getDocuments).toHaveBeenCalledWith(
'ds-1',
expect.objectContaining({ search: 'test query' })
)
})
vi.useRealTimers()
})
})
})
```
## Configuration Components (`app/configuration/`, `config/`)
Configuration components handle forms, validation, and data persistence.
### Key Test Areas
1. **Form Validation**
1. **Save/Reset**
1. **Required vs Optional Fields**
1. **Configuration Persistence**
1. **Error Feedback**
### Example: App Configuration Form
```typescript
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import AppConfigForm from './app-config-form'
vi.mock('@/service/apps', () => ({
updateAppConfig: vi.fn(),
getAppConfig: vi.fn(),
}))
import * as appService from '@/service/apps'
const mockedService = vi.mocked(appService)
describe('AppConfigForm', () => {
const defaultConfig = {
name: 'My App',
description: '',
icon: 'default',
openingStatement: '',
}
beforeEach(() => {
vi.clearAllMocks()
mockedService.getAppConfig.mockResolvedValue(defaultConfig)
})
describe('Form Validation', () => {
it('should require app name', async () => {
const user = userEvent.setup()
render(<AppConfigForm appId="app-1" />)
await waitFor(() => {
expect(screen.getByLabelText(/name/i)).toHaveValue('My App')
})
// Clear name field
await user.clear(screen.getByLabelText(/name/i))
await user.click(screen.getByRole('button', { name: /save/i }))
expect(screen.getByText(/name is required/i)).toBeInTheDocument()
expect(mockedService.updateAppConfig).not.toHaveBeenCalled()
})
it('should validate name length', async () => {
const user = userEvent.setup()
render(<AppConfigForm appId="app-1" />)
await waitFor(() => {
expect(screen.getByLabelText(/name/i)).toBeInTheDocument()
})
// Enter very long name
await user.clear(screen.getByLabelText(/name/i))
await user.type(screen.getByLabelText(/name/i), 'a'.repeat(101))
expect(screen.getByText(/name must be less than 100 characters/i)).toBeInTheDocument()
})
it('should allow empty optional fields', async () => {
const user = userEvent.setup()
mockedService.updateAppConfig.mockResolvedValue({ success: true })
render(<AppConfigForm appId="app-1" />)
await waitFor(() => {
expect(screen.getByLabelText(/name/i)).toHaveValue('My App')
})
// Leave description empty (optional)
await user.click(screen.getByRole('button', { name: /save/i }))
await waitFor(() => {
expect(mockedService.updateAppConfig).toHaveBeenCalled()
})
})
})
describe('Save/Reset Functionality', () => {
it('should save configuration', async () => {
const user = userEvent.setup()
mockedService.updateAppConfig.mockResolvedValue({ success: true })
render(<AppConfigForm appId="app-1" />)
await waitFor(() => {
expect(screen.getByLabelText(/name/i)).toHaveValue('My App')
})
await user.clear(screen.getByLabelText(/name/i))
await user.type(screen.getByLabelText(/name/i), 'Updated App')
await user.click(screen.getByRole('button', { name: /save/i }))
await waitFor(() => {
expect(mockedService.updateAppConfig).toHaveBeenCalledWith(
'app-1',
expect.objectContaining({ name: 'Updated App' })
)
})
expect(screen.getByText(/saved successfully/i)).toBeInTheDocument()
})
it('should reset to default values', async () => {
const user = userEvent.setup()
render(<AppConfigForm appId="app-1" />)
await waitFor(() => {
expect(screen.getByLabelText(/name/i)).toHaveValue('My App')
})
// Make changes
await user.clear(screen.getByLabelText(/name/i))
await user.type(screen.getByLabelText(/name/i), 'Changed Name')
// Reset
await user.click(screen.getByRole('button', { name: /reset/i }))
expect(screen.getByLabelText(/name/i)).toHaveValue('My App')
})
it('should show unsaved changes warning', async () => {
const user = userEvent.setup()
render(<AppConfigForm appId="app-1" />)
await waitFor(() => {
expect(screen.getByLabelText(/name/i)).toHaveValue('My App')
})
// Make changes
await user.type(screen.getByLabelText(/name/i), ' Updated')
expect(screen.getByText(/unsaved changes/i)).toBeInTheDocument()
})
})
describe('Error Handling', () => {
it('should show error on save failure', async () => {
const user = userEvent.setup()
mockedService.updateAppConfig.mockRejectedValue(new Error('Server error'))
render(<AppConfigForm appId="app-1" />)
await waitFor(() => {
expect(screen.getByLabelText(/name/i)).toHaveValue('My App')
})
await user.click(screen.getByRole('button', { name: /save/i }))
await waitFor(() => {
expect(screen.getByText(/failed to save/i)).toBeInTheDocument()
})
})
})
})
```

View File

@@ -1,512 +0,0 @@
# Mocking Guide for Dify Frontend Tests
## ⚠️ Important: What NOT to Mock
### DO NOT Mock Base Components
**Never mock components from `@/app/components/base/`** such as:
- `Loading`, `Spinner`
- `Button`, `Input`, `Select`
- `Tooltip`, `Modal`, `Dropdown`
- `Icon`, `Badge`, `Tag`
**Why?**
- Base components will have their own dedicated tests
- Mocking them creates false positives (tests pass but real integration fails)
- Using real components tests actual integration behavior
```typescript
// ❌ WRONG: Don't mock base components
vi.mock('@/app/components/base/loading', () => () => <div>Loading</div>)
vi.mock('@/app/components/base/button', () => ({ children }: any) => <button>{children}</button>)
// ✅ CORRECT: Import and use real base components
import Loading from '@/app/components/base/loading'
import Button from '@/app/components/base/button'
// They will render normally in tests
```
### What TO Mock
Only mock these categories:
1. **API services** (`@/service/*`) - Network calls
1. **Complex context providers** - When setup is too difficult
1. **Third-party libraries with side effects** - `next/navigation`, external SDKs
1. **i18n** - Always mock to return keys
### Zustand Stores - DO NOT Mock Manually
**Zustand is globally mocked** in `web/vitest.setup.ts`. Use real stores with `setState()`:
```typescript
// ✅ CORRECT: Use real store, set test state
import { useAppStore } from '@/app/components/app/store'
useAppStore.setState({ appDetail: { id: 'test', name: 'Test' } })
render(<MyComponent />)
// ❌ WRONG: Don't mock the store module
vi.mock('@/app/components/app/store', () => ({ ... }))
```
See [Zustand Store Testing](#zustand-store-testing) section for full details.
## Mock Placement
| Location | Purpose |
|----------|---------|
| `web/vitest.setup.ts` | Global mocks shared by all tests (`react-i18next`, `next/image`, `zustand`) |
| `web/__mocks__/zustand.ts` | Zustand mock implementation (auto-resets stores after each test) |
| `web/__mocks__/` | Reusable mock factories shared across multiple test files |
| Test file | Test-specific mocks, inline with `vi.mock()` |
Modules are not mocked automatically. Use `vi.mock` in test files, or add global mocks in `web/vitest.setup.ts`.
**Note**: Zustand is special - it's globally mocked but you should NOT mock store modules manually. See [Zustand Store Testing](#zustand-store-testing).
## Essential Mocks
### 1. i18n (Auto-loaded via Global Mock)
A global mock is defined in `web/vitest.setup.ts` and is auto-loaded by Vitest setup.
The global mock provides:
- `useTranslation` - returns translation keys with namespace prefix
- `Trans` component - renders i18nKey and components
- `useMixedTranslation` (from `@/app/components/plugins/marketplace/hooks`)
- `useGetLanguage` (from `@/context/i18n`) - returns `'en-US'`
**Default behavior**: Most tests should use the global mock (no local override needed).
**For custom translations**: Use the helper function from `@/test/i18n-mock`:
```typescript
import { createReactI18nextMock } from '@/test/i18n-mock'
vi.mock('react-i18next', () => createReactI18nextMock({
'my.custom.key': 'Custom translation',
'button.save': 'Save',
}))
```
**Avoid**: Manually defining `useTranslation` mocks that just return the key - the global mock already does this.
### 2. Next.js Router
```typescript
const mockPush = vi.fn()
const mockReplace = vi.fn()
vi.mock('next/navigation', () => ({
useRouter: () => ({
push: mockPush,
replace: mockReplace,
back: vi.fn(),
prefetch: vi.fn(),
}),
usePathname: () => '/current-path',
useSearchParams: () => new URLSearchParams('?key=value'),
}))
describe('Component', () => {
beforeEach(() => {
vi.clearAllMocks()
})
it('should navigate on click', () => {
render(<Component />)
fireEvent.click(screen.getByRole('button'))
expect(mockPush).toHaveBeenCalledWith('/expected-path')
})
})
```
### 3. Portal Components (with Shared State)
```typescript
// ⚠️ Important: Use shared state for components that depend on each other
let mockPortalOpenState = false
vi.mock('@/app/components/base/portal-to-follow-elem', () => ({
PortalToFollowElem: ({ children, open, ...props }: any) => {
mockPortalOpenState = open || false // Update shared state
return <div data-testid="portal" data-open={open}>{children}</div>
},
PortalToFollowElemContent: ({ children }: any) => {
// ✅ Matches actual: returns null when portal is closed
if (!mockPortalOpenState) return null
return <div data-testid="portal-content">{children}</div>
},
PortalToFollowElemTrigger: ({ children }: any) => (
<div data-testid="portal-trigger">{children}</div>
),
}))
describe('Component', () => {
beforeEach(() => {
vi.clearAllMocks()
mockPortalOpenState = false // ✅ Reset shared state
})
})
```
### 4. API Service Mocks
```typescript
import * as api from '@/service/api'
vi.mock('@/service/api')
const mockedApi = vi.mocked(api)
describe('Component', () => {
beforeEach(() => {
vi.clearAllMocks()
// Setup default mock implementation
mockedApi.fetchData.mockResolvedValue({ data: [] })
})
it('should show data on success', async () => {
mockedApi.fetchData.mockResolvedValue({ data: [{ id: 1 }] })
render(<Component />)
await waitFor(() => {
expect(screen.getByText('1')).toBeInTheDocument()
})
})
it('should show error on failure', async () => {
mockedApi.fetchData.mockRejectedValue(new Error('Network error'))
render(<Component />)
await waitFor(() => {
expect(screen.getByText(/error/i)).toBeInTheDocument()
})
})
})
```
### 5. HTTP Mocking with Nock
```typescript
import nock from 'nock'
const GITHUB_HOST = 'https://api.github.com'
const GITHUB_PATH = '/repos/owner/repo'
const mockGithubApi = (status: number, body: Record<string, unknown>, delayMs = 0) => {
return nock(GITHUB_HOST)
.get(GITHUB_PATH)
.delay(delayMs)
.reply(status, body)
}
describe('GithubComponent', () => {
afterEach(() => {
nock.cleanAll()
})
it('should display repo info', async () => {
mockGithubApi(200, { name: 'dify', stars: 1000 })
render(<GithubComponent />)
await waitFor(() => {
expect(screen.getByText('dify')).toBeInTheDocument()
})
})
it('should handle API error', async () => {
mockGithubApi(500, { message: 'Server error' })
render(<GithubComponent />)
await waitFor(() => {
expect(screen.getByText(/error/i)).toBeInTheDocument()
})
})
})
```
### 6. Context Providers
```typescript
import { ProviderContext } from '@/context/provider-context'
import { createMockProviderContextValue, createMockPlan } from '@/__mocks__/provider-context'
describe('Component with Context', () => {
it('should render for free plan', () => {
const mockContext = createMockPlan('sandbox')
render(
<ProviderContext.Provider value={mockContext}>
<Component />
</ProviderContext.Provider>
)
expect(screen.getByText('Upgrade')).toBeInTheDocument()
})
it('should render for pro plan', () => {
const mockContext = createMockPlan('professional')
render(
<ProviderContext.Provider value={mockContext}>
<Component />
</ProviderContext.Provider>
)
expect(screen.queryByText('Upgrade')).not.toBeInTheDocument()
})
})
```
### 7. React Query
```typescript
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
const createTestQueryClient = () => new QueryClient({
defaultOptions: {
queries: { retry: false },
mutations: { retry: false },
},
})
const renderWithQueryClient = (ui: React.ReactElement) => {
const queryClient = createTestQueryClient()
return render(
<QueryClientProvider client={queryClient}>
{ui}
</QueryClientProvider>
)
}
```
## Mock Best Practices
### ✅ DO
1. **Use real base components** - Import from `@/app/components/base/` directly
1. **Use real project components** - Prefer importing over mocking
1. **Use real Zustand stores** - Set test state via `store.setState()`
1. **Reset mocks in `beforeEach`**, not `afterEach`
1. **Match actual component behavior** in mocks (when mocking is necessary)
1. **Use factory functions** for complex mock data
1. **Import actual types** for type safety
1. **Reset shared mock state** in `beforeEach`
### ❌ DON'T
1. **Don't mock base components** (`Loading`, `Button`, `Tooltip`, etc.)
1. **Don't mock Zustand store modules** - Use real stores with `setState()`
1. Don't mock components you can import directly
1. Don't create overly simplified mocks that miss conditional logic
1. Don't forget to clean up nock after each test
1. Don't use `any` types in mocks without necessity
### Mock Decision Tree
```
Need to use a component in test?
├─ Is it from @/app/components/base/*?
│ └─ YES → Import real component, DO NOT mock
├─ Is it a project component?
│ └─ YES → Prefer importing real component
│ Only mock if setup is extremely complex
├─ Is it an API service (@/service/*)?
│ └─ YES → Mock it
├─ Is it a third-party lib with side effects?
│ └─ YES → Mock it (next/navigation, external SDKs)
├─ Is it a Zustand store?
│ └─ YES → DO NOT mock the module!
│ Use real store + setState() to set test state
│ (Global mock handles auto-reset)
└─ Is it i18n?
└─ YES → Uses shared mock (auto-loaded). Override only for custom translations
```
## Zustand Store Testing
### Global Zustand Mock (Auto-loaded)
Zustand is globally mocked in `web/vitest.setup.ts` following the [official Zustand testing guide](https://zustand.docs.pmnd.rs/guides/testing). The mock in `web/__mocks__/zustand.ts` provides:
- Real store behavior with `getState()`, `setState()`, `subscribe()` methods
- Automatic store reset after each test via `afterEach`
- Proper test isolation between tests
### ✅ Recommended: Use Real Stores (Official Best Practice)
**DO NOT mock store modules manually.** Import and use the real store, then use `setState()` to set test state:
```typescript
// ✅ CORRECT: Use real store with setState
import { useAppStore } from '@/app/components/app/store'
describe('MyComponent', () => {
it('should render app details', () => {
// Arrange: Set test state via setState
useAppStore.setState({
appDetail: {
id: 'test-app',
name: 'Test App',
mode: 'chat',
},
})
// Act
render(<MyComponent />)
// Assert
expect(screen.getByText('Test App')).toBeInTheDocument()
// Can also verify store state directly
expect(useAppStore.getState().appDetail?.name).toBe('Test App')
})
// No cleanup needed - global mock auto-resets after each test
})
```
### ❌ Avoid: Manual Store Module Mocking
Manual mocking conflicts with the global Zustand mock and loses store functionality:
```typescript
// ❌ WRONG: Don't mock the store module
vi.mock('@/app/components/app/store', () => ({
useStore: (selector) => mockSelector(selector), // Missing getState, setState!
}))
// ❌ WRONG: This conflicts with global zustand mock
vi.mock('@/app/components/workflow/store', () => ({
useWorkflowStore: vi.fn(() => mockState),
}))
```
**Problems with manual mocking:**
1. Loses `getState()`, `setState()`, `subscribe()` methods
1. Conflicts with global Zustand mock behavior
1. Requires manual maintenance of store API
1. Tests don't reflect actual store behavior
### When Manual Store Mocking is Necessary
In rare cases where the store has complex initialization or side effects, you can mock it, but ensure you provide the full store API:
```typescript
// If you MUST mock (rare), include full store API
const mockStore = {
appDetail: { id: 'test', name: 'Test' },
setAppDetail: vi.fn(),
}
vi.mock('@/app/components/app/store', () => ({
useStore: Object.assign(
(selector: (state: typeof mockStore) => unknown) => selector(mockStore),
{
getState: () => mockStore,
setState: vi.fn(),
subscribe: vi.fn(),
},
),
}))
```
### Store Testing Decision Tree
```
Need to test a component using Zustand store?
├─ Can you use the real store?
│ └─ YES → Use real store + setState (RECOMMENDED)
│ useAppStore.setState({ ... })
├─ Does the store have complex initialization/side effects?
│ └─ YES → Consider mocking, but include full API
│ (getState, setState, subscribe)
└─ Are you testing the store itself (not a component)?
└─ YES → Test store directly with getState/setState
const store = useMyStore
store.setState({ count: 0 })
store.getState().increment()
expect(store.getState().count).toBe(1)
```
### Example: Testing Store Actions
```typescript
import { useCounterStore } from '@/stores/counter'
describe('Counter Store', () => {
it('should increment count', () => {
// Initial state (auto-reset by global mock)
expect(useCounterStore.getState().count).toBe(0)
// Call action
useCounterStore.getState().increment()
// Verify state change
expect(useCounterStore.getState().count).toBe(1)
})
it('should reset to initial state', () => {
// Set some state
useCounterStore.setState({ count: 100 })
expect(useCounterStore.getState().count).toBe(100)
// After this test, global mock will reset to initial state
})
})
```
## Factory Function Pattern
```typescript
// __mocks__/data-factories.ts
import type { User, Project } from '@/types'
export const createMockUser = (overrides: Partial<User> = {}): User => ({
id: 'user-1',
name: 'Test User',
email: 'test@example.com',
role: 'member',
createdAt: new Date().toISOString(),
...overrides,
})
export const createMockProject = (overrides: Partial<Project> = {}): Project => ({
id: 'project-1',
name: 'Test Project',
description: 'A test project',
owner: createMockUser(),
members: [],
createdAt: new Date().toISOString(),
...overrides,
})
// Usage in tests
it('should display project owner', () => {
const project = createMockProject({
owner: createMockUser({ name: 'John Doe' }),
})
render(<ProjectCard project={project} />)
expect(screen.getByText('John Doe')).toBeInTheDocument()
})
```

View File

@@ -1,269 +0,0 @@
# Testing Workflow Guide
This guide defines the workflow for generating tests, especially for complex components or directories with multiple files.
## Scope Clarification
This guide addresses **multi-file workflow** (how to process multiple test files). For coverage requirements within a single test file, see `web/testing/testing.md` § Coverage Goals.
| Scope | Rule |
|-------|------|
| **Single file** | Complete coverage in one generation (100% function, >95% branch) |
| **Multi-file directory** | Process one file at a time, verify each before proceeding |
## ⚠️ Critical Rule: Incremental Approach for Multi-File Testing
When testing a **directory with multiple files**, **NEVER generate all test files at once.** Use an incremental, verify-as-you-go approach.
### Why Incremental?
| Batch Approach (❌) | Incremental Approach (✅) |
|---------------------|---------------------------|
| Generate 5+ tests at once | Generate 1 test at a time |
| Run tests only at the end | Run test immediately after each file |
| Multiple failures compound | Single point of failure, easy to debug |
| Hard to identify root cause | Clear cause-effect relationship |
| Mock issues affect many files | Mock issues caught early |
| Messy git history | Clean, atomic commits possible |
## Single File Workflow
When testing a **single component, hook, or utility**:
```
1. Read source code completely
2. Run `pnpm analyze-component <path>` (if available)
3. Check complexity score and features detected
4. Write the test file
5. Run test: `pnpm test <file>.spec.tsx`
6. Fix any failures
7. Verify coverage meets goals (100% function, >95% branch)
```
## Directory/Multi-File Workflow (MUST FOLLOW)
When testing a **directory or multiple files**, follow this strict workflow:
### Step 1: Analyze and Plan
1. **List all files** that need tests in the directory
1. **Categorize by complexity**:
- 🟢 **Simple**: Utility functions, simple hooks, presentational components
- 🟡 **Medium**: Components with state, effects, or event handlers
- 🔴 **Complex**: Components with API calls, routing, or many dependencies
1. **Order by dependency**: Test dependencies before dependents
1. **Create a todo list** to track progress
### Step 2: Determine Processing Order
Process files in this recommended order:
```
1. Utility functions (simplest, no React)
2. Custom hooks (isolated logic)
3. Simple presentational components (few/no props)
4. Medium complexity components (state, effects)
5. Complex components (API, routing, many deps)
6. Container/index components (integration tests - last)
```
**Rationale**:
- Simpler files help establish mock patterns
- Hooks used by components should be tested first
- Integration tests (index files) depend on child components working
### Step 3: Process Each File Incrementally
**For EACH file in the ordered list:**
```
┌─────────────────────────────────────────────┐
│ 1. Write test file │
│ 2. Run: pnpm test <file>.spec.tsx │
│ 3. If FAIL → Fix immediately, re-run │
│ 4. If PASS → Mark complete in todo list │
│ 5. ONLY THEN proceed to next file │
└─────────────────────────────────────────────┘
```
**DO NOT proceed to the next file until the current one passes.**
### Step 4: Final Verification
After all individual tests pass:
```bash
# Run all tests in the directory together
pnpm test path/to/directory/
# Check coverage
pnpm test:coverage path/to/directory/
```
## Component Complexity Guidelines
Use `pnpm analyze-component <path>` to assess complexity before testing.
### 🔴 Very Complex Components (Complexity > 50)
**Consider refactoring BEFORE testing:**
- Break component into smaller, testable pieces
- Extract complex logic into custom hooks
- Separate container and presentational layers
**If testing as-is:**
- Use integration tests for complex workflows
- Use `test.each()` for data-driven testing
- Multiple `describe` blocks for organization
- Consider testing major sections separately
### 🟡 Medium Complexity (Complexity 30-50)
- Group related tests in `describe` blocks
- Test integration scenarios between internal parts
- Focus on state transitions and side effects
- Use helper functions to reduce test complexity
### 🟢 Simple Components (Complexity < 30)
- Standard test structure
- Focus on props, rendering, and edge cases
- Usually straightforward to test
### 📏 Large Files (500+ lines)
Regardless of complexity score:
- **Strongly consider refactoring** before testing
- If testing as-is, test major sections separately
- Create helper functions for test setup
- May need multiple test files
## Todo List Format
When testing multiple files, use a todo list like this:
```
Testing: path/to/directory/
Ordered by complexity (simple → complex):
☐ utils/helper.ts [utility, simple]
☐ hooks/use-custom-hook.ts [hook, simple]
☐ empty-state.tsx [component, simple]
☐ item-card.tsx [component, medium]
☐ list.tsx [component, complex]
☐ index.tsx [integration]
Progress: 0/6 complete
```
Update status as you complete each:
- ☐ → ⏳ (in progress)
- ⏳ → ✅ (complete and verified)
- ⏳ → ❌ (blocked, needs attention)
## When to Stop and Verify
**Always run tests after:**
- Completing a test file
- Making changes to fix a failure
- Modifying shared mocks
- Updating test utilities or helpers
**Signs you should pause:**
- More than 2 consecutive test failures
- Mock-related errors appearing
- Unclear why a test is failing
- Test passing but coverage unexpectedly low
## Common Pitfalls to Avoid
### ❌ Don't: Generate Everything First
```
# BAD: Writing all files then testing
Write component-a.spec.tsx
Write component-b.spec.tsx
Write component-c.spec.tsx
Write component-d.spec.tsx
Run pnpm test ← Multiple failures, hard to debug
```
### ✅ Do: Verify Each Step
```
# GOOD: Incremental with verification
Write component-a.spec.tsx
Run pnpm test component-a.spec.tsx ✅
Write component-b.spec.tsx
Run pnpm test component-b.spec.tsx ✅
...continue...
```
### ❌ Don't: Skip Verification for "Simple" Components
Even simple components can have:
- Import errors
- Missing mock setup
- Incorrect assumptions about props
**Always verify, regardless of perceived simplicity.**
### ❌ Don't: Continue When Tests Fail
Failing tests compound:
- A mock issue in file A affects files B, C, D
- Fixing A later requires revisiting all dependent tests
- Time wasted on debugging cascading failures
**Fix failures immediately before proceeding.**
## Integration with Claude's Todo Feature
When using Claude for multi-file testing:
1. **Ask Claude to create a todo list** before starting
1. **Request one file at a time** or ensure Claude processes incrementally
1. **Verify each test passes** before asking for the next
1. **Mark todos complete** as you progress
Example prompt:
```
Test all components in `path/to/directory/`.
First, analyze the directory and create a todo list ordered by complexity.
Then, process ONE file at a time, waiting for my confirmation that tests pass
before proceeding to the next.
```
## Summary Checklist
Before starting multi-file testing:
- [ ] Listed all files needing tests
- [ ] Ordered by complexity (simple → complex)
- [ ] Created todo list for tracking
- [ ] Understand dependencies between files
During testing:
- [ ] Processing ONE file at a time
- [ ] Running tests after EACH file
- [ ] Fixing failures BEFORE proceeding
- [ ] Updating todo list progress
After completion:
- [ ] All individual tests pass
- [ ] Full directory test run passes
- [ ] Coverage goals met
- [ ] Todo list shows all complete

View File

@@ -1,46 +0,0 @@
---
name: orpc-contract-first
description: Guide for implementing oRPC contract-first API patterns in Dify frontend. Triggers when creating new API contracts, adding service endpoints, integrating TanStack Query with typed contracts, or migrating legacy service calls to oRPC. Use for all API layer work in web/contract and web/service directories.
---
# oRPC Contract-First Development
## Project Structure
```
web/contract/
├── base.ts # Base contract (inputStructure: 'detailed')
├── router.ts # Router composition & type exports
├── marketplace.ts # Marketplace contracts
└── console/ # Console contracts by domain
├── system.ts
└── billing.ts
```
## Workflow
1. **Create contract** in `web/contract/console/{domain}.ts`
- Import `base` from `../base` and `type` from `@orpc/contract`
- Define route with `path`, `method`, `input`, `output`
2. **Register in router** at `web/contract/router.ts`
- Import directly from domain file (no barrel files)
- Nest by API prefix: `billing: { invoices, bindPartnerStack }`
3. **Create hooks** in `web/service/use-{domain}.ts`
- Use `consoleQuery.{group}.{contract}.queryKey()` for query keys
- Use `consoleClient.{group}.{contract}()` for API calls
## Key Rules
- **Input structure**: Always use `{ params, query?, body? }` format
- **Path params**: Use `{paramName}` in path, match in `params` object
- **Router nesting**: Group by API prefix (e.g., `/billing/*``billing: {}`)
- **No barrel files**: Import directly from specific files
- **Types**: Import from `@/types/`, use `type<T>()` helper
## Type Export
```typescript
export type ConsoleInputs = InferContractRouterInputs<typeof consoleRouterContract>
```

View File

@@ -1,355 +0,0 @@
---
name: skill-creator
description: Guide for creating effective skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Claude's capabilities with specialized knowledge, workflows, or tool integrations.
---
# Skill Creator
This skill provides guidance for creating effective skills.
## About Skills
Skills are modular, self-contained packages that extend Claude's capabilities by providing
specialized knowledge, workflows, and tools. Think of them as "onboarding guides" for specific
domains or tasks—they transform Claude from a general-purpose agent into a specialized agent
equipped with procedural knowledge that no model can fully possess.
### What Skills Provide
1. Specialized workflows - Multi-step procedures for specific domains
2. Tool integrations - Instructions for working with specific file formats or APIs
3. Domain expertise - Company-specific knowledge, schemas, business logic
4. Bundled resources - Scripts, references, and assets for complex and repetitive tasks
## Core Principles
### Concise is Key
The context window is a public good. Skills share the context window with everything else Claude needs: system prompt, conversation history, other Skills' metadata, and the actual user request.
**Default assumption: Claude is already very smart.** Only add context Claude doesn't already have. Challenge each piece of information: "Does Claude really need this explanation?" and "Does this paragraph justify its token cost?"
Prefer concise examples over verbose explanations.
### Set Appropriate Degrees of Freedom
Match the level of specificity to the task's fragility and variability:
**High freedom (text-based instructions)**: Use when multiple approaches are valid, decisions depend on context, or heuristics guide the approach.
**Medium freedom (pseudocode or scripts with parameters)**: Use when a preferred pattern exists, some variation is acceptable, or configuration affects behavior.
**Low freedom (specific scripts, few parameters)**: Use when operations are fragile and error-prone, consistency is critical, or a specific sequence must be followed.
Think of Claude as exploring a path: a narrow bridge with cliffs needs specific guardrails (low freedom), while an open field allows many routes (high freedom).
### Anatomy of a Skill
Every skill consists of a required SKILL.md file and optional bundled resources:
```
skill-name/
├── SKILL.md (required)
│ ├── YAML frontmatter metadata (required)
│ │ ├── name: (required)
│ │ └── description: (required)
│ └── Markdown instructions (required)
└── Bundled Resources (optional)
├── scripts/ - Executable code (Python/Bash/etc.)
├── references/ - Documentation intended to be loaded into context as needed
└── assets/ - Files used in output (templates, icons, fonts, etc.)
```
#### SKILL.md (required)
Every SKILL.md consists of:
- **Frontmatter** (YAML): Contains `name` and `description` fields. These are the only fields that Claude reads to determine when the skill gets used, thus it is very important to be clear and comprehensive in describing what the skill is, and when it should be used.
- **Body** (Markdown): Instructions and guidance for using the skill. Only loaded AFTER the skill triggers (if at all).
#### Bundled Resources (optional)
##### Scripts (`scripts/`)
Executable code (Python/Bash/etc.) for tasks that require deterministic reliability or are repeatedly rewritten.
- **When to include**: When the same code is being rewritten repeatedly or deterministic reliability is needed
- **Example**: `scripts/rotate_pdf.py` for PDF rotation tasks
- **Benefits**: Token efficient, deterministic, may be executed without loading into context
- **Note**: Scripts may still need to be read by Claude for patching or environment-specific adjustments
##### References (`references/`)
Documentation and reference material intended to be loaded as needed into context to inform Claude's process and thinking.
- **When to include**: For documentation that Claude should reference while working
- **Examples**: `references/finance.md` for financial schemas, `references/mnda.md` for company NDA template, `references/policies.md` for company policies, `references/api_docs.md` for API specifications
- **Use cases**: Database schemas, API documentation, domain knowledge, company policies, detailed workflow guides
- **Benefits**: Keeps SKILL.md lean, loaded only when Claude determines it's needed
- **Best practice**: If files are large (>10k words), include grep search patterns in SKILL.md
- **Avoid duplication**: Information should live in either SKILL.md or references files, not both. Prefer references files for detailed information unless it's truly core to the skill—this keeps SKILL.md lean while making information discoverable without hogging the context window. Keep only essential procedural instructions and workflow guidance in SKILL.md; move detailed reference material, schemas, and examples to references files.
##### Assets (`assets/`)
Files not intended to be loaded into context, but rather used within the output Claude produces.
- **When to include**: When the skill needs files that will be used in the final output
- **Examples**: `assets/logo.png` for brand assets, `assets/slides.pptx` for PowerPoint templates, `assets/frontend-template/` for HTML/React boilerplate, `assets/font.ttf` for typography
- **Use cases**: Templates, images, icons, boilerplate code, fonts, sample documents that get copied or modified
- **Benefits**: Separates output resources from documentation, enables Claude to use files without loading them into context
#### What to Not Include in a Skill
A skill should only contain essential files that directly support its functionality. Do NOT create extraneous documentation or auxiliary files, including:
- README.md
- INSTALLATION_GUIDE.md
- QUICK_REFERENCE.md
- CHANGELOG.md
- etc.
The skill should only contain the information needed for an AI agent to do the job at hand. It should not contain auxilary context about the process that went into creating it, setup and testing procedures, user-facing documentation, etc. Creating additional documentation files just adds clutter and confusion.
### Progressive Disclosure Design Principle
Skills use a three-level loading system to manage context efficiently:
1. **Metadata (name + description)** - Always in context (~100 words)
2. **SKILL.md body** - When skill triggers (<5k words)
3. **Bundled resources** - As needed by Claude (Unlimited because scripts can be executed without reading into context window)
#### Progressive Disclosure Patterns
Keep SKILL.md body to the essentials and under 500 lines to minimize context bloat. Split content into separate files when approaching this limit. When splitting out content into other files, it is very important to reference them from SKILL.md and describe clearly when to read them, to ensure the reader of the skill knows they exist and when to use them.
**Key principle:** When a skill supports multiple variations, frameworks, or options, keep only the core workflow and selection guidance in SKILL.md. Move variant-specific details (patterns, examples, configuration) into separate reference files.
**Pattern 1: High-level guide with references**
```markdown
# PDF Processing
## Quick start
Extract text with pdfplumber:
[code example]
## Advanced features
- **Form filling**: See [FORMS.md](FORMS.md) for complete guide
- **API reference**: See [REFERENCE.md](REFERENCE.md) for all methods
- **Examples**: See [EXAMPLES.md](EXAMPLES.md) for common patterns
```
Claude loads FORMS.md, REFERENCE.md, or EXAMPLES.md only when needed.
**Pattern 2: Domain-specific organization**
For Skills with multiple domains, organize content by domain to avoid loading irrelevant context:
```
bigquery-skill/
├── SKILL.md (overview and navigation)
└── reference/
├── finance.md (revenue, billing metrics)
├── sales.md (opportunities, pipeline)
├── product.md (API usage, features)
└── marketing.md (campaigns, attribution)
```
When a user asks about sales metrics, Claude only reads sales.md.
Similarly, for skills supporting multiple frameworks or variants, organize by variant:
```
cloud-deploy/
├── SKILL.md (workflow + provider selection)
└── references/
├── aws.md (AWS deployment patterns)
├── gcp.md (GCP deployment patterns)
└── azure.md (Azure deployment patterns)
```
When the user chooses AWS, Claude only reads aws.md.
**Pattern 3: Conditional details**
Show basic content, link to advanced content:
```markdown
# DOCX Processing
## Creating documents
Use docx-js for new documents. See [DOCX-JS.md](DOCX-JS.md).
## Editing documents
For simple edits, modify the XML directly.
**For tracked changes**: See [REDLINING.md](REDLINING.md)
**For OOXML details**: See [OOXML.md](OOXML.md)
```
Claude reads REDLINING.md or OOXML.md only when the user needs those features.
**Important guidelines:**
- **Avoid deeply nested references** - Keep references one level deep from SKILL.md. All reference files should link directly from SKILL.md.
- **Structure longer reference files** - For files longer than 100 lines, include a table of contents at the top so Claude can see the full scope when previewing.
## Skill Creation Process
Skill creation involves these steps:
1. Understand the skill with concrete examples
2. Plan reusable skill contents (scripts, references, assets)
3. Initialize the skill (run init_skill.py)
4. Edit the skill (implement resources and write SKILL.md)
5. Package the skill (run package_skill.py)
6. Iterate based on real usage
Follow these steps in order, skipping only if there is a clear reason why they are not applicable.
### Step 1: Understanding the Skill with Concrete Examples
Skip this step only when the skill's usage patterns are already clearly understood. It remains valuable even when working with an existing skill.
To create an effective skill, clearly understand concrete examples of how the skill will be used. This understanding can come from either direct user examples or generated examples that are validated with user feedback.
For example, when building an image-editor skill, relevant questions include:
- "What functionality should the image-editor skill support? Editing, rotating, anything else?"
- "Can you give some examples of how this skill would be used?"
- "I can imagine users asking for things like 'Remove the red-eye from this image' or 'Rotate this image'. Are there other ways you imagine this skill being used?"
- "What would a user say that should trigger this skill?"
To avoid overwhelming users, avoid asking too many questions in a single message. Start with the most important questions and follow up as needed for better effectiveness.
Conclude this step when there is a clear sense of the functionality the skill should support.
### Step 2: Planning the Reusable Skill Contents
To turn concrete examples into an effective skill, analyze each example by:
1. Considering how to execute on the example from scratch
2. Identifying what scripts, references, and assets would be helpful when executing these workflows repeatedly
Example: When building a `pdf-editor` skill to handle queries like "Help me rotate this PDF," the analysis shows:
1. Rotating a PDF requires re-writing the same code each time
2. A `scripts/rotate_pdf.py` script would be helpful to store in the skill
Example: When designing a `frontend-webapp-builder` skill for queries like "Build me a todo app" or "Build me a dashboard to track my steps," the analysis shows:
1. Writing a frontend webapp requires the same boilerplate HTML/React each time
2. An `assets/hello-world/` template containing the boilerplate HTML/React project files would be helpful to store in the skill
Example: When building a `big-query` skill to handle queries like "How many users have logged in today?" the analysis shows:
1. Querying BigQuery requires re-discovering the table schemas and relationships each time
2. A `references/schema.md` file documenting the table schemas would be helpful to store in the skill
To establish the skill's contents, analyze each concrete example to create a list of the reusable resources to include: scripts, references, and assets.
### Step 3: Initializing the Skill
At this point, it is time to actually create the skill.
Skip this step only if the skill being developed already exists, and iteration or packaging is needed. In this case, continue to the next step.
When creating a new skill from scratch, always run the `init_skill.py` script. The script conveniently generates a new template skill directory that automatically includes everything a skill requires, making the skill creation process much more efficient and reliable.
Usage:
```bash
scripts/init_skill.py <skill-name> --path <output-directory>
```
The script:
- Creates the skill directory at the specified path
- Generates a SKILL.md template with proper frontmatter and TODO placeholders
- Creates example resource directories: `scripts/`, `references/`, and `assets/`
- Adds example files in each directory that can be customized or deleted
After initialization, customize or remove the generated SKILL.md and example files as needed.
### Step 4: Edit the Skill
When editing the (newly-generated or existing) skill, remember that the skill is being created for another instance of Claude to use. Include information that would be beneficial and non-obvious to Claude. Consider what procedural knowledge, domain-specific details, or reusable assets would help another Claude instance execute these tasks more effectively.
#### Learn Proven Design Patterns
Consult these helpful guides based on your skill's needs:
- **Multi-step processes**: See references/workflows.md for sequential workflows and conditional logic
- **Specific output formats or quality standards**: See references/output-patterns.md for template and example patterns
These files contain established best practices for effective skill design.
#### Start with Reusable Skill Contents
To begin implementation, start with the reusable resources identified above: `scripts/`, `references/`, and `assets/` files. Note that this step may require user input. For example, when implementing a `brand-guidelines` skill, the user may need to provide brand assets or templates to store in `assets/`, or documentation to store in `references/`.
Added scripts must be tested by actually running them to ensure there are no bugs and that the output matches what is expected. If there are many similar scripts, only a representative sample needs to be tested to ensure confidence that they all work while balancing time to completion.
Any example files and directories not needed for the skill should be deleted. The initialization script creates example files in `scripts/`, `references/`, and `assets/` to demonstrate structure, but most skills won't need all of them.
#### Update SKILL.md
**Writing Guidelines:** Always use imperative/infinitive form.
##### Frontmatter
Write the YAML frontmatter with `name` and `description`:
- `name`: The skill name
- `description`: This is the primary triggering mechanism for your skill, and helps Claude understand when to use the skill.
- Include both what the Skill does and specific triggers/contexts for when to use it.
- Include all "when to use" information here - Not in the body. The body is only loaded after triggering, so "When to Use This Skill" sections in the body are not helpful to Claude.
- Example description for a `docx` skill: "Comprehensive document creation, editing, and analysis with support for tracked changes, comments, formatting preservation, and text extraction. Use when Claude needs to work with professional documents (.docx files) for: (1) Creating new documents, (2) Modifying or editing content, (3) Working with tracked changes, (4) Adding comments, or any other document tasks"
Do not include any other fields in YAML frontmatter.
##### Body
Write instructions for using the skill and its bundled resources.
### Step 5: Packaging a Skill
Once development of the skill is complete, it must be packaged into a distributable .skill file that gets shared with the user. The packaging process automatically validates the skill first to ensure it meets all requirements:
```bash
scripts/package_skill.py <path/to/skill-folder>
```
Optional output directory specification:
```bash
scripts/package_skill.py <path/to/skill-folder> ./dist
```
The packaging script will:
1. **Validate** the skill automatically, checking:
- YAML frontmatter format and required fields
- Skill naming conventions and directory structure
- Description completeness and quality
- File organization and resource references
2. **Package** the skill if validation passes, creating a .skill file named after the skill (e.g., `my-skill.skill`) that includes all files and maintains the proper directory structure for distribution. The .skill file is a zip file with a .skill extension.
If validation fails, the script will report the errors and exit without creating a package. Fix any validation errors and run the packaging command again.
### Step 6: Iterate
After testing the skill, users may request improvements. Often this happens right after using the skill, with fresh context of how the skill performed.
**Iteration workflow:**
1. Use the skill on real tasks
2. Notice struggles or inefficiencies
3. Identify how SKILL.md or bundled resources should be updated
4. Implement changes and test again

View File

@@ -1,86 +0,0 @@
# Output Patterns
Use these patterns when skills need to produce consistent, high-quality output.
## Template Pattern
Provide templates for output format. Match the level of strictness to your needs.
**For strict requirements (like API responses or data formats):**
```markdown
## Report structure
ALWAYS use this exact template structure:
# [Analysis Title]
## Executive summary
[One-paragraph overview of key findings]
## Key findings
- Finding 1 with supporting data
- Finding 2 with supporting data
- Finding 3 with supporting data
## Recommendations
1. Specific actionable recommendation
2. Specific actionable recommendation
```
**For flexible guidance (when adaptation is useful):**
```markdown
## Report structure
Here is a sensible default format, but use your best judgment:
# [Analysis Title]
## Executive summary
[Overview]
## Key findings
[Adapt sections based on what you discover]
## Recommendations
[Tailor to the specific context]
Adjust sections as needed for the specific analysis type.
```
## Examples Pattern
For skills where output quality depends on seeing examples, provide input/output pairs:
```markdown
## Commit message format
Generate commit messages following these examples:
**Example 1:**
Input: Added user authentication with JWT tokens
Output:
```
feat(auth): implement JWT-based authentication
Add login endpoint and token validation middleware
```
**Example 2:**
Input: Fixed bug where dates displayed incorrectly in reports
Output:
```
fix(reports): correct date formatting in timezone conversion
Use UTC timestamps consistently across report generation
```
Follow this style: type(scope): brief description, then detailed explanation.
```
Examples help Claude understand the desired style and level of detail more clearly than descriptions alone.

View File

@@ -1,28 +0,0 @@
# Workflow Patterns
## Sequential Workflows
For complex tasks, break operations into clear, sequential steps. It is often helpful to give Claude an overview of the process towards the beginning of SKILL.md:
```markdown
Filling a PDF form involves these steps:
1. Analyze the form (run analyze_form.py)
2. Create field mapping (edit fields.json)
3. Validate mapping (run validate_fields.py)
4. Fill the form (run fill_form.py)
5. Verify output (run verify_output.py)
```
## Conditional Workflows
For tasks with branching logic, guide Claude through decision points:
```markdown
1. Determine the modification type:
**Creating new content?** → Follow "Creation workflow" below
**Editing existing content?** → Follow "Editing workflow" below
2. Creation workflow: [steps]
3. Editing workflow: [steps]
```

View File

@@ -1,300 +0,0 @@
#!/usr/bin/env python3
"""
Skill Initializer - Creates a new skill from template
Usage:
init_skill.py <skill-name> --path <path>
Examples:
init_skill.py my-new-skill --path skills/public
init_skill.py my-api-helper --path skills/private
init_skill.py custom-skill --path /custom/location
"""
import sys
from pathlib import Path
SKILL_TEMPLATE = """---
name: {skill_name}
description: [TODO: Complete and informative explanation of what the skill does and when to use it. Include WHEN to use this skill - specific scenarios, file types, or tasks that trigger it.]
---
# {skill_title}
## Overview
[TODO: 1-2 sentences explaining what this skill enables]
## Structuring This Skill
[TODO: Choose the structure that best fits this skill's purpose. Common patterns:
**1. Workflow-Based** (best for sequential processes)
- Works well when there are clear step-by-step procedures
- Example: DOCX skill with "Workflow Decision Tree""Reading""Creating""Editing"
- Structure: ## Overview → ## Workflow Decision Tree → ## Step 1 → ## Step 2...
**2. Task-Based** (best for tool collections)
- Works well when the skill offers different operations/capabilities
- Example: PDF skill with "Quick Start""Merge PDFs""Split PDFs""Extract Text"
- Structure: ## Overview → ## Quick Start → ## Task Category 1 → ## Task Category 2...
**3. Reference/Guidelines** (best for standards or specifications)
- Works well for brand guidelines, coding standards, or requirements
- Example: Brand styling with "Brand Guidelines""Colors""Typography""Features"
- Structure: ## Overview → ## Guidelines → ## Specifications → ## Usage...
**4. Capabilities-Based** (best for integrated systems)
- Works well when the skill provides multiple interrelated features
- Example: Product Management with "Core Capabilities" → numbered capability list
- Structure: ## Overview → ## Core Capabilities → ### 1. Feature → ### 2. Feature...
Patterns can be mixed and matched as needed. Most skills combine patterns (e.g., start with task-based, add workflow for complex operations).
Delete this entire "Structuring This Skill" section when done - it's just guidance.]
## [TODO: Replace with the first main section based on chosen structure]
[TODO: Add content here. See examples in existing skills:
- Code samples for technical skills
- Decision trees for complex workflows
- Concrete examples with realistic user requests
- References to scripts/templates/references as needed]
## Resources
This skill includes example resource directories that demonstrate how to organize different types of bundled resources:
### scripts/
Executable code (Python/Bash/etc.) that can be run directly to perform specific operations.
**Examples from other skills:**
- PDF skill: `fill_fillable_fields.py`, `extract_form_field_info.py` - utilities for PDF manipulation
- DOCX skill: `document.py`, `utilities.py` - Python modules for document processing
**Appropriate for:** Python scripts, shell scripts, or any executable code that performs automation, data processing, or specific operations.
**Note:** Scripts may be executed without loading into context, but can still be read by Claude for patching or environment adjustments.
### references/
Documentation and reference material intended to be loaded into context to inform Claude's process and thinking.
**Examples from other skills:**
- Product management: `communication.md`, `context_building.md` - detailed workflow guides
- BigQuery: API reference documentation and query examples
- Finance: Schema documentation, company policies
**Appropriate for:** In-depth documentation, API references, database schemas, comprehensive guides, or any detailed information that Claude should reference while working.
### assets/
Files not intended to be loaded into context, but rather used within the output Claude produces.
**Examples from other skills:**
- Brand styling: PowerPoint template files (.pptx), logo files
- Frontend builder: HTML/React boilerplate project directories
- Typography: Font files (.ttf, .woff2)
**Appropriate for:** Templates, boilerplate code, document templates, images, icons, fonts, or any files meant to be copied or used in the final output.
---
**Any unneeded directories can be deleted.** Not every skill requires all three types of resources.
"""
EXAMPLE_SCRIPT = '''#!/usr/bin/env python3
"""
Example helper script for {skill_name}
This is a placeholder script that can be executed directly.
Replace with actual implementation or delete if not needed.
Example real scripts from other skills:
- pdf/scripts/fill_fillable_fields.py - Fills PDF form fields
- pdf/scripts/convert_pdf_to_images.py - Converts PDF pages to images
"""
def main():
print("This is an example script for {skill_name}")
# TODO: Add actual script logic here
# This could be data processing, file conversion, API calls, etc.
if __name__ == "__main__":
main()
'''
EXAMPLE_REFERENCE = """# Reference Documentation for {skill_title}
This is a placeholder for detailed reference documentation.
Replace with actual reference content or delete if not needed.
Example real reference docs from other skills:
- product-management/references/communication.md - Comprehensive guide for status updates
- product-management/references/context_building.md - Deep-dive on gathering context
- bigquery/references/ - API references and query examples
## When Reference Docs Are Useful
Reference docs are ideal for:
- Comprehensive API documentation
- Detailed workflow guides
- Complex multi-step processes
- Information too lengthy for main SKILL.md
- Content that's only needed for specific use cases
## Structure Suggestions
### API Reference Example
- Overview
- Authentication
- Endpoints with examples
- Error codes
- Rate limits
### Workflow Guide Example
- Prerequisites
- Step-by-step instructions
- Common patterns
- Troubleshooting
- Best practices
"""
EXAMPLE_ASSET = """# Example Asset File
This placeholder represents where asset files would be stored.
Replace with actual asset files (templates, images, fonts, etc.) or delete if not needed.
Asset files are NOT intended to be loaded into context, but rather used within
the output Claude produces.
Example asset files from other skills:
- Brand guidelines: logo.png, slides_template.pptx
- Frontend builder: hello-world/ directory with HTML/React boilerplate
- Typography: custom-font.ttf, font-family.woff2
- Data: sample_data.csv, test_dataset.json
## Common Asset Types
- Templates: .pptx, .docx, boilerplate directories
- Images: .png, .jpg, .svg, .gif
- Fonts: .ttf, .otf, .woff, .woff2
- Boilerplate code: Project directories, starter files
- Icons: .ico, .svg
- Data files: .csv, .json, .xml, .yaml
Note: This is a text placeholder. Actual assets can be any file type.
"""
def title_case_skill_name(skill_name):
"""Convert hyphenated skill name to Title Case for display."""
return " ".join(word.capitalize() for word in skill_name.split("-"))
def init_skill(skill_name, path):
"""
Initialize a new skill directory with template SKILL.md.
Args:
skill_name: Name of the skill
path: Path where the skill directory should be created
Returns:
Path to created skill directory, or None if error
"""
# Determine skill directory path
skill_dir = Path(path).resolve() / skill_name
# Check if directory already exists
if skill_dir.exists():
print(f"❌ Error: Skill directory already exists: {skill_dir}")
return None
# Create skill directory
try:
skill_dir.mkdir(parents=True, exist_ok=False)
print(f"✅ Created skill directory: {skill_dir}")
except Exception as e:
print(f"❌ Error creating directory: {e}")
return None
# Create SKILL.md from template
skill_title = title_case_skill_name(skill_name)
skill_content = SKILL_TEMPLATE.format(skill_name=skill_name, skill_title=skill_title)
skill_md_path = skill_dir / "SKILL.md"
try:
skill_md_path.write_text(skill_content)
print("✅ Created SKILL.md")
except Exception as e:
print(f"❌ Error creating SKILL.md: {e}")
return None
# Create resource directories with example files
try:
# Create scripts/ directory with example script
scripts_dir = skill_dir / "scripts"
scripts_dir.mkdir(exist_ok=True)
example_script = scripts_dir / "example.py"
example_script.write_text(EXAMPLE_SCRIPT.format(skill_name=skill_name))
example_script.chmod(0o755)
print("✅ Created scripts/example.py")
# Create references/ directory with example reference doc
references_dir = skill_dir / "references"
references_dir.mkdir(exist_ok=True)
example_reference = references_dir / "api_reference.md"
example_reference.write_text(EXAMPLE_REFERENCE.format(skill_title=skill_title))
print("✅ Created references/api_reference.md")
# Create assets/ directory with example asset placeholder
assets_dir = skill_dir / "assets"
assets_dir.mkdir(exist_ok=True)
example_asset = assets_dir / "example_asset.txt"
example_asset.write_text(EXAMPLE_ASSET)
print("✅ Created assets/example_asset.txt")
except Exception as e:
print(f"❌ Error creating resource directories: {e}")
return None
# Print next steps
print(f"\n✅ Skill '{skill_name}' initialized successfully at {skill_dir}")
print("\nNext steps:")
print("1. Edit SKILL.md to complete the TODO items and update the description")
print("2. Customize or delete the example files in scripts/, references/, and assets/")
print("3. Run the validator when ready to check the skill structure")
return skill_dir
def main():
if len(sys.argv) < 4 or sys.argv[2] != "--path":
print("Usage: init_skill.py <skill-name> --path <path>")
print("\nSkill name requirements:")
print(" - Hyphen-case identifier (e.g., 'data-analyzer')")
print(" - Lowercase letters, digits, and hyphens only")
print(" - Max 40 characters")
print(" - Must match directory name exactly")
print("\nExamples:")
print(" init_skill.py my-new-skill --path skills/public")
print(" init_skill.py my-api-helper --path skills/private")
print(" init_skill.py custom-skill --path /custom/location")
sys.exit(1)
skill_name = sys.argv[1]
path = sys.argv[3]
print(f"🚀 Initializing skill: {skill_name}")
print(f" Location: {path}")
print()
result = init_skill(skill_name, path)
if result:
sys.exit(0)
else:
sys.exit(1)
if __name__ == "__main__":
main()

View File

@@ -1,110 +0,0 @@
#!/usr/bin/env python3
"""
Skill Packager - Creates a distributable .skill file of a skill folder
Usage:
python utils/package_skill.py <path/to/skill-folder> [output-directory]
Example:
python utils/package_skill.py skills/public/my-skill
python utils/package_skill.py skills/public/my-skill ./dist
"""
import sys
import zipfile
from pathlib import Path
from quick_validate import validate_skill
def package_skill(skill_path, output_dir=None):
"""
Package a skill folder into a .skill file.
Args:
skill_path: Path to the skill folder
output_dir: Optional output directory for the .skill file (defaults to current directory)
Returns:
Path to the created .skill file, or None if error
"""
skill_path = Path(skill_path).resolve()
# Validate skill folder exists
if not skill_path.exists():
print(f"❌ Error: Skill folder not found: {skill_path}")
return None
if not skill_path.is_dir():
print(f"❌ Error: Path is not a directory: {skill_path}")
return None
# Validate SKILL.md exists
skill_md = skill_path / "SKILL.md"
if not skill_md.exists():
print(f"❌ Error: SKILL.md not found in {skill_path}")
return None
# Run validation before packaging
print("🔍 Validating skill...")
valid, message = validate_skill(skill_path)
if not valid:
print(f"❌ Validation failed: {message}")
print(" Please fix the validation errors before packaging.")
return None
print(f"{message}\n")
# Determine output location
skill_name = skill_path.name
if output_dir:
output_path = Path(output_dir).resolve()
output_path.mkdir(parents=True, exist_ok=True)
else:
output_path = Path.cwd()
skill_filename = output_path / f"{skill_name}.skill"
# Create the .skill file (zip format)
try:
with zipfile.ZipFile(skill_filename, "w", zipfile.ZIP_DEFLATED) as zipf:
# Walk through the skill directory
for file_path in skill_path.rglob("*"):
if file_path.is_file():
# Calculate the relative path within the zip
arcname = file_path.relative_to(skill_path.parent)
zipf.write(file_path, arcname)
print(f" Added: {arcname}")
print(f"\n✅ Successfully packaged skill to: {skill_filename}")
return skill_filename
except Exception as e:
print(f"❌ Error creating .skill file: {e}")
return None
def main():
if len(sys.argv) < 2:
print("Usage: python utils/package_skill.py <path/to/skill-folder> [output-directory]")
print("\nExample:")
print(" python utils/package_skill.py skills/public/my-skill")
print(" python utils/package_skill.py skills/public/my-skill ./dist")
sys.exit(1)
skill_path = sys.argv[1]
output_dir = sys.argv[2] if len(sys.argv) > 2 else None
print(f"📦 Packaging skill: {skill_path}")
if output_dir:
print(f" Output directory: {output_dir}")
print()
result = package_skill(skill_path, output_dir)
if result:
sys.exit(0)
else:
sys.exit(1)
if __name__ == "__main__":
main()

View File

@@ -1,97 +0,0 @@
#!/usr/bin/env python3
"""
Quick validation script for skills - minimal version
"""
import sys
import os
import re
import yaml
from pathlib import Path
def validate_skill(skill_path):
"""Basic validation of a skill"""
skill_path = Path(skill_path)
# Check SKILL.md exists
skill_md = skill_path / "SKILL.md"
if not skill_md.exists():
return False, "SKILL.md not found"
# Read and validate frontmatter
content = skill_md.read_text()
if not content.startswith("---"):
return False, "No YAML frontmatter found"
# Extract frontmatter
match = re.match(r"^---\n(.*?)\n---", content, re.DOTALL)
if not match:
return False, "Invalid frontmatter format"
frontmatter_text = match.group(1)
# Parse YAML frontmatter
try:
frontmatter = yaml.safe_load(frontmatter_text)
if not isinstance(frontmatter, dict):
return False, "Frontmatter must be a YAML dictionary"
except yaml.YAMLError as e:
return False, f"Invalid YAML in frontmatter: {e}"
# Define allowed properties
ALLOWED_PROPERTIES = {"name", "description", "license", "allowed-tools", "metadata"}
# Check for unexpected properties (excluding nested keys under metadata)
unexpected_keys = set(frontmatter.keys()) - ALLOWED_PROPERTIES
if unexpected_keys:
return False, (
f"Unexpected key(s) in SKILL.md frontmatter: {', '.join(sorted(unexpected_keys))}. "
f"Allowed properties are: {', '.join(sorted(ALLOWED_PROPERTIES))}"
)
# Check required fields
if "name" not in frontmatter:
return False, "Missing 'name' in frontmatter"
if "description" not in frontmatter:
return False, "Missing 'description' in frontmatter"
# Extract name for validation
name = frontmatter.get("name", "")
if not isinstance(name, str):
return False, f"Name must be a string, got {type(name).__name__}"
name = name.strip()
if name:
# Check naming convention (hyphen-case: lowercase with hyphens)
if not re.match(r"^[a-z0-9-]+$", name):
return False, f"Name '{name}' should be hyphen-case (lowercase letters, digits, and hyphens only)"
if name.startswith("-") or name.endswith("-") or "--" in name:
return False, f"Name '{name}' cannot start/end with hyphen or contain consecutive hyphens"
# Check name length (max 64 characters per spec)
if len(name) > 64:
return False, f"Name is too long ({len(name)} characters). Maximum is 64 characters."
# Extract and validate description
description = frontmatter.get("description", "")
if not isinstance(description, str):
return False, f"Description must be a string, got {type(description).__name__}"
description = description.strip()
if description:
# Check for angle brackets
if "<" in description or ">" in description:
return False, "Description cannot contain angle brackets (< or >)"
# Check description length (max 1024 characters per spec)
if len(description) > 1024:
return False, f"Description is too long ({len(description)} characters). Maximum is 1024 characters."
return True, "Skill is valid!"
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python quick_validate.py <skill_directory>")
sys.exit(1)
valid, message = validate_skill(sys.argv[1])
print(message)
sys.exit(0 if valid else 1)

File diff suppressed because it is too large Load Diff

View File

@@ -1,125 +0,0 @@
---
name: vercel-react-best-practices
description: React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.
license: MIT
metadata:
author: vercel
version: "1.0.0"
---
# Vercel React Best Practices
Comprehensive performance optimization guide for React and Next.js applications, maintained by Vercel. Contains 45 rules across 8 categories, prioritized by impact to guide automated refactoring and code generation.
## When to Apply
Reference these guidelines when:
- Writing new React components or Next.js pages
- Implementing data fetching (client or server-side)
- Reviewing code for performance issues
- Refactoring existing React/Next.js code
- Optimizing bundle size or load times
## Rule Categories by Priority
| Priority | Category | Impact | Prefix |
|----------|----------|--------|--------|
| 1 | Eliminating Waterfalls | CRITICAL | `async-` |
| 2 | Bundle Size Optimization | CRITICAL | `bundle-` |
| 3 | Server-Side Performance | HIGH | `server-` |
| 4 | Client-Side Data Fetching | MEDIUM-HIGH | `client-` |
| 5 | Re-render Optimization | MEDIUM | `rerender-` |
| 6 | Rendering Performance | MEDIUM | `rendering-` |
| 7 | JavaScript Performance | LOW-MEDIUM | `js-` |
| 8 | Advanced Patterns | LOW | `advanced-` |
## Quick Reference
### 1. Eliminating Waterfalls (CRITICAL)
- `async-defer-await` - Move await into branches where actually used
- `async-parallel` - Use Promise.all() for independent operations
- `async-dependencies` - Use better-all for partial dependencies
- `async-api-routes` - Start promises early, await late in API routes
- `async-suspense-boundaries` - Use Suspense to stream content
### 2. Bundle Size Optimization (CRITICAL)
- `bundle-barrel-imports` - Import directly, avoid barrel files
- `bundle-dynamic-imports` - Use next/dynamic for heavy components
- `bundle-defer-third-party` - Load analytics/logging after hydration
- `bundle-conditional` - Load modules only when feature is activated
- `bundle-preload` - Preload on hover/focus for perceived speed
### 3. Server-Side Performance (HIGH)
- `server-cache-react` - Use React.cache() for per-request deduplication
- `server-cache-lru` - Use LRU cache for cross-request caching
- `server-serialization` - Minimize data passed to client components
- `server-parallel-fetching` - Restructure components to parallelize fetches
- `server-after-nonblocking` - Use after() for non-blocking operations
### 4. Client-Side Data Fetching (MEDIUM-HIGH)
- `client-swr-dedup` - Use SWR for automatic request deduplication
- `client-event-listeners` - Deduplicate global event listeners
### 5. Re-render Optimization (MEDIUM)
- `rerender-defer-reads` - Don't subscribe to state only used in callbacks
- `rerender-memo` - Extract expensive work into memoized components
- `rerender-dependencies` - Use primitive dependencies in effects
- `rerender-derived-state` - Subscribe to derived booleans, not raw values
- `rerender-functional-setstate` - Use functional setState for stable callbacks
- `rerender-lazy-state-init` - Pass function to useState for expensive values
- `rerender-transitions` - Use startTransition for non-urgent updates
### 6. Rendering Performance (MEDIUM)
- `rendering-animate-svg-wrapper` - Animate div wrapper, not SVG element
- `rendering-content-visibility` - Use content-visibility for long lists
- `rendering-hoist-jsx` - Extract static JSX outside components
- `rendering-svg-precision` - Reduce SVG coordinate precision
- `rendering-hydration-no-flicker` - Use inline script for client-only data
- `rendering-activity` - Use Activity component for show/hide
- `rendering-conditional-render` - Use ternary, not && for conditionals
### 7. JavaScript Performance (LOW-MEDIUM)
- `js-batch-dom-css` - Group CSS changes via classes or cssText
- `js-index-maps` - Build Map for repeated lookups
- `js-cache-property-access` - Cache object properties in loops
- `js-cache-function-results` - Cache function results in module-level Map
- `js-cache-storage` - Cache localStorage/sessionStorage reads
- `js-combine-iterations` - Combine multiple filter/map into one loop
- `js-length-check-first` - Check array length before expensive comparison
- `js-early-exit` - Return early from functions
- `js-hoist-regexp` - Hoist RegExp creation outside loops
- `js-min-max-loop` - Use loop for min/max instead of sort
- `js-set-map-lookups` - Use Set/Map for O(1) lookups
- `js-tosorted-immutable` - Use toSorted() for immutability
### 8. Advanced Patterns (LOW)
- `advanced-event-handler-refs` - Store event handlers in refs
- `advanced-use-latest` - useLatest for stable callback refs
## How to Use
Read individual rule files for detailed explanations and code examples:
```
rules/async-parallel.md
rules/bundle-barrel-imports.md
rules/_sections.md
```
Each rule file contains:
- Brief explanation of why it matters
- Incorrect code example with explanation
- Correct code example with explanation
- Additional context and references
## Full Compiled Document
For the complete guide with all rules expanded: `AGENTS.md`

View File

@@ -1,55 +0,0 @@
---
title: Store Event Handlers in Refs
impact: LOW
impactDescription: stable subscriptions
tags: advanced, hooks, refs, event-handlers, optimization
---
## Store Event Handlers in Refs
Store callbacks in refs when used in effects that shouldn't re-subscribe on callback changes.
**Incorrect (re-subscribes on every render):**
```tsx
function useWindowEvent(event: string, handler: (e) => void) {
useEffect(() => {
window.addEventListener(event, handler)
return () => window.removeEventListener(event, handler)
}, [event, handler])
}
```
**Correct (stable subscription):**
```tsx
function useWindowEvent(event: string, handler: (e) => void) {
const handlerRef = useRef(handler)
useEffect(() => {
handlerRef.current = handler
}, [handler])
useEffect(() => {
const listener = (e) => handlerRef.current(e)
window.addEventListener(event, listener)
return () => window.removeEventListener(event, listener)
}, [event])
}
```
**Alternative: use `useEffectEvent` if you're on latest React:**
```tsx
import { useEffectEvent } from 'react'
function useWindowEvent(event: string, handler: (e) => void) {
const onEvent = useEffectEvent(handler)
useEffect(() => {
window.addEventListener(event, onEvent)
return () => window.removeEventListener(event, onEvent)
}, [event])
}
```
`useEffectEvent` provides a cleaner API for the same pattern: it creates a stable function reference that always calls the latest version of the handler.

View File

@@ -1,49 +0,0 @@
---
title: useLatest for Stable Callback Refs
impact: LOW
impactDescription: prevents effect re-runs
tags: advanced, hooks, useLatest, refs, optimization
---
## useLatest for Stable Callback Refs
Access latest values in callbacks without adding them to dependency arrays. Prevents effect re-runs while avoiding stale closures.
**Implementation:**
```typescript
function useLatest<T>(value: T) {
const ref = useRef(value)
useLayoutEffect(() => {
ref.current = value
}, [value])
return ref
}
```
**Incorrect (effect re-runs on every callback change):**
```tsx
function SearchInput({ onSearch }: { onSearch: (q: string) => void }) {
const [query, setQuery] = useState('')
useEffect(() => {
const timeout = setTimeout(() => onSearch(query), 300)
return () => clearTimeout(timeout)
}, [query, onSearch])
}
```
**Correct (stable effect, fresh callback):**
```tsx
function SearchInput({ onSearch }: { onSearch: (q: string) => void }) {
const [query, setQuery] = useState('')
const onSearchRef = useLatest(onSearch)
useEffect(() => {
const timeout = setTimeout(() => onSearchRef.current(query), 300)
return () => clearTimeout(timeout)
}, [query])
}
```

View File

@@ -1,38 +0,0 @@
---
title: Prevent Waterfall Chains in API Routes
impact: CRITICAL
impactDescription: 2-10× improvement
tags: api-routes, server-actions, waterfalls, parallelization
---
## Prevent Waterfall Chains in API Routes
In API routes and Server Actions, start independent operations immediately, even if you don't await them yet.
**Incorrect (config waits for auth, data waits for both):**
```typescript
export async function GET(request: Request) {
const session = await auth()
const config = await fetchConfig()
const data = await fetchData(session.user.id)
return Response.json({ data, config })
}
```
**Correct (auth and config start immediately):**
```typescript
export async function GET(request: Request) {
const sessionPromise = auth()
const configPromise = fetchConfig()
const session = await sessionPromise
const [config, data] = await Promise.all([
configPromise,
fetchData(session.user.id)
])
return Response.json({ data, config })
}
```
For operations with more complex dependency chains, use `better-all` to automatically maximize parallelism (see Dependency-Based Parallelization).

View File

@@ -1,80 +0,0 @@
---
title: Defer Await Until Needed
impact: HIGH
impactDescription: avoids blocking unused code paths
tags: async, await, conditional, optimization
---
## Defer Await Until Needed
Move `await` operations into the branches where they're actually used to avoid blocking code paths that don't need them.
**Incorrect (blocks both branches):**
```typescript
async function handleRequest(userId: string, skipProcessing: boolean) {
const userData = await fetchUserData(userId)
if (skipProcessing) {
// Returns immediately but still waited for userData
return { skipped: true }
}
// Only this branch uses userData
return processUserData(userData)
}
```
**Correct (only blocks when needed):**
```typescript
async function handleRequest(userId: string, skipProcessing: boolean) {
if (skipProcessing) {
// Returns immediately without waiting
return { skipped: true }
}
// Fetch only when needed
const userData = await fetchUserData(userId)
return processUserData(userData)
}
```
**Another example (early return optimization):**
```typescript
// Incorrect: always fetches permissions
async function updateResource(resourceId: string, userId: string) {
const permissions = await fetchPermissions(userId)
const resource = await getResource(resourceId)
if (!resource) {
return { error: 'Not found' }
}
if (!permissions.canEdit) {
return { error: 'Forbidden' }
}
return await updateResourceData(resource, permissions)
}
// Correct: fetches only when needed
async function updateResource(resourceId: string, userId: string) {
const resource = await getResource(resourceId)
if (!resource) {
return { error: 'Not found' }
}
const permissions = await fetchPermissions(userId)
if (!permissions.canEdit) {
return { error: 'Forbidden' }
}
return await updateResourceData(resource, permissions)
}
```
This optimization is especially valuable when the skipped branch is frequently taken, or when the deferred operation is expensive.

View File

@@ -1,36 +0,0 @@
---
title: Dependency-Based Parallelization
impact: CRITICAL
impactDescription: 2-10× improvement
tags: async, parallelization, dependencies, better-all
---
## Dependency-Based Parallelization
For operations with partial dependencies, use `better-all` to maximize parallelism. It automatically starts each task at the earliest possible moment.
**Incorrect (profile waits for config unnecessarily):**
```typescript
const [user, config] = await Promise.all([
fetchUser(),
fetchConfig()
])
const profile = await fetchProfile(user.id)
```
**Correct (config and profile run in parallel):**
```typescript
import { all } from 'better-all'
const { user, config, profile } = await all({
async user() { return fetchUser() },
async config() { return fetchConfig() },
async profile() {
return fetchProfile((await this.$.user).id)
}
})
```
Reference: [https://github.com/shuding/better-all](https://github.com/shuding/better-all)

View File

@@ -1,28 +0,0 @@
---
title: Promise.all() for Independent Operations
impact: CRITICAL
impactDescription: 2-10× improvement
tags: async, parallelization, promises, waterfalls
---
## Promise.all() for Independent Operations
When async operations have no interdependencies, execute them concurrently using `Promise.all()`.
**Incorrect (sequential execution, 3 round trips):**
```typescript
const user = await fetchUser()
const posts = await fetchPosts()
const comments = await fetchComments()
```
**Correct (parallel execution, 1 round trip):**
```typescript
const [user, posts, comments] = await Promise.all([
fetchUser(),
fetchPosts(),
fetchComments()
])
```

View File

@@ -1,99 +0,0 @@
---
title: Strategic Suspense Boundaries
impact: HIGH
impactDescription: faster initial paint
tags: async, suspense, streaming, layout-shift
---
## Strategic Suspense Boundaries
Instead of awaiting data in async components before returning JSX, use Suspense boundaries to show the wrapper UI faster while data loads.
**Incorrect (wrapper blocked by data fetching):**
```tsx
async function Page() {
const data = await fetchData() // Blocks entire page
return (
<div>
<div>Sidebar</div>
<div>Header</div>
<div>
<DataDisplay data={data} />
</div>
<div>Footer</div>
</div>
)
}
```
The entire layout waits for data even though only the middle section needs it.
**Correct (wrapper shows immediately, data streams in):**
```tsx
function Page() {
return (
<div>
<div>Sidebar</div>
<div>Header</div>
<div>
<Suspense fallback={<Skeleton />}>
<DataDisplay />
</Suspense>
</div>
<div>Footer</div>
</div>
)
}
async function DataDisplay() {
const data = await fetchData() // Only blocks this component
return <div>{data.content}</div>
}
```
Sidebar, Header, and Footer render immediately. Only DataDisplay waits for data.
**Alternative (share promise across components):**
```tsx
function Page() {
// Start fetch immediately, but don't await
const dataPromise = fetchData()
return (
<div>
<div>Sidebar</div>
<div>Header</div>
<Suspense fallback={<Skeleton />}>
<DataDisplay dataPromise={dataPromise} />
<DataSummary dataPromise={dataPromise} />
</Suspense>
<div>Footer</div>
</div>
)
}
function DataDisplay({ dataPromise }: { dataPromise: Promise<Data> }) {
const data = use(dataPromise) // Unwraps the promise
return <div>{data.content}</div>
}
function DataSummary({ dataPromise }: { dataPromise: Promise<Data> }) {
const data = use(dataPromise) // Reuses the same promise
return <div>{data.summary}</div>
}
```
Both components share the same promise, so only one fetch occurs. Layout renders immediately while both components wait together.
**When NOT to use this pattern:**
- Critical data needed for layout decisions (affects positioning)
- SEO-critical content above the fold
- Small, fast queries where suspense overhead isn't worth it
- When you want to avoid layout shift (loading → content jump)
**Trade-off:** Faster initial paint vs potential layout shift. Choose based on your UX priorities.

View File

@@ -1,59 +0,0 @@
---
title: Avoid Barrel File Imports
impact: CRITICAL
impactDescription: 200-800ms import cost, slow builds
tags: bundle, imports, tree-shaking, barrel-files, performance
---
## Avoid Barrel File Imports
Import directly from source files instead of barrel files to avoid loading thousands of unused modules. **Barrel files** are entry points that re-export multiple modules (e.g., `index.js` that does `export * from './module'`).
Popular icon and component libraries can have **up to 10,000 re-exports** in their entry file. For many React packages, **it takes 200-800ms just to import them**, affecting both development speed and production cold starts.
**Why tree-shaking doesn't help:** When a library is marked as external (not bundled), the bundler can't optimize it. If you bundle it to enable tree-shaking, builds become substantially slower analyzing the entire module graph.
**Incorrect (imports entire library):**
```tsx
import { Check, X, Menu } from 'lucide-react'
// Loads 1,583 modules, takes ~2.8s extra in dev
// Runtime cost: 200-800ms on every cold start
import { Button, TextField } from '@mui/material'
// Loads 2,225 modules, takes ~4.2s extra in dev
```
**Correct (imports only what you need):**
```tsx
import Check from 'lucide-react/dist/esm/icons/check'
import X from 'lucide-react/dist/esm/icons/x'
import Menu from 'lucide-react/dist/esm/icons/menu'
// Loads only 3 modules (~2KB vs ~1MB)
import Button from '@mui/material/Button'
import TextField from '@mui/material/TextField'
// Loads only what you use
```
**Alternative (Next.js 13.5+):**
```js
// next.config.js - use optimizePackageImports
module.exports = {
experimental: {
optimizePackageImports: ['lucide-react', '@mui/material']
}
}
// Then you can keep the ergonomic barrel imports:
import { Check, X, Menu } from 'lucide-react'
// Automatically transformed to direct imports at build time
```
Direct imports provide 15-70% faster dev boot, 28% faster builds, 40% faster cold starts, and significantly faster HMR.
Libraries commonly affected: `lucide-react`, `@mui/material`, `@mui/icons-material`, `@tabler/icons-react`, `react-icons`, `@headlessui/react`, `@radix-ui/react-*`, `lodash`, `ramda`, `date-fns`, `rxjs`, `react-use`.
Reference: [How we optimized package imports in Next.js](https://vercel.com/blog/how-we-optimized-package-imports-in-next-js)

View File

@@ -1,31 +0,0 @@
---
title: Conditional Module Loading
impact: HIGH
impactDescription: loads large data only when needed
tags: bundle, conditional-loading, lazy-loading
---
## Conditional Module Loading
Load large data or modules only when a feature is activated.
**Example (lazy-load animation frames):**
```tsx
function AnimationPlayer({ enabled, setEnabled }: { enabled: boolean; setEnabled: React.Dispatch<React.SetStateAction<boolean>> }) {
const [frames, setFrames] = useState<Frame[] | null>(null)
useEffect(() => {
if (enabled && !frames && typeof window !== 'undefined') {
import('./animation-frames.js')
.then(mod => setFrames(mod.frames))
.catch(() => setEnabled(false))
}
}, [enabled, frames, setEnabled])
if (!frames) return <Skeleton />
return <Canvas frames={frames} />
}
```
The `typeof window !== 'undefined'` check prevents bundling this module for SSR, optimizing server bundle size and build speed.

View File

@@ -1,49 +0,0 @@
---
title: Defer Non-Critical Third-Party Libraries
impact: MEDIUM
impactDescription: loads after hydration
tags: bundle, third-party, analytics, defer
---
## Defer Non-Critical Third-Party Libraries
Analytics, logging, and error tracking don't block user interaction. Load them after hydration.
**Incorrect (blocks initial bundle):**
```tsx
import { Analytics } from '@vercel/analytics/react'
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
<Analytics />
</body>
</html>
)
}
```
**Correct (loads after hydration):**
```tsx
import dynamic from 'next/dynamic'
const Analytics = dynamic(
() => import('@vercel/analytics/react').then(m => m.Analytics),
{ ssr: false }
)
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
<Analytics />
</body>
</html>
)
}
```

View File

@@ -1,35 +0,0 @@
---
title: Dynamic Imports for Heavy Components
impact: CRITICAL
impactDescription: directly affects TTI and LCP
tags: bundle, dynamic-import, code-splitting, next-dynamic
---
## Dynamic Imports for Heavy Components
Use `next/dynamic` to lazy-load large components not needed on initial render.
**Incorrect (Monaco bundles with main chunk ~300KB):**
```tsx
import { MonacoEditor } from './monaco-editor'
function CodePanel({ code }: { code: string }) {
return <MonacoEditor value={code} />
}
```
**Correct (Monaco loads on demand):**
```tsx
import dynamic from 'next/dynamic'
const MonacoEditor = dynamic(
() => import('./monaco-editor').then(m => m.MonacoEditor),
{ ssr: false }
)
function CodePanel({ code }: { code: string }) {
return <MonacoEditor value={code} />
}
```

View File

@@ -1,50 +0,0 @@
---
title: Preload Based on User Intent
impact: MEDIUM
impactDescription: reduces perceived latency
tags: bundle, preload, user-intent, hover
---
## Preload Based on User Intent
Preload heavy bundles before they're needed to reduce perceived latency.
**Example (preload on hover/focus):**
```tsx
function EditorButton({ onClick }: { onClick: () => void }) {
const preload = () => {
if (typeof window !== 'undefined') {
void import('./monaco-editor')
}
}
return (
<button
onMouseEnter={preload}
onFocus={preload}
onClick={onClick}
>
Open Editor
</button>
)
}
```
**Example (preload when feature flag is enabled):**
```tsx
function FlagsProvider({ children, flags }: Props) {
useEffect(() => {
if (flags.editorEnabled && typeof window !== 'undefined') {
void import('./monaco-editor').then(mod => mod.init())
}
}, [flags.editorEnabled])
return <FlagsContext.Provider value={flags}>
{children}
</FlagsContext.Provider>
}
```
The `typeof window !== 'undefined'` check prevents bundling preloaded modules for SSR, optimizing server bundle size and build speed.

View File

@@ -1,74 +0,0 @@
---
title: Deduplicate Global Event Listeners
impact: LOW
impactDescription: single listener for N components
tags: client, swr, event-listeners, subscription
---
## Deduplicate Global Event Listeners
Use `useSWRSubscription()` to share global event listeners across component instances.
**Incorrect (N instances = N listeners):**
```tsx
function useKeyboardShortcut(key: string, callback: () => void) {
useEffect(() => {
const handler = (e: KeyboardEvent) => {
if (e.metaKey && e.key === key) {
callback()
}
}
window.addEventListener('keydown', handler)
return () => window.removeEventListener('keydown', handler)
}, [key, callback])
}
```
When using the `useKeyboardShortcut` hook multiple times, each instance will register a new listener.
**Correct (N instances = 1 listener):**
```tsx
import useSWRSubscription from 'swr/subscription'
// Module-level Map to track callbacks per key
const keyCallbacks = new Map<string, Set<() => void>>()
function useKeyboardShortcut(key: string, callback: () => void) {
// Register this callback in the Map
useEffect(() => {
if (!keyCallbacks.has(key)) {
keyCallbacks.set(key, new Set())
}
keyCallbacks.get(key)!.add(callback)
return () => {
const set = keyCallbacks.get(key)
if (set) {
set.delete(callback)
if (set.size === 0) {
keyCallbacks.delete(key)
}
}
}
}, [key, callback])
useSWRSubscription('global-keydown', () => {
const handler = (e: KeyboardEvent) => {
if (e.metaKey && keyCallbacks.has(e.key)) {
keyCallbacks.get(e.key)!.forEach(cb => cb())
}
}
window.addEventListener('keydown', handler)
return () => window.removeEventListener('keydown', handler)
})
}
function Profile() {
// Multiple shortcuts will share the same listener
useKeyboardShortcut('p', () => { /* ... */ })
useKeyboardShortcut('k', () => { /* ... */ })
// ...
}
```

View File

@@ -1,71 +0,0 @@
---
title: Version and Minimize localStorage Data
impact: MEDIUM
impactDescription: prevents schema conflicts, reduces storage size
tags: client, localStorage, storage, versioning, data-minimization
---
## Version and Minimize localStorage Data
Add version prefix to keys and store only needed fields. Prevents schema conflicts and accidental storage of sensitive data.
**Incorrect:**
```typescript
// No version, stores everything, no error handling
localStorage.setItem('userConfig', JSON.stringify(fullUserObject))
const data = localStorage.getItem('userConfig')
```
**Correct:**
```typescript
const VERSION = 'v2'
function saveConfig(config: { theme: string; language: string }) {
try {
localStorage.setItem(`userConfig:${VERSION}`, JSON.stringify(config))
} catch {
// Throws in incognito/private browsing, quota exceeded, or disabled
}
}
function loadConfig() {
try {
const data = localStorage.getItem(`userConfig:${VERSION}`)
return data ? JSON.parse(data) : null
} catch {
return null
}
}
// Migration from v1 to v2
function migrate() {
try {
const v1 = localStorage.getItem('userConfig:v1')
if (v1) {
const old = JSON.parse(v1)
saveConfig({ theme: old.darkMode ? 'dark' : 'light', language: old.lang })
localStorage.removeItem('userConfig:v1')
}
} catch {}
}
```
**Store minimal fields from server responses:**
```typescript
// User object has 20+ fields, only store what UI needs
function cachePrefs(user: FullUser) {
try {
localStorage.setItem('prefs:v1', JSON.stringify({
theme: user.preferences.theme,
notifications: user.preferences.notifications
}))
} catch {}
}
```
**Always wrap in try-catch:** `getItem()` and `setItem()` throw in incognito/private browsing (Safari, Firefox), when quota exceeded, or when disabled.
**Benefits:** Schema evolution via versioning, reduced storage size, prevents storing tokens/PII/internal flags.

View File

@@ -1,48 +0,0 @@
---
title: Use Passive Event Listeners for Scrolling Performance
impact: MEDIUM
impactDescription: eliminates scroll delay caused by event listeners
tags: client, event-listeners, scrolling, performance, touch, wheel
---
## Use Passive Event Listeners for Scrolling Performance
Add `{ passive: true }` to touch and wheel event listeners to enable immediate scrolling. Browsers normally wait for listeners to finish to check if `preventDefault()` is called, causing scroll delay.
**Incorrect:**
```typescript
useEffect(() => {
const handleTouch = (e: TouchEvent) => console.log(e.touches[0].clientX)
const handleWheel = (e: WheelEvent) => console.log(e.deltaY)
document.addEventListener('touchstart', handleTouch)
document.addEventListener('wheel', handleWheel)
return () => {
document.removeEventListener('touchstart', handleTouch)
document.removeEventListener('wheel', handleWheel)
}
}, [])
```
**Correct:**
```typescript
useEffect(() => {
const handleTouch = (e: TouchEvent) => console.log(e.touches[0].clientX)
const handleWheel = (e: WheelEvent) => console.log(e.deltaY)
document.addEventListener('touchstart', handleTouch, { passive: true })
document.addEventListener('wheel', handleWheel, { passive: true })
return () => {
document.removeEventListener('touchstart', handleTouch)
document.removeEventListener('wheel', handleWheel)
}
}, [])
```
**Use passive when:** tracking/analytics, logging, any listener that doesn't call `preventDefault()`.
**Don't use passive when:** implementing custom swipe gestures, custom zoom controls, or any listener that needs `preventDefault()`.

View File

@@ -1,56 +0,0 @@
---
title: Use SWR for Automatic Deduplication
impact: MEDIUM-HIGH
impactDescription: automatic deduplication
tags: client, swr, deduplication, data-fetching
---
## Use SWR for Automatic Deduplication
SWR enables request deduplication, caching, and revalidation across component instances.
**Incorrect (no deduplication, each instance fetches):**
```tsx
function UserList() {
const [users, setUsers] = useState([])
useEffect(() => {
fetch('/api/users')
.then(r => r.json())
.then(setUsers)
}, [])
}
```
**Correct (multiple instances share one request):**
```tsx
import useSWR from 'swr'
function UserList() {
const { data: users } = useSWR('/api/users', fetcher)
}
```
**For immutable data:**
```tsx
import { useImmutableSWR } from '@/lib/swr'
function StaticContent() {
const { data } = useImmutableSWR('/api/config', fetcher)
}
```
**For mutations:**
```tsx
import { useSWRMutation } from 'swr/mutation'
function UpdateButton() {
const { trigger } = useSWRMutation('/api/user', updateUser)
return <button onClick={() => trigger()}>Update</button>
}
```
Reference: [https://swr.vercel.app](https://swr.vercel.app)

View File

@@ -1,57 +0,0 @@
---
title: Batch DOM CSS Changes
impact: MEDIUM
impactDescription: reduces reflows/repaints
tags: javascript, dom, css, performance, reflow
---
## Batch DOM CSS Changes
Avoid interleaving style writes with layout reads. When you read a layout property (like `offsetWidth`, `getBoundingClientRect()`, or `getComputedStyle()`) between style changes, the browser is forced to trigger a synchronous reflow.
**Incorrect (interleaved reads and writes force reflows):**
```typescript
function updateElementStyles(element: HTMLElement) {
element.style.width = '100px'
const width = element.offsetWidth // Forces reflow
element.style.height = '200px'
const height = element.offsetHeight // Forces another reflow
}
```
**Correct (batch writes, then read once):**
```typescript
function updateElementStyles(element: HTMLElement) {
// Batch all writes together
element.style.width = '100px'
element.style.height = '200px'
element.style.backgroundColor = 'blue'
element.style.border = '1px solid black'
// Read after all writes are done (single reflow)
const { width, height } = element.getBoundingClientRect()
}
```
**Better: use CSS classes**
```css
.highlighted-box {
width: 100px;
height: 200px;
background-color: blue;
border: 1px solid black;
}
```
```typescript
function updateElementStyles(element: HTMLElement) {
element.classList.add('highlighted-box')
const { width, height } = element.getBoundingClientRect()
}
```
Prefer CSS classes over inline styles when possible. CSS files are cached by the browser, and classes provide better separation of concerns and are easier to maintain.

View File

@@ -1,80 +0,0 @@
---
title: Cache Repeated Function Calls
impact: MEDIUM
impactDescription: avoid redundant computation
tags: javascript, cache, memoization, performance
---
## Cache Repeated Function Calls
Use a module-level Map to cache function results when the same function is called repeatedly with the same inputs during render.
**Incorrect (redundant computation):**
```typescript
function ProjectList({ projects }: { projects: Project[] }) {
return (
<div>
{projects.map(project => {
// slugify() called 100+ times for same project names
const slug = slugify(project.name)
return <ProjectCard key={project.id} slug={slug} />
})}
</div>
)
}
```
**Correct (cached results):**
```typescript
// Module-level cache
const slugifyCache = new Map<string, string>()
function cachedSlugify(text: string): string {
if (slugifyCache.has(text)) {
return slugifyCache.get(text)!
}
const result = slugify(text)
slugifyCache.set(text, result)
return result
}
function ProjectList({ projects }: { projects: Project[] }) {
return (
<div>
{projects.map(project => {
// Computed only once per unique project name
const slug = cachedSlugify(project.name)
return <ProjectCard key={project.id} slug={slug} />
})}
</div>
)
}
```
**Simpler pattern for single-value functions:**
```typescript
let isLoggedInCache: boolean | null = null
function isLoggedIn(): boolean {
if (isLoggedInCache !== null) {
return isLoggedInCache
}
isLoggedInCache = document.cookie.includes('auth=')
return isLoggedInCache
}
// Clear cache when auth changes
function onAuthChange() {
isLoggedInCache = null
}
```
Use a Map (not a hook) so it works everywhere: utilities, event handlers, not just React components.
Reference: [How we made the Vercel Dashboard twice as fast](https://vercel.com/blog/how-we-made-the-vercel-dashboard-twice-as-fast)

View File

@@ -1,28 +0,0 @@
---
title: Cache Property Access in Loops
impact: LOW-MEDIUM
impactDescription: reduces lookups
tags: javascript, loops, optimization, caching
---
## Cache Property Access in Loops
Cache object property lookups in hot paths.
**Incorrect (3 lookups × N iterations):**
```typescript
for (let i = 0; i < arr.length; i++) {
process(obj.config.settings.value)
}
```
**Correct (1 lookup total):**
```typescript
const value = obj.config.settings.value
const len = arr.length
for (let i = 0; i < len; i++) {
process(value)
}
```

View File

@@ -1,70 +0,0 @@
---
title: Cache Storage API Calls
impact: LOW-MEDIUM
impactDescription: reduces expensive I/O
tags: javascript, localStorage, storage, caching, performance
---
## Cache Storage API Calls
`localStorage`, `sessionStorage`, and `document.cookie` are synchronous and expensive. Cache reads in memory.
**Incorrect (reads storage on every call):**
```typescript
function getTheme() {
return localStorage.getItem('theme') ?? 'light'
}
// Called 10 times = 10 storage reads
```
**Correct (Map cache):**
```typescript
const storageCache = new Map<string, string | null>()
function getLocalStorage(key: string) {
if (!storageCache.has(key)) {
storageCache.set(key, localStorage.getItem(key))
}
return storageCache.get(key)
}
function setLocalStorage(key: string, value: string) {
localStorage.setItem(key, value)
storageCache.set(key, value) // keep cache in sync
}
```
Use a Map (not a hook) so it works everywhere: utilities, event handlers, not just React components.
**Cookie caching:**
```typescript
let cookieCache: Record<string, string> | null = null
function getCookie(name: string) {
if (!cookieCache) {
cookieCache = Object.fromEntries(
document.cookie.split('; ').map(c => c.split('='))
)
}
return cookieCache[name]
}
```
**Important (invalidate on external changes):**
If storage can change externally (another tab, server-set cookies), invalidate cache:
```typescript
window.addEventListener('storage', (e) => {
if (e.key) storageCache.delete(e.key)
})
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'visible') {
storageCache.clear()
}
})
```

View File

@@ -1,32 +0,0 @@
---
title: Combine Multiple Array Iterations
impact: LOW-MEDIUM
impactDescription: reduces iterations
tags: javascript, arrays, loops, performance
---
## Combine Multiple Array Iterations
Multiple `.filter()` or `.map()` calls iterate the array multiple times. Combine into one loop.
**Incorrect (3 iterations):**
```typescript
const admins = users.filter(u => u.isAdmin)
const testers = users.filter(u => u.isTester)
const inactive = users.filter(u => !u.isActive)
```
**Correct (1 iteration):**
```typescript
const admins: User[] = []
const testers: User[] = []
const inactive: User[] = []
for (const user of users) {
if (user.isAdmin) admins.push(user)
if (user.isTester) testers.push(user)
if (!user.isActive) inactive.push(user)
}
```

View File

@@ -1,50 +0,0 @@
---
title: Early Return from Functions
impact: LOW-MEDIUM
impactDescription: avoids unnecessary computation
tags: javascript, functions, optimization, early-return
---
## Early Return from Functions
Return early when result is determined to skip unnecessary processing.
**Incorrect (processes all items even after finding answer):**
```typescript
function validateUsers(users: User[]) {
let hasError = false
let errorMessage = ''
for (const user of users) {
if (!user.email) {
hasError = true
errorMessage = 'Email required'
}
if (!user.name) {
hasError = true
errorMessage = 'Name required'
}
// Continues checking all users even after error found
}
return hasError ? { valid: false, error: errorMessage } : { valid: true }
}
```
**Correct (returns immediately on first error):**
```typescript
function validateUsers(users: User[]) {
for (const user of users) {
if (!user.email) {
return { valid: false, error: 'Email required' }
}
if (!user.name) {
return { valid: false, error: 'Name required' }
}
}
return { valid: true }
}
```

View File

@@ -1,45 +0,0 @@
---
title: Hoist RegExp Creation
impact: LOW-MEDIUM
impactDescription: avoids recreation
tags: javascript, regexp, optimization, memoization
---
## Hoist RegExp Creation
Don't create RegExp inside render. Hoist to module scope or memoize with `useMemo()`.
**Incorrect (new RegExp every render):**
```tsx
function Highlighter({ text, query }: Props) {
const regex = new RegExp(`(${query})`, 'gi')
const parts = text.split(regex)
return <>{parts.map((part, i) => ...)}</>
}
```
**Correct (memoize or hoist):**
```tsx
const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
function Highlighter({ text, query }: Props) {
const regex = useMemo(
() => new RegExp(`(${escapeRegex(query)})`, 'gi'),
[query]
)
const parts = text.split(regex)
return <>{parts.map((part, i) => ...)}</>
}
```
**Warning (global regex has mutable state):**
Global regex (`/g`) has mutable `lastIndex` state:
```typescript
const regex = /foo/g
regex.test('foo') // true, lastIndex = 3
regex.test('foo') // false, lastIndex = 0
```

View File

@@ -1,37 +0,0 @@
---
title: Build Index Maps for Repeated Lookups
impact: LOW-MEDIUM
impactDescription: 1M ops to 2K ops
tags: javascript, map, indexing, optimization, performance
---
## Build Index Maps for Repeated Lookups
Multiple `.find()` calls by the same key should use a Map.
**Incorrect (O(n) per lookup):**
```typescript
function processOrders(orders: Order[], users: User[]) {
return orders.map(order => ({
...order,
user: users.find(u => u.id === order.userId)
}))
}
```
**Correct (O(1) per lookup):**
```typescript
function processOrders(orders: Order[], users: User[]) {
const userById = new Map(users.map(u => [u.id, u]))
return orders.map(order => ({
...order,
user: userById.get(order.userId)
}))
}
```
Build map once (O(n)), then all lookups are O(1).
For 1000 orders × 1000 users: 1M ops → 2K ops.

View File

@@ -1,49 +0,0 @@
---
title: Early Length Check for Array Comparisons
impact: MEDIUM-HIGH
impactDescription: avoids expensive operations when lengths differ
tags: javascript, arrays, performance, optimization, comparison
---
## Early Length Check for Array Comparisons
When comparing arrays with expensive operations (sorting, deep equality, serialization), check lengths first. If lengths differ, the arrays cannot be equal.
In real-world applications, this optimization is especially valuable when the comparison runs in hot paths (event handlers, render loops).
**Incorrect (always runs expensive comparison):**
```typescript
function hasChanges(current: string[], original: string[]) {
// Always sorts and joins, even when lengths differ
return current.sort().join() !== original.sort().join()
}
```
Two O(n log n) sorts run even when `current.length` is 5 and `original.length` is 100. There is also overhead of joining the arrays and comparing the strings.
**Correct (O(1) length check first):**
```typescript
function hasChanges(current: string[], original: string[]) {
// Early return if lengths differ
if (current.length !== original.length) {
return true
}
// Only sort when lengths match
const currentSorted = current.toSorted()
const originalSorted = original.toSorted()
for (let i = 0; i < currentSorted.length; i++) {
if (currentSorted[i] !== originalSorted[i]) {
return true
}
}
return false
}
```
This new approach is more efficient because:
- It avoids the overhead of sorting and joining the arrays when lengths differ
- It avoids consuming memory for the joined strings (especially important for large arrays)
- It avoids mutating the original arrays
- It returns early when a difference is found

View File

@@ -1,82 +0,0 @@
---
title: Use Loop for Min/Max Instead of Sort
impact: LOW
impactDescription: O(n) instead of O(n log n)
tags: javascript, arrays, performance, sorting, algorithms
---
## Use Loop for Min/Max Instead of Sort
Finding the smallest or largest element only requires a single pass through the array. Sorting is wasteful and slower.
**Incorrect (O(n log n) - sort to find latest):**
```typescript
interface Project {
id: string
name: string
updatedAt: number
}
function getLatestProject(projects: Project[]) {
const sorted = [...projects].sort((a, b) => b.updatedAt - a.updatedAt)
return sorted[0]
}
```
Sorts the entire array just to find the maximum value.
**Incorrect (O(n log n) - sort for oldest and newest):**
```typescript
function getOldestAndNewest(projects: Project[]) {
const sorted = [...projects].sort((a, b) => a.updatedAt - b.updatedAt)
return { oldest: sorted[0], newest: sorted[sorted.length - 1] }
}
```
Still sorts unnecessarily when only min/max are needed.
**Correct (O(n) - single loop):**
```typescript
function getLatestProject(projects: Project[]) {
if (projects.length === 0) return null
let latest = projects[0]
for (let i = 1; i < projects.length; i++) {
if (projects[i].updatedAt > latest.updatedAt) {
latest = projects[i]
}
}
return latest
}
function getOldestAndNewest(projects: Project[]) {
if (projects.length === 0) return { oldest: null, newest: null }
let oldest = projects[0]
let newest = projects[0]
for (let i = 1; i < projects.length; i++) {
if (projects[i].updatedAt < oldest.updatedAt) oldest = projects[i]
if (projects[i].updatedAt > newest.updatedAt) newest = projects[i]
}
return { oldest, newest }
}
```
Single pass through the array, no copying, no sorting.
**Alternative (Math.min/Math.max for small arrays):**
```typescript
const numbers = [5, 2, 8, 1, 9]
const min = Math.min(...numbers)
const max = Math.max(...numbers)
```
This works for small arrays, but can be slower or just throw an error for very large arrays due to spread operator limitations. Maximal array length is approximately 124000 in Chrome 143 and 638000 in Safari 18; exact numbers may vary - see [the fiddle](https://jsfiddle.net/qw1jabsx/4/). Use the loop approach for reliability.

View File

@@ -1,24 +0,0 @@
---
title: Use Set/Map for O(1) Lookups
impact: LOW-MEDIUM
impactDescription: O(n) to O(1)
tags: javascript, set, map, data-structures, performance
---
## Use Set/Map for O(1) Lookups
Convert arrays to Set/Map for repeated membership checks.
**Incorrect (O(n) per check):**
```typescript
const allowedIds = ['a', 'b', 'c', ...]
items.filter(item => allowedIds.includes(item.id))
```
**Correct (O(1) per check):**
```typescript
const allowedIds = new Set(['a', 'b', 'c', ...])
items.filter(item => allowedIds.has(item.id))
```

View File

@@ -1,57 +0,0 @@
---
title: Use toSorted() Instead of sort() for Immutability
impact: MEDIUM-HIGH
impactDescription: prevents mutation bugs in React state
tags: javascript, arrays, immutability, react, state, mutation
---
## Use toSorted() Instead of sort() for Immutability
`.sort()` mutates the array in place, which can cause bugs with React state and props. Use `.toSorted()` to create a new sorted array without mutation.
**Incorrect (mutates original array):**
```typescript
function UserList({ users }: { users: User[] }) {
// Mutates the users prop array!
const sorted = useMemo(
() => users.sort((a, b) => a.name.localeCompare(b.name)),
[users]
)
return <div>{sorted.map(renderUser)}</div>
}
```
**Correct (creates new array):**
```typescript
function UserList({ users }: { users: User[] }) {
// Creates new sorted array, original unchanged
const sorted = useMemo(
() => users.toSorted((a, b) => a.name.localeCompare(b.name)),
[users]
)
return <div>{sorted.map(renderUser)}</div>
}
```
**Why this matters in React:**
1. Props/state mutations break React's immutability model - React expects props and state to be treated as read-only
2. Causes stale closure bugs - Mutating arrays inside closures (callbacks, effects) can lead to unexpected behavior
**Browser support (fallback for older browsers):**
`.toSorted()` is available in all modern browsers (Chrome 110+, Safari 16+, Firefox 115+, Node.js 20+). For older environments, use spread operator:
```typescript
// Fallback for older browsers
const sorted = [...items].sort((a, b) => a.value - b.value)
```
**Other immutable array methods:**
- `.toSorted()` - immutable sort
- `.toReversed()` - immutable reverse
- `.toSpliced()` - immutable splice
- `.with()` - immutable element replacement

View File

@@ -1,26 +0,0 @@
---
title: Use Activity Component for Show/Hide
impact: MEDIUM
impactDescription: preserves state/DOM
tags: rendering, activity, visibility, state-preservation
---
## Use Activity Component for Show/Hide
Use React's `<Activity>` to preserve state/DOM for expensive components that frequently toggle visibility.
**Usage:**
```tsx
import { Activity } from 'react'
function Dropdown({ isOpen }: Props) {
return (
<Activity mode={isOpen ? 'visible' : 'hidden'}>
<ExpensiveMenu />
</Activity>
)
}
```
Avoids expensive re-renders and state loss.

View File

@@ -1,47 +0,0 @@
---
title: Animate SVG Wrapper Instead of SVG Element
impact: LOW
impactDescription: enables hardware acceleration
tags: rendering, svg, css, animation, performance
---
## Animate SVG Wrapper Instead of SVG Element
Many browsers don't have hardware acceleration for CSS3 animations on SVG elements. Wrap SVG in a `<div>` and animate the wrapper instead.
**Incorrect (animating SVG directly - no hardware acceleration):**
```tsx
function LoadingSpinner() {
return (
<svg
className="animate-spin"
width="24"
height="24"
viewBox="0 0 24 24"
>
<circle cx="12" cy="12" r="10" stroke="currentColor" />
</svg>
)
}
```
**Correct (animating wrapper div - hardware accelerated):**
```tsx
function LoadingSpinner() {
return (
<div className="animate-spin">
<svg
width="24"
height="24"
viewBox="0 0 24 24"
>
<circle cx="12" cy="12" r="10" stroke="currentColor" />
</svg>
</div>
)
}
```
This applies to all CSS transforms and transitions (`transform`, `opacity`, `translate`, `scale`, `rotate`). The wrapper div allows browsers to use GPU acceleration for smoother animations.

View File

@@ -1,40 +0,0 @@
---
title: Use Explicit Conditional Rendering
impact: LOW
impactDescription: prevents rendering 0 or NaN
tags: rendering, conditional, jsx, falsy-values
---
## Use Explicit Conditional Rendering
Use explicit ternary operators (`? :`) instead of `&&` for conditional rendering when the condition can be `0`, `NaN`, or other falsy values that render.
**Incorrect (renders "0" when count is 0):**
```tsx
function Badge({ count }: { count: number }) {
return (
<div>
{count && <span className="badge">{count}</span>}
</div>
)
}
// When count = 0, renders: <div>0</div>
// When count = 5, renders: <div><span class="badge">5</span></div>
```
**Correct (renders nothing when count is 0):**
```tsx
function Badge({ count }: { count: number }) {
return (
<div>
{count > 0 ? <span className="badge">{count}</span> : null}
</div>
)
}
// When count = 0, renders: <div></div>
// When count = 5, renders: <div><span class="badge">5</span></div>
```

View File

@@ -1,38 +0,0 @@
---
title: CSS content-visibility for Long Lists
impact: HIGH
impactDescription: faster initial render
tags: rendering, css, content-visibility, long-lists
---
## CSS content-visibility for Long Lists
Apply `content-visibility: auto` to defer off-screen rendering.
**CSS:**
```css
.message-item {
content-visibility: auto;
contain-intrinsic-size: 0 80px;
}
```
**Example:**
```tsx
function MessageList({ messages }: { messages: Message[] }) {
return (
<div className="overflow-y-auto h-screen">
{messages.map(msg => (
<div key={msg.id} className="message-item">
<Avatar user={msg.author} />
<div>{msg.content}</div>
</div>
))}
</div>
)
}
```
For 1000 messages, browser skips layout/paint for ~990 off-screen items (10× faster initial render).

View File

@@ -1,46 +0,0 @@
---
title: Hoist Static JSX Elements
impact: LOW
impactDescription: avoids re-creation
tags: rendering, jsx, static, optimization
---
## Hoist Static JSX Elements
Extract static JSX outside components to avoid re-creation.
**Incorrect (recreates element every render):**
```tsx
function LoadingSkeleton() {
return <div className="animate-pulse h-20 bg-gray-200" />
}
function Container() {
return (
<div>
{loading && <LoadingSkeleton />}
</div>
)
}
```
**Correct (reuses same element):**
```tsx
const loadingSkeleton = (
<div className="animate-pulse h-20 bg-gray-200" />
)
function Container() {
return (
<div>
{loading && loadingSkeleton}
</div>
)
}
```
This is especially helpful for large and static SVG nodes, which can be expensive to recreate on every render.
**Note:** If your project has [React Compiler](https://react.dev/learn/react-compiler) enabled, the compiler automatically hoists static JSX elements and optimizes component re-renders, making manual hoisting unnecessary.

View File

@@ -1,82 +0,0 @@
---
title: Prevent Hydration Mismatch Without Flickering
impact: MEDIUM
impactDescription: avoids visual flicker and hydration errors
tags: rendering, ssr, hydration, localStorage, flicker
---
## Prevent Hydration Mismatch Without Flickering
When rendering content that depends on client-side storage (localStorage, cookies), avoid both SSR breakage and post-hydration flickering by injecting a synchronous script that updates the DOM before React hydrates.
**Incorrect (breaks SSR):**
```tsx
function ThemeWrapper({ children }: { children: ReactNode }) {
// localStorage is not available on server - throws error
const theme = localStorage.getItem('theme') || 'light'
return (
<div className={theme}>
{children}
</div>
)
}
```
Server-side rendering will fail because `localStorage` is undefined.
**Incorrect (visual flickering):**
```tsx
function ThemeWrapper({ children }: { children: ReactNode }) {
const [theme, setTheme] = useState('light')
useEffect(() => {
// Runs after hydration - causes visible flash
const stored = localStorage.getItem('theme')
if (stored) {
setTheme(stored)
}
}, [])
return (
<div className={theme}>
{children}
</div>
)
}
```
Component first renders with default value (`light`), then updates after hydration, causing a visible flash of incorrect content.
**Correct (no flicker, no hydration mismatch):**
```tsx
function ThemeWrapper({ children }: { children: ReactNode }) {
return (
<>
<div id="theme-wrapper">
{children}
</div>
<script
dangerouslySetInnerHTML={{
__html: `
(function() {
try {
var theme = localStorage.getItem('theme') || 'light';
var el = document.getElementById('theme-wrapper');
if (el) el.className = theme;
} catch (e) {}
})();
`,
}}
/>
</>
)
}
```
The inline script executes synchronously before showing the element, ensuring the DOM already has the correct value. No flickering, no hydration mismatch.
This pattern is especially useful for theme toggles, user preferences, authentication states, and any client-only data that should render immediately without flashing default values.

View File

@@ -1,28 +0,0 @@
---
title: Optimize SVG Precision
impact: LOW
impactDescription: reduces file size
tags: rendering, svg, optimization, svgo
---
## Optimize SVG Precision
Reduce SVG coordinate precision to decrease file size. The optimal precision depends on the viewBox size, but in general reducing precision should be considered.
**Incorrect (excessive precision):**
```svg
<path d="M 10.293847 20.847362 L 30.938472 40.192837" />
```
**Correct (1 decimal place):**
```svg
<path d="M 10.3 20.8 L 30.9 40.2" />
```
**Automate with SVGO:**
```bash
npx svgo --precision=1 --multipass icon.svg
```

View File

@@ -1,39 +0,0 @@
---
title: Defer State Reads to Usage Point
impact: MEDIUM
impactDescription: avoids unnecessary subscriptions
tags: rerender, searchParams, localStorage, optimization
---
## Defer State Reads to Usage Point
Don't subscribe to dynamic state (searchParams, localStorage) if you only read it inside callbacks.
**Incorrect (subscribes to all searchParams changes):**
```tsx
function ShareButton({ chatId }: { chatId: string }) {
const searchParams = useSearchParams()
const handleShare = () => {
const ref = searchParams.get('ref')
shareChat(chatId, { ref })
}
return <button onClick={handleShare}>Share</button>
}
```
**Correct (reads on demand, no subscription):**
```tsx
function ShareButton({ chatId }: { chatId: string }) {
const handleShare = () => {
const params = new URLSearchParams(window.location.search)
const ref = params.get('ref')
shareChat(chatId, { ref })
}
return <button onClick={handleShare}>Share</button>
}
```

View File

@@ -1,45 +0,0 @@
---
title: Narrow Effect Dependencies
impact: LOW
impactDescription: minimizes effect re-runs
tags: rerender, useEffect, dependencies, optimization
---
## Narrow Effect Dependencies
Specify primitive dependencies instead of objects to minimize effect re-runs.
**Incorrect (re-runs on any user field change):**
```tsx
useEffect(() => {
console.log(user.id)
}, [user])
```
**Correct (re-runs only when id changes):**
```tsx
useEffect(() => {
console.log(user.id)
}, [user.id])
```
**For derived state, compute outside effect:**
```tsx
// Incorrect: runs on width=767, 766, 765...
useEffect(() => {
if (width < 768) {
enableMobileMode()
}
}, [width])
// Correct: runs only on boolean transition
const isMobile = width < 768
useEffect(() => {
if (isMobile) {
enableMobileMode()
}
}, [isMobile])
```

View File

@@ -1,29 +0,0 @@
---
title: Subscribe to Derived State
impact: MEDIUM
impactDescription: reduces re-render frequency
tags: rerender, derived-state, media-query, optimization
---
## Subscribe to Derived State
Subscribe to derived boolean state instead of continuous values to reduce re-render frequency.
**Incorrect (re-renders on every pixel change):**
```tsx
function Sidebar() {
const width = useWindowWidth() // updates continuously
const isMobile = width < 768
return <nav className={isMobile ? 'mobile' : 'desktop'} />
}
```
**Correct (re-renders only when boolean changes):**
```tsx
function Sidebar() {
const isMobile = useMediaQuery('(max-width: 767px)')
return <nav className={isMobile ? 'mobile' : 'desktop'} />
}
```

View File

@@ -1,74 +0,0 @@
---
title: Use Functional setState Updates
impact: MEDIUM
impactDescription: prevents stale closures and unnecessary callback recreations
tags: react, hooks, useState, useCallback, callbacks, closures
---
## Use Functional setState Updates
When updating state based on the current state value, use the functional update form of setState instead of directly referencing the state variable. This prevents stale closures, eliminates unnecessary dependencies, and creates stable callback references.
**Incorrect (requires state as dependency):**
```tsx
function TodoList() {
const [items, setItems] = useState(initialItems)
// Callback must depend on items, recreated on every items change
const addItems = useCallback((newItems: Item[]) => {
setItems([...items, ...newItems])
}, [items]) // ❌ items dependency causes recreations
// Risk of stale closure if dependency is forgotten
const removeItem = useCallback((id: string) => {
setItems(items.filter(item => item.id !== id))
}, []) // ❌ Missing items dependency - will use stale items!
return <ItemsEditor items={items} onAdd={addItems} onRemove={removeItem} />
}
```
The first callback is recreated every time `items` changes, which can cause child components to re-render unnecessarily. The second callback has a stale closure bug—it will always reference the initial `items` value.
**Correct (stable callbacks, no stale closures):**
```tsx
function TodoList() {
const [items, setItems] = useState(initialItems)
// Stable callback, never recreated
const addItems = useCallback((newItems: Item[]) => {
setItems(curr => [...curr, ...newItems])
}, []) // ✅ No dependencies needed
// Always uses latest state, no stale closure risk
const removeItem = useCallback((id: string) => {
setItems(curr => curr.filter(item => item.id !== id))
}, []) // ✅ Safe and stable
return <ItemsEditor items={items} onAdd={addItems} onRemove={removeItem} />
}
```
**Benefits:**
1. **Stable callback references** - Callbacks don't need to be recreated when state changes
2. **No stale closures** - Always operates on the latest state value
3. **Fewer dependencies** - Simplifies dependency arrays and reduces memory leaks
4. **Prevents bugs** - Eliminates the most common source of React closure bugs
**When to use functional updates:**
- Any setState that depends on the current state value
- Inside useCallback/useMemo when state is needed
- Event handlers that reference state
- Async operations that update state
**When direct updates are fine:**
- Setting state to a static value: `setCount(0)`
- Setting state from props/arguments only: `setName(newName)`
- State doesn't depend on previous value
**Note:** If your project has [React Compiler](https://react.dev/learn/react-compiler) enabled, the compiler can automatically optimize some cases, but functional updates are still recommended for correctness and to prevent stale closure bugs.

View File

@@ -1,58 +0,0 @@
---
title: Use Lazy State Initialization
impact: MEDIUM
impactDescription: wasted computation on every render
tags: react, hooks, useState, performance, initialization
---
## Use Lazy State Initialization
Pass a function to `useState` for expensive initial values. Without the function form, the initializer runs on every render even though the value is only used once.
**Incorrect (runs on every render):**
```tsx
function FilteredList({ items }: { items: Item[] }) {
// buildSearchIndex() runs on EVERY render, even after initialization
const [searchIndex, setSearchIndex] = useState(buildSearchIndex(items))
const [query, setQuery] = useState('')
// When query changes, buildSearchIndex runs again unnecessarily
return <SearchResults index={searchIndex} query={query} />
}
function UserProfile() {
// JSON.parse runs on every render
const [settings, setSettings] = useState(
JSON.parse(localStorage.getItem('settings') || '{}')
)
return <SettingsForm settings={settings} onChange={setSettings} />
}
```
**Correct (runs only once):**
```tsx
function FilteredList({ items }: { items: Item[] }) {
// buildSearchIndex() runs ONLY on initial render
const [searchIndex, setSearchIndex] = useState(() => buildSearchIndex(items))
const [query, setQuery] = useState('')
return <SearchResults index={searchIndex} query={query} />
}
function UserProfile() {
// JSON.parse runs only on initial render
const [settings, setSettings] = useState(() => {
const stored = localStorage.getItem('settings')
return stored ? JSON.parse(stored) : {}
})
return <SettingsForm settings={settings} onChange={setSettings} />
}
```
Use lazy initialization when computing initial values from localStorage/sessionStorage, building data structures (indexes, maps), reading from the DOM, or performing heavy transformations.
For simple primitives (`useState(0)`), direct references (`useState(props.value)`), or cheap literals (`useState({})`), the function form is unnecessary.

View File

@@ -1,44 +0,0 @@
---
title: Extract to Memoized Components
impact: MEDIUM
impactDescription: enables early returns
tags: rerender, memo, useMemo, optimization
---
## Extract to Memoized Components
Extract expensive work into memoized components to enable early returns before computation.
**Incorrect (computes avatar even when loading):**
```tsx
function Profile({ user, loading }: Props) {
const avatar = useMemo(() => {
const id = computeAvatarId(user)
return <Avatar id={id} />
}, [user])
if (loading) return <Skeleton />
return <div>{avatar}</div>
}
```
**Correct (skips computation when loading):**
```tsx
const UserAvatar = memo(function UserAvatar({ user }: { user: User }) {
const id = useMemo(() => computeAvatarId(user), [user])
return <Avatar id={id} />
})
function Profile({ user, loading }: Props) {
if (loading) return <Skeleton />
return (
<div>
<UserAvatar user={user} />
</div>
)
}
```
**Note:** If your project has [React Compiler](https://react.dev/learn/react-compiler) enabled, manual memoization with `memo()` and `useMemo()` is not necessary. The compiler automatically optimizes re-renders.

View File

@@ -1,40 +0,0 @@
---
title: Use Transitions for Non-Urgent Updates
impact: MEDIUM
impactDescription: maintains UI responsiveness
tags: rerender, transitions, startTransition, performance
---
## Use Transitions for Non-Urgent Updates
Mark frequent, non-urgent state updates as transitions to maintain UI responsiveness.
**Incorrect (blocks UI on every scroll):**
```tsx
function ScrollTracker() {
const [scrollY, setScrollY] = useState(0)
useEffect(() => {
const handler = () => setScrollY(window.scrollY)
window.addEventListener('scroll', handler, { passive: true })
return () => window.removeEventListener('scroll', handler)
}, [])
}
```
**Correct (non-blocking updates):**
```tsx
import { startTransition } from 'react'
function ScrollTracker() {
const [scrollY, setScrollY] = useState(0)
useEffect(() => {
const handler = () => {
startTransition(() => setScrollY(window.scrollY))
}
window.addEventListener('scroll', handler, { passive: true })
return () => window.removeEventListener('scroll', handler)
}, [])
}
```

View File

@@ -1,73 +0,0 @@
---
title: Use after() for Non-Blocking Operations
impact: MEDIUM
impactDescription: faster response times
tags: server, async, logging, analytics, side-effects
---
## Use after() for Non-Blocking Operations
Use Next.js's `after()` to schedule work that should execute after a response is sent. This prevents logging, analytics, and other side effects from blocking the response.
**Incorrect (blocks response):**
```tsx
import { logUserAction } from '@/app/utils'
export async function POST(request: Request) {
// Perform mutation
await updateDatabase(request)
// Logging blocks the response
const userAgent = request.headers.get('user-agent') || 'unknown'
await logUserAction({ userAgent })
return new Response(JSON.stringify({ status: 'success' }), {
status: 200,
headers: { 'Content-Type': 'application/json' }
})
}
```
**Correct (non-blocking):**
```tsx
import { after } from 'next/server'
import { headers, cookies } from 'next/headers'
import { logUserAction } from '@/app/utils'
export async function POST(request: Request) {
// Perform mutation
await updateDatabase(request)
// Log after response is sent
after(async () => {
const userAgent = (await headers()).get('user-agent') || 'unknown'
const sessionCookie = (await cookies()).get('session-id')?.value || 'anonymous'
logUserAction({ sessionCookie, userAgent })
})
return new Response(JSON.stringify({ status: 'success' }), {
status: 200,
headers: { 'Content-Type': 'application/json' }
})
}
```
The response is sent immediately while logging happens in the background.
**Common use cases:**
- Analytics tracking
- Audit logging
- Sending notifications
- Cache invalidation
- Cleanup tasks
**Important notes:**
- `after()` runs even if the response fails or redirects
- Works in Server Actions, Route Handlers, and Server Components
Reference: [https://nextjs.org/docs/app/api-reference/functions/after](https://nextjs.org/docs/app/api-reference/functions/after)

View File

@@ -1,41 +0,0 @@
---
title: Cross-Request LRU Caching
impact: HIGH
impactDescription: caches across requests
tags: server, cache, lru, cross-request
---
## Cross-Request LRU Caching
`React.cache()` only works within one request. For data shared across sequential requests (user clicks button A then button B), use an LRU cache.
**Implementation:**
```typescript
import { LRUCache } from 'lru-cache'
const cache = new LRUCache<string, any>({
max: 1000,
ttl: 5 * 60 * 1000 // 5 minutes
})
export async function getUser(id: string) {
const cached = cache.get(id)
if (cached) return cached
const user = await db.user.findUnique({ where: { id } })
cache.set(id, user)
return user
}
// Request 1: DB query, result cached
// Request 2: cache hit, no DB query
```
Use when sequential user actions hit multiple endpoints needing the same data within seconds.
**With Vercel's [Fluid Compute](https://vercel.com/docs/fluid-compute):** LRU caching is especially effective because multiple concurrent requests can share the same function instance and cache. This means the cache persists across requests without needing external storage like Redis.
**In traditional serverless:** Each invocation runs in isolation, so consider Redis for cross-process caching.
Reference: [https://github.com/isaacs/node-lru-cache](https://github.com/isaacs/node-lru-cache)

View File

@@ -1,76 +0,0 @@
---
title: Per-Request Deduplication with React.cache()
impact: MEDIUM
impactDescription: deduplicates within request
tags: server, cache, react-cache, deduplication
---
## Per-Request Deduplication with React.cache()
Use `React.cache()` for server-side request deduplication. Authentication and database queries benefit most.
**Usage:**
```typescript
import { cache } from 'react'
export const getCurrentUser = cache(async () => {
const session = await auth()
if (!session?.user?.id) return null
return await db.user.findUnique({
where: { id: session.user.id }
})
})
```
Within a single request, multiple calls to `getCurrentUser()` execute the query only once.
**Avoid inline objects as arguments:**
`React.cache()` uses shallow equality (`Object.is`) to determine cache hits. Inline objects create new references each call, preventing cache hits.
**Incorrect (always cache miss):**
```typescript
const getUser = cache(async (params: { uid: number }) => {
return await db.user.findUnique({ where: { id: params.uid } })
})
// Each call creates new object, never hits cache
getUser({ uid: 1 })
getUser({ uid: 1 }) // Cache miss, runs query again
```
**Correct (cache hit):**
```typescript
const getUser = cache(async (uid: number) => {
return await db.user.findUnique({ where: { id: uid } })
})
// Primitive args use value equality
getUser(1)
getUser(1) // Cache hit, returns cached result
```
If you must pass objects, pass the same reference:
```typescript
const params = { uid: 1 }
getUser(params) // Query runs
getUser(params) // Cache hit (same reference)
```
**Next.js-Specific Note:**
In Next.js, the `fetch` API is automatically extended with request memoization. Requests with the same URL and options are automatically deduplicated within a single request, so you don't need `React.cache()` for `fetch` calls. However, `React.cache()` is still essential for other async tasks:
- Database queries (Prisma, Drizzle, etc.)
- Heavy computations
- Authentication checks
- File system operations
- Any non-fetch async work
Use `React.cache()` to deduplicate these operations across your component tree.
Reference: [React.cache documentation](https://react.dev/reference/react/cache)

View File

@@ -1,83 +0,0 @@
---
title: Parallel Data Fetching with Component Composition
impact: CRITICAL
impactDescription: eliminates server-side waterfalls
tags: server, rsc, parallel-fetching, composition
---
## Parallel Data Fetching with Component Composition
React Server Components execute sequentially within a tree. Restructure with composition to parallelize data fetching.
**Incorrect (Sidebar waits for Page's fetch to complete):**
```tsx
export default async function Page() {
const header = await fetchHeader()
return (
<div>
<div>{header}</div>
<Sidebar />
</div>
)
}
async function Sidebar() {
const items = await fetchSidebarItems()
return <nav>{items.map(renderItem)}</nav>
}
```
**Correct (both fetch simultaneously):**
```tsx
async function Header() {
const data = await fetchHeader()
return <div>{data}</div>
}
async function Sidebar() {
const items = await fetchSidebarItems()
return <nav>{items.map(renderItem)}</nav>
}
export default function Page() {
return (
<div>
<Header />
<Sidebar />
</div>
)
}
```
**Alternative with children prop:**
```tsx
async function Header() {
const data = await fetchHeader()
return <div>{data}</div>
}
async function Sidebar() {
const items = await fetchSidebarItems()
return <nav>{items.map(renderItem)}</nav>
}
function Layout({ children }: { children: ReactNode }) {
return (
<div>
<Header />
{children}
</div>
)
}
export default function Page() {
return (
<Layout>
<Sidebar />
</Layout>
)
}
```

View File

@@ -1,38 +0,0 @@
---
title: Minimize Serialization at RSC Boundaries
impact: HIGH
impactDescription: reduces data transfer size
tags: server, rsc, serialization, props
---
## Minimize Serialization at RSC Boundaries
The React Server/Client boundary serializes all object properties into strings and embeds them in the HTML response and subsequent RSC requests. This serialized data directly impacts page weight and load time, so **size matters a lot**. Only pass fields that the client actually uses.
**Incorrect (serializes all 50 fields):**
```tsx
async function Page() {
const user = await fetchUser() // 50 fields
return <Profile user={user} />
}
'use client'
function Profile({ user }: { user: User }) {
return <div>{user.name}</div> // uses 1 field
}
```
**Correct (serializes only 1 field):**
```tsx
async function Page() {
const user = await fetchUser()
return <Profile name={user.name} />
}
'use client'
function Profile({ name }: { name: string }) {
return <div>{name}</div>
}
```

View File

@@ -1 +0,0 @@
../.claude/skills

View File

@@ -1,5 +0,0 @@
[run]
omit =
api/tests/*
api/migrations/*
api/core/rag/datasource/vdb/*

View File

@@ -1,4 +1,5 @@
FROM mcr.microsoft.com/devcontainers/python:3.12-bookworm
FROM mcr.microsoft.com/devcontainers/python:3.12
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
&& apt-get -y install libgmp-dev libmpfr-dev libmpc-dev
# [Optional] Uncomment this section to install additional OS packages.
# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
# && apt-get -y install --no-install-recommends <your-package-list-here>

View File

@@ -1,26 +1,23 @@
# Development with devcontainer
This project includes a devcontainer configuration that allows you to open the project in a container with a fully configured development environment.
Both frontend and backend environments are initialized when the container is started.
## GitHub Codespaces
[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/langgenius/dify)
you can simply click the button above to open this project in GitHub Codespaces.
For more info, check out the [GitHub documentation](https://docs.github.com/en/free-pro-team@latest/github/developing-online-with-codespaces/creating-a-codespace#creating-a-codespace).
## VS Code Dev Containers
## VS Code Dev Containers
[![Open in Dev Containers](https://img.shields.io/static/v1?label=Dev%20Containers&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/langgenius/dify)
if you have VS Code installed, you can click the button above to open this project in VS Code Dev Containers.
You can learn more in the [Dev Containers documentation](https://code.visualstudio.com/docs/devcontainers/containers).
## Pros of Devcontainer
## Pros of Devcontainer
Unified Development Environment: By using devcontainers, you can ensure that all developers are developing in the same environment, reducing the occurrence of "it works on my machine" type of issues.
Quick Start: New developers can set up their development environment in a few simple steps, without spending a lot of time on environment configuration.
@@ -28,15 +25,13 @@ Quick Start: New developers can set up their development environment in a few si
Isolation: Devcontainers isolate your project from your host operating system, reducing the chance of OS updates or other application installations impacting the development environment.
## Cons of Devcontainer
Learning Curve: For developers unfamiliar with Docker and VS Code, using devcontainers may be somewhat complex.
Performance Impact: While usually minimal, programs running inside a devcontainer may be slightly slower than those running directly on the host.
## Troubleshooting
if you see such error message when you open this project in codespaces:
![Alt text](troubleshooting.png)
a simple workaround is change `/signin` endpoint into another one, then login with GitHub account and close the tab, then change it back to `/signin` endpoint. Then all things will be fine.
The reason is `signin` endpoint is not allowed in codespaces, details can be found [here](https://github.com/orgs/community/discussions/5204)
The reason is `signin` endpoint is not allowed in codespaces, details can be found [here](https://github.com/orgs/community/discussions/5204)

View File

@@ -2,19 +2,16 @@
// README at: https://github.com/devcontainers/templates/tree/main/src/anaconda
{
"name": "Python 3.12",
"build": {
"build": {
"context": "..",
"dockerfile": "Dockerfile"
},
"mounts": [
"source=dify-dev-tmp,target=/tmp,type=volume"
],
"features": {
"ghcr.io/devcontainers/features/node:1": {
"nodeGypDependencies": true,
"version": "lts"
},
"ghcr.io/devcontainers-extra/features/npm-package:1": {
"ghcr.io/devcontainers-contrib/features/npm-package:1": {
"package": "typescript",
"version": "latest"
},
@@ -37,13 +34,19 @@
},
"postStartCommand": "./.devcontainer/post_start_command.sh",
"postCreateCommand": "./.devcontainer/post_create_command.sh"
// Features to add to the dev container. More info: https://containers.dev/features.
// "features": {},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "python --version",
// Configure tool-specific properties.
// "customizations": {},
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
}
// "remoteUser": "root"
}

View File

@@ -1,3 +1,3 @@
This file copied into the container along with environment.yml* from the parent
folder. This file is included to prevents the Dockerfile COPY instruction from
failing if no environment.yml is found.
folder. This file is included to prevents the Dockerfile COPY instruction from
failing if no environment.yml is found.

View File

@@ -1,16 +1,13 @@
#!/bin/bash
WORKSPACE_ROOT=$(pwd)
export COREPACK_ENABLE_DOWNLOAD_PROMPT=0
corepack enable
npm add -g pnpm@9.12.2
cd web && pnpm install
pipx install uv
pipx install poetry
echo "alias start-api=\"cd $WORKSPACE_ROOT/api && uv run python -m flask run --host 0.0.0.0 --port=5001 --debug\"" >> ~/.bashrc
echo "alias start-worker=\"cd $WORKSPACE_ROOT/api && uv run python -m celery -A app.celery worker -P threads -c 1 --loglevel INFO -Q dataset,priority_dataset,priority_pipeline,pipeline,mail,ops_trace,app_deletion,plugin,workflow_storage,conversation,workflow,schedule_poller,schedule_executor,triggered_workflow_dispatcher,trigger_refresh_executor,retention\"" >> ~/.bashrc
echo "alias start-web=\"cd $WORKSPACE_ROOT/web && pnpm dev\"" >> ~/.bashrc
echo "alias start-web-prod=\"cd $WORKSPACE_ROOT/web && pnpm build && pnpm start\"" >> ~/.bashrc
echo "alias start-containers=\"cd $WORKSPACE_ROOT/docker && docker-compose -f docker-compose.middleware.yaml -p dify --env-file middleware.env up -d\"" >> ~/.bashrc
echo "alias stop-containers=\"cd $WORKSPACE_ROOT/docker && docker-compose -f docker-compose.middleware.yaml -p dify --env-file middleware.env down\"" >> ~/.bashrc
echo 'alias start-api="cd /workspaces/dify/api && poetry run python -m flask run --host 0.0.0.0 --port=5001 --debug"' >> ~/.bashrc
echo 'alias start-worker="cd /workspaces/dify/api && poetry run python -m celery -A app.celery worker -P gevent -c 1 --loglevel INFO -Q dataset,generation,mail,ops_trace,app_deletion"' >> ~/.bashrc
echo 'alias start-web="cd /workspaces/dify/web && pnpm dev"' >> ~/.bashrc
echo 'alias start-containers="cd /workspaces/dify/docker && docker-compose -f docker-compose.middleware.yaml -p dify up -d"' >> ~/.bashrc
echo 'alias stop-containers="cd /workspaces/dify/docker && docker-compose -f docker-compose.middleware.yaml -p dify down"' >> ~/.bashrc
source /home/vscode/.bashrc

View File

@@ -1,3 +1,3 @@
#!/bin/bash
cd api && uv sync
cd api && poetry install

View File

@@ -1,39 +0,0 @@
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.py]
indent_size = 4
indent_style = space
[*.{yml,yaml}]
indent_style = space
indent_size = 2
[*.toml]
indent_size = 4
indent_style = space
# Markdown and MDX are whitespace sensitive languages.
# Do not remove trailing spaces.
[*.{md,mdx}]
trim_trailing_whitespace = false
# Matches multiple files with brace expansion notation
# Set default charset
[*.{js,jsx,ts,tsx,mjs}]
indent_style = space
indent_size = 2
# Matches the exact files package.json
[package.json]
indent_style = space
indent_size = 2

2
.gitattributes vendored
View File

@@ -1,5 +1,5 @@
# Ensure that .sh scripts use LF as line separator, even if they are checked out
# to Windows(NTFS) file-system, by a user of Docker for Windows.
# to Windows(NTFS) file-system, by a user of Docker for Window.
# These .sh scripts will be run from the Container after `docker compose up -d`.
# If they appear to be CRLF style, Dash from the Container will fail to execute
# them.

249
.github/CODEOWNERS vendored
View File

@@ -1,249 +0,0 @@
# CODEOWNERS
# This file defines code ownership for the Dify project.
# Each line is a file pattern followed by one or more owners.
# Owners can be @username, @org/team-name, or email addresses.
# For more information, see: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
* @crazywoola @laipz8200 @Yeuoly
# CODEOWNERS file
/.github/CODEOWNERS @laipz8200 @crazywoola
# Docs
/docs/ @crazywoola
# Backend (default owner, more specific rules below will override)
/api/ @QuantumGhost
# Backend - MCP
/api/core/mcp/ @Nov1c444
/api/core/entities/mcp_provider.py @Nov1c444
/api/services/tools/mcp_tools_manage_service.py @Nov1c444
/api/controllers/mcp/ @Nov1c444
/api/controllers/console/app/mcp_server.py @Nov1c444
/api/tests/**/*mcp* @Nov1c444
# Backend - Workflow - Engine (Core graph execution engine)
/api/core/workflow/graph_engine/ @laipz8200 @QuantumGhost
/api/core/workflow/runtime/ @laipz8200 @QuantumGhost
/api/core/workflow/graph/ @laipz8200 @QuantumGhost
/api/core/workflow/graph_events/ @laipz8200 @QuantumGhost
/api/core/workflow/node_events/ @laipz8200 @QuantumGhost
/api/core/model_runtime/ @laipz8200 @QuantumGhost
# Backend - Workflow - Nodes (Agent, Iteration, Loop, LLM)
/api/core/workflow/nodes/agent/ @Nov1c444
/api/core/workflow/nodes/iteration/ @Nov1c444
/api/core/workflow/nodes/loop/ @Nov1c444
/api/core/workflow/nodes/llm/ @Nov1c444
# Backend - RAG (Retrieval Augmented Generation)
/api/core/rag/ @JohnJyong
/api/services/rag_pipeline/ @JohnJyong
/api/services/dataset_service.py @JohnJyong
/api/services/knowledge_service.py @JohnJyong
/api/services/external_knowledge_service.py @JohnJyong
/api/services/hit_testing_service.py @JohnJyong
/api/services/metadata_service.py @JohnJyong
/api/services/vector_service.py @JohnJyong
/api/services/entities/knowledge_entities/ @JohnJyong
/api/services/entities/external_knowledge_entities/ @JohnJyong
/api/controllers/console/datasets/ @JohnJyong
/api/controllers/service_api/dataset/ @JohnJyong
/api/models/dataset.py @JohnJyong
/api/tasks/rag_pipeline/ @JohnJyong
/api/tasks/add_document_to_index_task.py @JohnJyong
/api/tasks/batch_clean_document_task.py @JohnJyong
/api/tasks/clean_document_task.py @JohnJyong
/api/tasks/clean_notion_document_task.py @JohnJyong
/api/tasks/document_indexing_task.py @JohnJyong
/api/tasks/document_indexing_sync_task.py @JohnJyong
/api/tasks/document_indexing_update_task.py @JohnJyong
/api/tasks/duplicate_document_indexing_task.py @JohnJyong
/api/tasks/recover_document_indexing_task.py @JohnJyong
/api/tasks/remove_document_from_index_task.py @JohnJyong
/api/tasks/retry_document_indexing_task.py @JohnJyong
/api/tasks/sync_website_document_indexing_task.py @JohnJyong
/api/tasks/batch_create_segment_to_index_task.py @JohnJyong
/api/tasks/create_segment_to_index_task.py @JohnJyong
/api/tasks/delete_segment_from_index_task.py @JohnJyong
/api/tasks/disable_segment_from_index_task.py @JohnJyong
/api/tasks/disable_segments_from_index_task.py @JohnJyong
/api/tasks/enable_segment_to_index_task.py @JohnJyong
/api/tasks/enable_segments_to_index_task.py @JohnJyong
/api/tasks/clean_dataset_task.py @JohnJyong
/api/tasks/deal_dataset_index_update_task.py @JohnJyong
/api/tasks/deal_dataset_vector_index_task.py @JohnJyong
# Backend - Plugins
/api/core/plugin/ @Mairuis @Yeuoly @Stream29
/api/services/plugin/ @Mairuis @Yeuoly @Stream29
/api/controllers/console/workspace/plugin.py @Mairuis @Yeuoly @Stream29
/api/controllers/inner_api/plugin/ @Mairuis @Yeuoly @Stream29
/api/tasks/process_tenant_plugin_autoupgrade_check_task.py @Mairuis @Yeuoly @Stream29
# Backend - Trigger/Schedule/Webhook
/api/controllers/trigger/ @Mairuis @Yeuoly
/api/controllers/console/app/workflow_trigger.py @Mairuis @Yeuoly
/api/controllers/console/workspace/trigger_providers.py @Mairuis @Yeuoly
/api/core/trigger/ @Mairuis @Yeuoly
/api/core/app/layers/trigger_post_layer.py @Mairuis @Yeuoly
/api/services/trigger/ @Mairuis @Yeuoly
/api/models/trigger.py @Mairuis @Yeuoly
/api/fields/workflow_trigger_fields.py @Mairuis @Yeuoly
/api/repositories/workflow_trigger_log_repository.py @Mairuis @Yeuoly
/api/repositories/sqlalchemy_workflow_trigger_log_repository.py @Mairuis @Yeuoly
/api/libs/schedule_utils.py @Mairuis @Yeuoly
/api/services/workflow/scheduler.py @Mairuis @Yeuoly
/api/schedule/trigger_provider_refresh_task.py @Mairuis @Yeuoly
/api/schedule/workflow_schedule_task.py @Mairuis @Yeuoly
/api/tasks/trigger_processing_tasks.py @Mairuis @Yeuoly
/api/tasks/trigger_subscription_refresh_tasks.py @Mairuis @Yeuoly
/api/tasks/workflow_schedule_tasks.py @Mairuis @Yeuoly
/api/tasks/workflow_cfs_scheduler/ @Mairuis @Yeuoly
/api/events/event_handlers/sync_plugin_trigger_when_app_created.py @Mairuis @Yeuoly
/api/events/event_handlers/update_app_triggers_when_app_published_workflow_updated.py @Mairuis @Yeuoly
/api/events/event_handlers/sync_workflow_schedule_when_app_published.py @Mairuis @Yeuoly
/api/events/event_handlers/sync_webhook_when_app_created.py @Mairuis @Yeuoly
# Backend - Async Workflow
/api/services/async_workflow_service.py @Mairuis @Yeuoly
/api/tasks/async_workflow_tasks.py @Mairuis @Yeuoly
# Backend - Billing
/api/services/billing_service.py @hj24 @zyssyz123
/api/controllers/console/billing/ @hj24 @zyssyz123
# Backend - Enterprise
/api/configs/enterprise/ @GarfieldDai @GareArc
/api/services/enterprise/ @GarfieldDai @GareArc
/api/services/feature_service.py @GarfieldDai @GareArc
/api/controllers/console/feature.py @GarfieldDai @GareArc
/api/controllers/web/feature.py @GarfieldDai @GareArc
# Backend - Database Migrations
/api/migrations/ @snakevash @laipz8200 @MRZHUH
# Backend - Vector DB Middleware
/api/configs/middleware/vdb/* @JohnJyong
# Frontend
/web/ @iamjoel
# Frontend - Web Tests
/.github/workflows/web-tests.yml @iamjoel
# Frontend - App - Orchestration
/web/app/components/workflow/ @iamjoel @zxhlyh
/web/app/components/workflow-app/ @iamjoel @zxhlyh
/web/app/components/app/configuration/ @iamjoel @zxhlyh
/web/app/components/app/app-publisher/ @iamjoel @zxhlyh
# Frontend - WebApp - Chat
/web/app/components/base/chat/ @iamjoel @zxhlyh
# Frontend - WebApp - Completion
/web/app/components/share/text-generation/ @iamjoel @zxhlyh
# Frontend - App - List and Creation
/web/app/components/apps/ @JzoNgKVO @iamjoel
/web/app/components/app/create-app-dialog/ @JzoNgKVO @iamjoel
/web/app/components/app/create-app-modal/ @JzoNgKVO @iamjoel
/web/app/components/app/create-from-dsl-modal/ @JzoNgKVO @iamjoel
# Frontend - App - API Documentation
/web/app/components/develop/ @JzoNgKVO @iamjoel
# Frontend - App - Logs and Annotations
/web/app/components/app/workflow-log/ @JzoNgKVO @iamjoel
/web/app/components/app/log/ @JzoNgKVO @iamjoel
/web/app/components/app/log-annotation/ @JzoNgKVO @iamjoel
/web/app/components/app/annotation/ @JzoNgKVO @iamjoel
# Frontend - App - Monitoring
/web/app/(commonLayout)/app/(appDetailLayout)/\[appId\]/overview/ @JzoNgKVO @iamjoel
/web/app/components/app/overview/ @JzoNgKVO @iamjoel
# Frontend - App - Settings
/web/app/components/app-sidebar/ @JzoNgKVO @iamjoel
# Frontend - RAG - Hit Testing
/web/app/components/datasets/hit-testing/ @JzoNgKVO @iamjoel
# Frontend - RAG - List and Creation
/web/app/components/datasets/list/ @iamjoel @WTW0313
/web/app/components/datasets/create/ @iamjoel @WTW0313
/web/app/components/datasets/create-from-pipeline/ @iamjoel @WTW0313
/web/app/components/datasets/external-knowledge-base/ @iamjoel @WTW0313
# Frontend - RAG - Orchestration (general rule first, specific rules below override)
/web/app/components/rag-pipeline/ @iamjoel @WTW0313
/web/app/components/rag-pipeline/components/rag-pipeline-main.tsx @iamjoel @zxhlyh
/web/app/components/rag-pipeline/store/ @iamjoel @zxhlyh
# Frontend - RAG - Documents List
/web/app/components/datasets/documents/list.tsx @iamjoel @WTW0313
/web/app/components/datasets/documents/create-from-pipeline/ @iamjoel @WTW0313
# Frontend - RAG - Segments List
/web/app/components/datasets/documents/detail/ @iamjoel @WTW0313
# Frontend - RAG - Settings
/web/app/components/datasets/settings/ @iamjoel @WTW0313
# Frontend - Ecosystem - Plugins
/web/app/components/plugins/ @iamjoel @zhsama
# Frontend - Ecosystem - Tools
/web/app/components/tools/ @iamjoel @Yessenia-d
# Frontend - Ecosystem - MarketPlace
/web/app/components/plugins/marketplace/ @iamjoel @Yessenia-d
# Frontend - Login and Registration
/web/app/signin/ @douxc @iamjoel
/web/app/signup/ @douxc @iamjoel
/web/app/reset-password/ @douxc @iamjoel
/web/app/install/ @douxc @iamjoel
/web/app/init/ @douxc @iamjoel
/web/app/forgot-password/ @douxc @iamjoel
/web/app/account/ @douxc @iamjoel
# Frontend - Service Authentication
/web/service/base.ts @douxc @iamjoel
# Frontend - WebApp Authentication and Access Control
/web/app/(shareLayout)/components/ @douxc @iamjoel
/web/app/(shareLayout)/webapp-signin/ @douxc @iamjoel
/web/app/(shareLayout)/webapp-reset-password/ @douxc @iamjoel
/web/app/components/app/app-access-control/ @douxc @iamjoel
# Frontend - Explore Page
/web/app/components/explore/ @CodingOnStar @iamjoel
# Frontend - Personal Settings
/web/app/components/header/account-setting/ @CodingOnStar @iamjoel
/web/app/components/header/account-dropdown/ @CodingOnStar @iamjoel
# Frontend - Analytics
/web/app/components/base/ga/ @CodingOnStar @iamjoel
# Frontend - Base Components
/web/app/components/base/ @iamjoel @zxhlyh
# Frontend - Utils and Hooks
/web/utils/classnames.ts @iamjoel @zxhlyh
/web/utils/time.ts @iamjoel @zxhlyh
/web/utils/format.ts @iamjoel @zxhlyh
/web/utils/clipboard.ts @iamjoel @zxhlyh
/web/hooks/use-document-title.ts @iamjoel @zxhlyh
# Frontend - Billing and Education
/web/app/components/billing/ @iamjoel @zxhlyh
/web/app/education-apply/ @iamjoel @zxhlyh
# Frontend - Workspace
/web/app/components/header/account-dropdown/workplace-selector/ @iamjoel @zxhlyh
# Docker
/docker/* @laipz8200

View File

@@ -17,25 +17,27 @@ diverse, inclusive, and healthy community.
Examples of behavior that contributes to a positive environment for our
community include:
- Demonstrating empathy and kindness toward other people
- Being respectful of differing opinions, viewpoints, and experiences
- Giving and gracefully accepting constructive feedback
- Accepting responsibility and apologizing to those affected by our mistakes,
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
- Focusing on what is best not just for us as individuals, but for the
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
- The use of sexualized language or imagery, and sexual attention or
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
- Trolling, insulting or derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or email
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
- Other conduct which could reasonably be considered inappropriate in a
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Language Policy
To facilitate clear and effective communication, all discussions, comments, documentation, and pull requests in this project should be conducted in English. This ensures that all contributors can participate and collaborate effectively.

View File

@@ -9,7 +9,7 @@ body:
required: true
- label: I confirm that I am using English to submit this report (我已阅读并同意 [Language Policy](https://github.com/langgenius/dify/issues/1542)).
required: true
- label: "[FOR CHINESE USERS] 请务必使用英文提交 Issue否则会被关闭。谢谢:)"
- label: "[FOR CHINESE USERS] 请务必使用英文提交 Issue否则会被关闭。谢谢:"
required: true
- label: "Please do not modify this template :) and fill in all the required fields."
required: true

View File

@@ -9,7 +9,7 @@ body:
required: true
- label: I confirm that I am using English to submit this report (我已阅读并同意 [Language Policy](https://github.com/langgenius/dify/issues/1542)).
required: true
- label: "[FOR CHINESE USERS] 请务必使用英文提交 Issue否则会被关闭。谢谢:)"
- label: "[FOR CHINESE USERS] 请务必使用英文提交 Issue否则会被关闭。谢谢:"
required: true
- label: "Please do not modify this template :) and fill in all the required fields."
required: true

View File

@@ -9,7 +9,7 @@ body:
required: true
- label: I confirm that I am using English to submit this report (我已阅读并同意 [Language Policy](https://github.com/langgenius/dify/issues/1542)).
required: true
- label: "[FOR CHINESE USERS] 请务必使用英文提交 Issue否则会被关闭。谢谢:)"
- label: "[FOR CHINESE USERS] 请务必使用英文提交 Issue否则会被关闭。谢谢:"
required: true
- label: "Please do not modify this template :) and fill in all the required fields."
required: true

View File

@@ -8,15 +8,13 @@ body:
label: Self Checks
description: "To make sure we get to you in time, please check the following :)"
options:
- label: I have read the [Contributing Guide](https://github.com/langgenius/dify/blob/main/CONTRIBUTING.md) and [Language Policy](https://github.com/langgenius/dify/issues/1542).
required: true
- label: This is only for bug report, if you would like to ask a question, please head to [Discussions](https://github.com/langgenius/dify/discussions/categories/general).
required: true
- label: I have searched for existing issues [search for existing issues](https://github.com/langgenius/dify/issues), including closed ones.
required: true
- label: I confirm that I am using English to submit this report, otherwise it will be closed.
- label: I confirm that I am using English to submit this report (我已阅读并同意 [Language Policy](https://github.com/langgenius/dify/issues/1542)).
required: true
- label: 【中文用户 & Non English User】请使用英提交,否则会被关闭
- label: "[FOR CHINESE USERS] 请务必使用英提交 Issue,否则会被关闭。谢谢!:"
required: true
- label: "Please do not modify this template :) and fill in all the required fields."
required: true
@@ -44,22 +42,20 @@ body:
attributes:
label: Steps to reproduce
description: We highly suggest including screenshots and a bug report log. Please use the right markdown syntax for code blocks.
placeholder: Having detailed steps helps us reproduce the bug. If you have logs, please use fenced code blocks (triple backticks ```) to format them.
placeholder: Having detailed steps helps us reproduce the bug.
validations:
required: true
- type: textarea
attributes:
label: ✔️ Expected Behavior
description: Describe what you expected to happen.
placeholder: What were you expecting? Please do not copy and paste the steps to reproduce here.
placeholder: What were you expecting?
validations:
required: true
required: false
- type: textarea
attributes:
label: ❌ Actual Behavior
description: Describe what actually happened.
placeholder: What happened instead? Please do not copy and paste the steps to reproduce here.
placeholder: What happened instead?
validations:
required: false

View File

@@ -1,14 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: "\U0001F510 Security Vulnerabilities"
url: "https://github.com/langgenius/dify/security/advisories/new"
about: Report security vulnerabilities through GitHub Security Advisories to ensure responsible disclosure. 💡 Please do not report security vulnerabilities in public issues.
- name: "\U0001F4A1 Model Providers & Plugins"
url: "https://github.com/langgenius/dify-official-plugins/issues/new/choose"
about: Report issues with official plugins or model providers, you will need to provide the plugin version and other relevant details.
- name: "\U0001F4AC Documentation Issues"
url: "https://github.com/langgenius/dify-docs/issues/new"
about: Report issues with the documentation, such as typos, outdated information, or missing content. Please provide the specific section and details of the issue.
- name: "\U0001F4E7 Discussions"
url: https://github.com/langgenius/dify/discussions/categories/general
about: General discussions and seek help from the community
about: General discussions and request help from the community

View File

@@ -0,0 +1,24 @@
name: "📚 Documentation Issue"
description: Report issues in our documentation
labels:
- documentation
body:
- type: checkboxes
attributes:
label: Self Checks
description: "To make sure we get to you in time, please check the following :)"
options:
- label: I have searched for existing issues [search for existing issues](https://github.com/langgenius/dify/issues), including closed ones.
required: true
- label: I confirm that I am using English to submit report (我已阅读并同意 [Language Policy](https://github.com/langgenius/dify/issues/1542)).
required: true
- label: "[FOR CHINESE USERS] 请务必使用英文提交 Issue否则会被关闭。谢谢:"
required: true
- label: "Please do not modify this template :) and fill in all the required fields."
required: true
- type: textarea
attributes:
label: Provide a description of requested docs changes
placeholder: Briefly describe which document needs to be corrected and why.
validations:
required: true

View File

@@ -8,11 +8,11 @@ body:
label: Self Checks
description: "To make sure we get to you in time, please check the following :)"
options:
- label: I have read the [Contributing Guide](https://github.com/langgenius/dify/blob/main/CONTRIBUTING.md) and [Language Policy](https://github.com/langgenius/dify/issues/1542).
required: true
- label: I have searched for existing issues [search for existing issues](https://github.com/langgenius/dify/issues), including closed ones.
required: true
- label: I confirm that I am using English to submit this report, otherwise it will be closed.
- label: I confirm that I am using English to submit this report (我已阅读并同意 [Language Policy](https://github.com/langgenius/dify/issues/1542)).
required: true
- label: "[FOR CHINESE USERS] 请务必使用英文提交 Issue否则会被关闭。谢谢:"
required: true
- label: "Please do not modify this template :) and fill in all the required fields."
required: true

View File

@@ -1,42 +0,0 @@
name: "✨ Refactor or Chore"
description: Refactor existing code or perform maintenance chores to improve readability and reliability.
title: "[Refactor/Chore] "
body:
- type: checkboxes
attributes:
label: Self Checks
description: "To make sure we get to you in time, please check the following :)"
options:
- label: I have read the [Contributing Guide](https://github.com/langgenius/dify/blob/main/CONTRIBUTING.md) and [Language Policy](https://github.com/langgenius/dify/issues/1542).
required: true
- label: This is only for refactors or chores; if you would like to ask a question, please head to [Discussions](https://github.com/langgenius/dify/discussions/categories/general).
required: true
- label: I have searched for existing issues [search for existing issues](https://github.com/langgenius/dify/issues), including closed ones.
required: true
- label: I confirm that I am using English to submit this report, otherwise it will be closed.
required: true
- label: 【中文用户 & Non English User】请使用英语提交否则会被关闭
required: true
- label: "Please do not modify this template :) and fill in all the required fields."
required: true
- type: textarea
id: description
attributes:
label: Description
placeholder: "Describe the refactor or chore you are proposing."
validations:
required: true
- type: textarea
id: motivation
attributes:
label: Motivation
placeholder: "Explain why this refactor or chore is necessary."
validations:
required: false
- type: textarea
id: additional-context
attributes:
label: Additional Context
placeholder: "Add any other context or screenshots about the request here."
validations:
required: false

View File

@@ -0,0 +1,55 @@
name: "🌐 Localization/Translation issue"
description: Report incorrect translations. [please use English :]
labels:
- translation
body:
- type: checkboxes
attributes:
label: Self Checks
description: "To make sure we get to you in time, please check the following :)"
options:
- label: I have searched for existing issues [search for existing issues](https://github.com/langgenius/dify/issues), including closed ones.
required: true
- label: I confirm that I am using English to submit this report (我已阅读并同意 [Language Policy](https://github.com/langgenius/dify/issues/1542)).
required: true
- label: "[FOR CHINESE USERS] 请务必使用英文提交 Issue否则会被关闭。谢谢:"
required: true
- label: "Please do not modify this template :) and fill in all the required fields."
required: true
- type: input
attributes:
label: Dify version
description: Hover over system tray icon or look at Settings
validations:
required: true
- type: input
attributes:
label: Utility with translation issue
placeholder: Some area
description: Please input here the utility with the translation issue
validations:
required: true
- type: input
attributes:
label: 🌐 Language affected
placeholder: "German"
validations:
required: true
- type: textarea
attributes:
label: ❌ Actual phrase(s)
placeholder: What is there? Please include a screenshot as that is extremely helpful.
validations:
required: true
- type: textarea
attributes:
label: ✔️ Expected phrase(s)
placeholder: What was expected?
validations:
required: true
- type: textarea
attributes:
label: Why is the current translation wrong
placeholder: Why do you feel this is incorrect?
validations:
required: true

36
.github/actions/setup-poetry/action.yml vendored Normal file
View File

@@ -0,0 +1,36 @@
name: Setup Poetry and Python
inputs:
python-version:
description: Python version to use and the Poetry installed with
required: true
default: '3.11'
poetry-version:
description: Poetry version to set up
required: true
default: '2.0.1'
poetry-lockfile:
description: Path to the Poetry lockfile to restore cache from
required: true
default: ''
runs:
using: composite
steps:
- name: Set up Python ${{ inputs.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ inputs.python-version }}
cache: pip
- name: Install Poetry
shell: bash
run: pip install poetry==${{ inputs.poetry-version }}
- name: Restore Poetry cache
if: ${{ inputs.poetry-lockfile != '' }}
uses: actions/setup-python@v5
with:
python-version: ${{ inputs.python-version }}
cache: poetry
cache-dependency-path: ${{ inputs.poetry-lockfile }}

View File

@@ -1,12 +0,0 @@
version: 2
updates:
- package-ecosystem: "npm"
directory: "/web"
schedule:
interval: "weekly"
open-pull-requests-limit: 2
- package-ecosystem: "uv"
directory: "/api"
schedule:
interval: "weekly"
open-pull-requests-limit: 2

View File

@@ -1,22 +0,0 @@
{
"Verbose": false,
"Debug": false,
"IgnoreDefaults": false,
"SpacesAfterTabs": false,
"NoColor": false,
"Exclude": [
"^web/public/vs/",
"^web/public/pdf.worker.min.mjs$",
"web/app/components/base/icons/src/vender/"
],
"AllowedContentTypes": [],
"PassedFiles": [],
"Disable": {
"EndOfLine": false,
"Indentation": false,
"IndentSize": true,
"InsertFinalNewline": false,
"TrimTrailingWhitespace": false,
"MaxLineLength": false
}
}

Some files were not shown because too many files have changed in this diff Show More