Fix: Added styles for empty states on the page. #10703 (#11588)

### What problem does this PR solve?

Fix: Added styles for empty states on the page.
### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)
This commit is contained in:
chanx
2025-11-28 14:03:20 +08:00
committed by GitHub
parent dbdda0fbab
commit 7d05d4ced7
29 changed files with 866 additions and 419 deletions

View File

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -0,0 +1,35 @@
<svg width="84" height="104" viewBox="0 0 84 104" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="search nothing">
<path id="Vector" d="M60.6654 71.3333V39.3333C60.6654 37.9188 60.1035 36.5623 59.1033 35.5621C58.1031 34.5619 56.7465 34 55.332 34H20.6654M20.6654 34C22.0799 34 23.4364 34.5619 24.4366 35.5621C25.4368 36.5623 25.9987 37.9188 25.9987 39.3333V76.6667C25.9987 78.0812 26.5606 79.4377 27.5608 80.4379C28.561 81.4381 29.9175 82 31.332 82M20.6654 34C19.2509 34 17.8943 34.5619 16.8941 35.5621C15.8939 36.5623 15.332 37.9188 15.332 39.3333V44.6667C15.332 45.3739 15.613 46.0522 16.1131 46.5523C16.6132 47.0524 17.2915 47.3333 17.9987 47.3333H25.9987M31.332 82H63.332C64.7465 82 66.1031 81.4381 67.1033 80.4379C68.1035 79.4377 68.6654 78.0812 68.6654 76.6667V74C68.6654 73.2928 68.3844 72.6145 67.8843 72.1144C67.3842 71.6143 66.7059 71.3333 65.9987 71.3333H39.332C38.6248 71.3333 37.9465 71.6143 37.4464 72.1144C36.9463 72.6145 36.6654 73.2928 36.6654 74V76.6667C36.6654 78.0812 36.1035 79.4377 35.1033 80.4379C34.1031 81.4381 32.7465 82 31.332 82Z" stroke="url(#paint0_linear_493_43922)" stroke-opacity="0.2" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
<g id="Vector_2">
<path d="M60.6654 65.3333V33.3333C60.6654 31.9188 60.1035 30.5623 59.1033 29.5621C58.1031 28.5619 56.7465 28 55.332 28H20.6654" fill="white"/>
<path d="M31.332 76H63.332C64.7465 76 66.1031 75.4381 67.1033 74.4379C68.1035 73.4377 68.6654 72.0812 68.6654 70.6667V68C68.6654 67.2928 68.3844 66.6145 67.8843 66.1144C67.3842 65.6143 66.7059 65.3333 65.9987 65.3333H39.332C38.6248 65.3333 37.9465 65.6143 37.4464 66.1144C36.9463 66.6145 36.6654 67.2928 36.6654 68V70.6667C36.6654 72.0812 36.1035 73.4377 35.1033 74.4379C34.1031 75.4381 32.7465 76 31.332 76C29.9175 76 28.561 75.4381 27.5608 74.4379C26.5606 73.4377 25.9987 72.0812 25.9987 70.6667V33.3333C25.9987 31.9188 25.4368 30.5623 24.4366 29.5621C23.4364 28.5619 22.0799 28 20.6654 28C19.2509 28 17.8943 28.5619 16.8941 29.5621C15.8939 30.5623 15.332 31.9188 15.332 33.3333V38.6667C15.332 39.3739 15.613 40.0522 16.1131 40.5523C16.6132 41.0524 17.2915 41.3333 17.9987 41.3333H25.9987" fill="white"/>
<path d="M60.6654 65.3333V33.3333C60.6654 31.9188 60.1035 30.5623 59.1033 29.5621C58.1031 28.5619 56.7465 28 55.332 28H20.6654M20.6654 28C22.0799 28 23.4364 28.5619 24.4366 29.5621C25.4368 30.5623 25.9987 31.9188 25.9987 33.3333V70.6667C25.9987 72.0812 26.5606 73.4377 27.5608 74.4379C28.561 75.4381 29.9175 76 31.332 76M20.6654 28C19.2509 28 17.8943 28.5619 16.8941 29.5621C15.8939 30.5623 15.332 31.9188 15.332 33.3333V38.6667C15.332 39.3739 15.613 40.0522 16.1131 40.5523C16.6132 41.0524 17.2915 41.3333 17.9987 41.3333H25.9987M31.332 76H63.332C64.7465 76 66.1031 75.4381 67.1033 74.4379C68.1035 73.4377 68.6654 72.0812 68.6654 70.6667V68C68.6654 67.2928 68.3844 66.6145 67.8843 66.1144C67.3842 65.6143 66.7059 65.3333 65.9987 65.3333H39.332C38.6248 65.3333 37.9465 65.6143 37.4464 66.1144C36.9463 66.6145 36.6654 67.2928 36.6654 68V70.6667C36.6654 72.0812 36.1035 73.4377 35.1033 74.4379C34.1031 75.4381 32.7465 76 31.332 76Z" stroke="url(#paint1_linear_493_43922)" stroke-opacity="0.6" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<path id="Vector_3" d="M61.3333 59.3333V27.3333C61.3333 25.9188 60.7714 24.5623 59.7712 23.5621C58.771 22.5619 57.4145 22 56 22H21.3333M21.3333 22C22.7478 22 24.1044 22.5619 25.1046 23.5621C26.1048 24.5623 26.6667 25.9188 26.6667 27.3333V64.6667C26.6667 66.0812 27.2286 67.4377 28.2288 68.4379C29.229 69.4381 30.5855 70 32 70M21.3333 22C19.9188 22 18.5623 22.5619 17.5621 23.5621C16.5619 24.5623 16 25.9188 16 27.3333V32.6667C16 33.3739 16.281 34.0522 16.781 34.5523C17.2811 35.0524 17.9594 35.3333 18.6667 35.3333H26.6667M32 70H64C65.4145 70 66.771 69.4381 67.7712 68.4379C68.7714 67.4377 69.3333 66.0812 69.3333 64.6667V62C69.3333 61.2928 69.0524 60.6145 68.5523 60.1144C68.0522 59.6143 67.3739 59.3333 66.6667 59.3333H40C39.2928 59.3333 38.6145 59.6143 38.1144 60.1144C37.6143 60.6145 37.3333 61.2928 37.3333 62V64.6667C37.3333 66.0812 36.7714 67.4377 35.7712 68.4379C34.771 69.4381 33.4145 70 32 70Z" stroke="url(#paint2_linear_493_43922)" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector_4" d="M61.3333 59.3333V27.3333C61.3333 25.9188 60.7714 24.5623 59.7712 23.5621C58.771 22.5619 57.4145 22 56 22H21.3333M21.3333 22C22.7478 22 24.1044 22.5619 25.1046 23.5621C26.1048 24.5623 26.6667 25.9188 26.6667 27.3333V64.6667C26.6667 66.0812 27.2286 67.4377 28.2288 68.4379C29.229 69.4381 30.5855 70 32 70M21.3333 22C19.9188 22 18.5623 22.5619 17.5621 23.5621C16.5619 24.5623 16 25.9188 16 27.3333V32.6667C16 33.3739 16.281 34.0522 16.781 34.5523C17.2811 35.0524 17.9594 35.3333 18.6667 35.3333H26.6667M32 70H64C65.4145 70 66.771 69.4381 67.7712 68.4379C68.7714 67.4377 69.3333 66.0812 69.3333 64.6667V62C69.3333 61.2928 69.0524 60.6145 68.5523 60.1144C68.0522 59.6143 67.3739 59.3333 66.6667 59.3333H40C39.2928 59.3333 38.6145 59.6143 38.1144 60.1144C37.6143 60.6145 37.3333 61.2928 37.3333 62V64.6667C37.3333 66.0812 36.7714 67.4377 35.7712 68.4379C34.771 69.4381 33.4145 70 32 70Z" stroke="url(#paint3_linear_493_43922)" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector_5" d="M56 52L51.1778 47.1778M53.7778 40.8889C53.7778 45.7981 49.7981 49.7778 44.8889 49.7778C39.9797 49.7778 36 45.7981 36 40.8889C36 35.9797 39.9797 32 44.8889 32C49.7981 32 53.7778 35.9797 53.7778 40.8889Z" stroke="url(#paint4_linear_493_43922)" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<linearGradient id="paint0_linear_493_43922" x1="41.9987" y1="34" x2="41.9987" y2="82" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#7B7B7C"/>
</linearGradient>
<linearGradient id="paint1_linear_493_43922" x1="41.9987" y1="28" x2="41.9987" y2="76" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#7B7B7C"/>
</linearGradient>
<linearGradient id="paint2_linear_493_43922" x1="42.6667" y1="22" x2="42.6667" y2="70" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#7B7B7C"/>
</linearGradient>
<linearGradient id="paint3_linear_493_43922" x1="42.6667" y1="22" x2="42.6667" y2="70" gradientUnits="userSpaceOnUse">
<stop stop-color="#161618"/>
<stop offset="1" stop-color="#7B7B7C"/>
</linearGradient>
<linearGradient id="paint4_linear_493_43922" x1="46" y1="32" x2="46" y2="52" gradientUnits="userSpaceOnUse">
<stop stop-color="#161618"/>
<stop offset="1" stop-color="#7B7B7C"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 6.5 KiB

View File

@ -0,0 +1,39 @@
<svg width="84" height="104" viewBox="0 0 84 104" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="search nothing">
<path id="Vector" d="M60.6654 71.3333V39.3333C60.6654 37.9188 60.1035 36.5623 59.1033 35.5621C58.1031 34.5619 56.7465 34 55.332 34H20.6654M20.6654 34C22.0799 34 23.4364 34.5619 24.4366 35.5621C25.4368 36.5623 25.9987 37.9188 25.9987 39.3333V76.6667C25.9987 78.0812 26.5606 79.4377 27.5608 80.4379C28.561 81.4381 29.9175 82 31.332 82M20.6654 34C19.2509 34 17.8943 34.5619 16.8941 35.5621C15.8939 36.5623 15.332 37.9188 15.332 39.3333V44.6667C15.332 45.3739 15.613 46.0522 16.1131 46.5523C16.6132 47.0524 17.2915 47.3333 17.9987 47.3333H25.9987M31.332 82H63.332C64.7465 82 66.1031 81.4381 67.1033 80.4379C68.1035 79.4377 68.6654 78.0812 68.6654 76.6667V74C68.6654 73.2928 68.3844 72.6145 67.8843 72.1144C67.3842 71.6143 66.7059 71.3333 65.9987 71.3333H39.332C38.6248 71.3333 37.9465 71.6143 37.4464 72.1144C36.9463 72.6145 36.6654 73.2928 36.6654 74V76.6667C36.6654 78.0812 36.1035 79.4377 35.1033 80.4379C34.1031 81.4381 32.7465 82 31.332 82Z" stroke="url(#paint0_linear_486_6812)" stroke-opacity="0.2" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
<g id="Vector_2">
<path d="M60.6654 65.3333V33.3333C60.6654 31.9188 60.1035 30.5623 59.1033 29.5621C58.1031 28.5619 56.7465 28 55.332 28H20.6654" fill="#161618"/>
<path d="M31.332 76H63.332C64.7465 76 66.1031 75.4381 67.1033 74.4379C68.1035 73.4377 68.6654 72.0812 68.6654 70.6667V68C68.6654 67.2928 68.3844 66.6145 67.8843 66.1144C67.3842 65.6143 66.7059 65.3333 65.9987 65.3333H39.332C38.6248 65.3333 37.9465 65.6143 37.4464 66.1144C36.9463 66.6145 36.6654 67.2928 36.6654 68V70.6667C36.6654 72.0812 36.1035 73.4377 35.1033 74.4379C34.1031 75.4381 32.7465 76 31.332 76C29.9175 76 28.561 75.4381 27.5608 74.4379C26.5606 73.4377 25.9987 72.0812 25.9987 70.6667V33.3333C25.9987 31.9188 25.4368 30.5623 24.4366 29.5621C23.4364 28.5619 22.0799 28 20.6654 28C19.2509 28 17.8943 28.5619 16.8941 29.5621C15.8939 30.5623 15.332 31.9188 15.332 33.3333V38.6667C15.332 39.3739 15.613 40.0522 16.1131 40.5523C16.6132 41.0524 17.2915 41.3333 17.9987 41.3333H25.9987" fill="#161618"/>
<path d="M60.6654 65.3333V33.3333C60.6654 31.9188 60.1035 30.5623 59.1033 29.5621C58.1031 28.5619 56.7465 28 55.332 28H20.6654M20.6654 28C22.0799 28 23.4364 28.5619 24.4366 29.5621C25.4368 30.5623 25.9987 31.9188 25.9987 33.3333V70.6667C25.9987 72.0812 26.5606 73.4377 27.5608 74.4379C28.561 75.4381 29.9175 76 31.332 76M20.6654 28C19.2509 28 17.8943 28.5619 16.8941 29.5621C15.8939 30.5623 15.332 31.9188 15.332 33.3333V38.6667C15.332 39.3739 15.613 40.0522 16.1131 40.5523C16.6132 41.0524 17.2915 41.3333 17.9987 41.3333H25.9987M31.332 76H63.332C64.7465 76 66.1031 75.4381 67.1033 74.4379C68.1035 73.4377 68.6654 72.0812 68.6654 70.6667V68C68.6654 67.2928 68.3844 66.6145 67.8843 66.1144C67.3842 65.6143 66.7059 65.3333 65.9987 65.3333H39.332C38.6248 65.3333 37.9465 65.6143 37.4464 66.1144C36.9463 66.6145 36.6654 67.2928 36.6654 68V70.6667C36.6654 72.0812 36.1035 73.4377 35.1033 74.4379C34.1031 75.4381 32.7465 76 31.332 76Z" stroke="url(#paint1_linear_486_6812)" stroke-opacity="0.6" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<path id="Vector_3" d="M61.3333 59.3333V27.3333C61.3333 25.9188 60.7714 24.5623 59.7712 23.5621C58.771 22.5619 57.4145 22 56 22H21.3333M21.3333 22C22.7478 22 24.1044 22.5619 25.1046 23.5621C26.1048 24.5623 26.6667 25.9188 26.6667 27.3333V64.6667C26.6667 66.0812 27.2286 67.4377 28.2288 68.4379C29.229 69.4381 30.5855 70 32 70M21.3333 22C19.9188 22 18.5623 22.5619 17.5621 23.5621C16.5619 24.5623 16 25.9188 16 27.3333V32.6667C16 33.3739 16.281 34.0522 16.781 34.5523C17.2811 35.0524 17.9594 35.3333 18.6667 35.3333H26.6667M32 70H64C65.4145 70 66.771 69.4381 67.7712 68.4379C68.7714 67.4377 69.3333 66.0812 69.3333 64.6667V62C69.3333 61.2928 69.0524 60.6145 68.5523 60.1144C68.0522 59.6143 67.3739 59.3333 66.6667 59.3333H40C39.2928 59.3333 38.6145 59.6143 38.1144 60.1144C37.6143 60.6145 37.3333 61.2928 37.3333 62V64.6667C37.3333 66.0812 36.7714 67.4377 35.7712 68.4379C34.771 69.4381 33.4145 70 32 70Z" stroke="url(#paint2_linear_486_6812)" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
<g id="Vector_4">
<path d="M61.3333 59.3333V27.3333C61.3333 25.9188 60.7714 24.5623 59.7712 23.5621C58.771 22.5619 57.4145 22 56 22H21.3333" fill="#161618"/>
<path d="M32 70H64C65.4145 70 66.771 69.4381 67.7712 68.4379C68.7714 67.4377 69.3333 66.0812 69.3333 64.6667V62C69.3333 61.2928 69.0524 60.6145 68.5523 60.1144C68.0522 59.6143 67.3739 59.3333 66.6667 59.3333H40C39.2928 59.3333 38.6145 59.6143 38.1144 60.1144C37.6143 60.6145 37.3333 61.2928 37.3333 62V64.6667C37.3333 66.0812 36.7714 67.4377 35.7712 68.4379C34.771 69.4381 33.4145 70 32 70C30.5855 70 29.229 69.4381 28.2288 68.4379C27.2286 67.4377 26.6667 66.0812 26.6667 64.6667V27.3333C26.6667 25.9188 26.1048 24.5623 25.1046 23.5621C24.1044 22.5619 22.7478 22 21.3333 22C19.9188 22 18.5623 22.5619 17.5621 23.5621C16.5619 24.5623 16 25.9188 16 27.3333V32.6667C16 33.3739 16.281 34.0522 16.781 34.5523C17.2811 35.0524 17.9594 35.3333 18.6667 35.3333H26.6667" fill="#161618"/>
<path d="M61.3333 59.3333V27.3333C61.3333 25.9188 60.7714 24.5623 59.7712 23.5621C58.771 22.5619 57.4145 22 56 22H21.3333M21.3333 22C22.7478 22 24.1044 22.5619 25.1046 23.5621C26.1048 24.5623 26.6667 25.9188 26.6667 27.3333V64.6667C26.6667 66.0812 27.2286 67.4377 28.2288 68.4379C29.229 69.4381 30.5855 70 32 70M21.3333 22C19.9188 22 18.5623 22.5619 17.5621 23.5621C16.5619 24.5623 16 25.9188 16 27.3333V32.6667C16 33.3739 16.281 34.0522 16.781 34.5523C17.2811 35.0524 17.9594 35.3333 18.6667 35.3333H26.6667M32 70H64C65.4145 70 66.771 69.4381 67.7712 68.4379C68.7714 67.4377 69.3333 66.0812 69.3333 64.6667V62C69.3333 61.2928 69.0524 60.6145 68.5523 60.1144C68.0522 59.6143 67.3739 59.3333 66.6667 59.3333H40C39.2928 59.3333 38.6145 59.6143 38.1144 60.1144C37.6143 60.6145 37.3333 61.2928 37.3333 62V64.6667C37.3333 66.0812 36.7714 67.4377 35.7712 68.4379C34.771 69.4381 33.4145 70 32 70Z" stroke="url(#paint3_linear_486_6812)" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<path id="Vector_5" d="M56 52L51.1778 47.1778M53.7778 40.8889C53.7778 45.7981 49.7981 49.7778 44.8889 49.7778C39.9797 49.7778 36 45.7981 36 40.8889C36 35.9797 39.9797 32 44.8889 32C49.7981 32 53.7778 35.9797 53.7778 40.8889Z" stroke="url(#paint4_linear_486_6812)" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<linearGradient id="paint0_linear_486_6812" x1="41.9987" y1="34" x2="41.9987" y2="82" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#7B7B7C"/>
</linearGradient>
<linearGradient id="paint1_linear_486_6812" x1="41.9987" y1="28" x2="41.9987" y2="76" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#7B7B7C"/>
</linearGradient>
<linearGradient id="paint2_linear_486_6812" x1="42.6667" y1="22" x2="42.6667" y2="70" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#7B7B7C"/>
</linearGradient>
<linearGradient id="paint3_linear_486_6812" x1="42.6667" y1="22" x2="42.6667" y2="70" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#7B7B7C"/>
</linearGradient>
<linearGradient id="paint4_linear_486_6812" x1="46" y1="32" x2="46" y2="52" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#7B7B7C"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 7.4 KiB

View File

@ -0,0 +1,33 @@
import { t } from 'i18next';
import { HomeIcon } from '../svg-icon';
export enum EmptyType {
Data = 'data',
SearchData = 'search-data',
}
export enum EmptyCardType {
Agent = 'agent',
Dataset = 'dataset',
Chat = 'chat',
Search = 'search',
}
export const EmptyCardData = {
[EmptyCardType.Agent]: {
icon: <HomeIcon name="agents" width={'24'} />,
title: t('empty.agentTitle'),
},
[EmptyCardType.Dataset]: {
icon: <HomeIcon name="datasets" width={'24'} />,
title: t('empty.datasetTitle'),
},
[EmptyCardType.Chat]: {
icon: <HomeIcon name="chats" width={'24'} />,
title: t('empty.chatTitle'),
},
[EmptyCardType.Search]: {
icon: <HomeIcon name="searches" width={'24'} />,
title: t('empty.searchTitle'),
},
};

View File

@ -2,79 +2,33 @@ import { cn } from '@/lib/utils';
import { t } from 'i18next'; import { t } from 'i18next';
import { useIsDarkTheme } from '../theme-provider'; import { useIsDarkTheme } from '../theme-provider';
import noDataIcon from './no data bri.svg'; import { Plus } from 'lucide-react';
import noDataIconDark from './no data.svg'; import { useMemo } from 'react';
import SvgIcon from '../svg-icon';
type EmptyProps = { import { EmptyCardData, EmptyCardType, EmptyType } from './constant';
className?: string; import { EmptyCardProps, EmptyProps } from './interface';
children?: React.ReactNode;
};
const EmptyIcon = () => {
const isDarkTheme = useIsDarkTheme();
const EmptyIcon = ({ name, width }: { name: string; width?: number }) => {
return ( return (
<img // <img
className="h-20" // className="h-20"
src={isDarkTheme ? noDataIconDark : noDataIcon} // src={isDarkTheme ? noDataIconDark : noDataIcon}
alt={t('common.noData')} // alt={t('common.noData')}
/> // />
); <SvgIcon name={name || 'empty/no-data-dark'} width={width || 42} />
return (
<svg
width="184"
height="152"
viewBox="0 0 184 152"
xmlns="http://www.w3.org/2000/svg"
>
<title>{t('common.noData')}</title>
<g fill="none" fillRule="evenodd">
<g transform="translate(24 31.67)">
<ellipse
fillOpacity=".8"
fill={isDarkTheme ? '#28282A' : '#F5F5F7'}
cx="67.797"
cy="106.89"
rx="67.797"
ry="12.668"
></ellipse>
<path
d="M122.034 69.674L98.109 40.229c-1.148-1.386-2.826-2.225-4.593-2.225h-51.44c-1.766 0-3.444.839-4.592 2.225L13.56 69.674v15.383h108.475V69.674z"
fill={isDarkTheme ? '#736960' : '#AEB8C2'}
></path>
<path
d="M101.537 86.214L80.63 61.102c-1.001-1.207-2.507-1.867-4.048-1.867H31.724c-1.54 0-3.047.66-4.048 1.867L6.769 86.214v13.792h94.768V86.214z"
fill="url(#linearGradient-1)"
transform="translate(13.56)"
></path>
<path
d="M33.83 0h67.933a4 4 0 0 1 4 4v93.344a4 4 0 0 1-4 4H33.83a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4z"
fill={isDarkTheme ? '#28282A' : '#F5F5F7'}
></path>
<path
d="M42.678 9.953h50.237a2 2 0 0 1 2 2V36.91a2 2 0 0 1-2 2H42.678a2 2 0 0 1-2-2V11.953a2 2 0 0 1 2-2zM42.94 49.767h49.713a2.262 2.262 0 1 1 0 4.524H42.94a2.262 2.262 0 0 1 0-4.524zM42.94 61.53h49.713a2.262 2.262 0 1 1 0 4.525H42.94a2.262 2.262 0 0 1 0-4.525zM121.813 105.032c-.775 3.071-3.497 5.36-6.735 5.36H20.515c-3.238 0-5.96-2.29-6.734-5.36a7.309 7.309 0 0 1-.222-1.79V69.675h26.318c2.907 0 5.25 2.448 5.25 5.42v.04c0 2.971 2.37 5.37 5.277 5.37h34.785c2.907 0 5.277-2.421 5.277-5.393V75.1c0-2.972 2.343-5.426 5.25-5.426h26.318v33.569c0 .617-.077 1.216-.221 1.789z"
fill={isDarkTheme ? '#45413A' : '#DCE0E6'}
></path>
</g>
<path
d="M149.121 33.292l-6.83 2.65a1 1 0 0 1-1.317-1.23l1.937-6.207c-2.589-2.944-4.109-6.534-4.109-10.408C138.802 8.102 148.92 0 161.402 0 173.881 0 184 8.102 184 18.097c0 9.995-10.118 18.097-22.599 18.097-4.528 0-8.744-1.066-12.28-2.902z"
fill={isDarkTheme ? '#45413A' : '#DCE0E6'}
></path>
<g
transform="translate(149.65 15.383)"
fill={isDarkTheme ? '#222' : '#FFF'}
>
<ellipse cx="20.654" cy="3.167" rx="2.849" ry="2.815"></ellipse>
<path d="M5.698 5.63H0L2.898.704zM9.259.704h4.985V5.63H9.259z"></path>
</g>
</g>
</svg>
); );
}; };
const Empty = (props: EmptyProps) => { const Empty = (props: EmptyProps) => {
const { className, children } = props; const { className, children, type, text, iconWidth } = props;
const isDarkTheme = useIsDarkTheme();
const name = useMemo(() => {
return isDarkTheme
? `empty/no-${type || EmptyType.Data}-dark`
: `empty/no-${type || EmptyType.Data}-bri`;
}, [isDarkTheme, type]);
return ( return (
<div <div
className={cn( className={cn(
@ -82,11 +36,12 @@ const Empty = (props: EmptyProps) => {
className, className,
)} )}
> >
<EmptyIcon /> <EmptyIcon name={name} width={iconWidth} />
{!children && ( {!children && (
<div className="empty-text text-text-secondary"> <div className="empty-text text-text-secondary text-sm">
{t('common.noData')} {text ||
(type === 'data' ? t('common.noData') : t('common.noResults'))}
</div> </div>
)} )}
{children} {children}
@ -95,3 +50,65 @@ const Empty = (props: EmptyProps) => {
}; };
export default Empty; export default Empty;
export const EmptyCard = (props: EmptyCardProps) => {
const { icon, className, children, title, description, style } = props;
return (
<div
className={cn(
'flex flex-col gap-3 items-start justify-start border border-dashed border-border-button rounded-md p-5 w-fit',
className,
)}
style={style}
>
{icon}
{title && <div className="text-text-primary text-base">{title}</div>}
{description && (
<div className="text-text-secondary text-sm">{description}</div>
)}
{children}
</div>
);
};
export const EmptyAppCard = (props: {
type: EmptyCardType;
onClick?: () => void;
showIcon?: boolean;
className?: string;
size?: 'small' | 'large';
}) => {
const { type, showIcon, className } = props;
let defaultClass = '';
let style = {};
switch (props.size) {
case 'small':
style = { width: '256px' };
defaultClass = 'mt-1';
break;
case 'large':
style = { width: '480px' };
defaultClass = 'mt-5';
break;
default:
defaultClass = '';
break;
}
return (
<div className=" cursor-pointer " onClick={props.onClick}>
<EmptyCard
icon={showIcon ? EmptyCardData[type].icon : undefined}
title={EmptyCardData[type].title}
className={className}
style={style}
// description={EmptyCardData[type].description}
>
<div
className={cn(defaultClass, 'flex items-center justify-start w-full')}
>
<Plus size={24} />
</div>
</EmptyCard>
</div>
);
};

View File

@ -0,0 +1,18 @@
import { EmptyType } from './constant';
export type EmptyProps = {
className?: string;
children?: React.ReactNode;
type?: EmptyType;
text?: string;
iconWidth?: number;
};
export type EmptyCardProps = {
icon?: React.ReactNode;
className?: string;
children?: React.ReactNode;
title?: string;
description?: string;
style?: React.CSSProperties;
};

View File

@ -58,7 +58,7 @@ export const useSelectLlmOptions = () => {
function buildLlmOptionsWithIcon(x: IThirdOAIModel) { function buildLlmOptionsWithIcon(x: IThirdOAIModel) {
return { return {
label: ( label: (
<div className="flex items-center justify-center gap-6"> <div className="flex items-center justify-center gap-2">
<LlmIcon <LlmIcon
name={getLLMIconName(x.fid, x.llm_name)} name={getLLMIconName(x.fid, x.llm_name)}
width={24} width={24}

View File

@ -14,9 +14,16 @@ export const useNavigatePage = () => {
const [searchParams] = useSearchParams(); const [searchParams] = useSearchParams();
const { id } = useParams(); const { id } = useParams();
const navigateToDatasetList = useCallback(() => { const navigateToDatasetList = useCallback(
({ isCreate = false }: { isCreate?: boolean }) => {
if (isCreate) {
navigate(Routes.Datasets + '?isCreate=true');
} else {
navigate(Routes.Datasets); navigate(Routes.Datasets);
}, [navigate]); }
},
[navigate],
);
const navigateToDataset = useCallback( const navigateToDataset = useCallback(
(id: string) => () => { (id: string) => () => {

View File

@ -54,7 +54,7 @@ export const useFetchTenantInfo = (
): ResponseGetType<ITenantInfo> => { ): ResponseGetType<ITenantInfo> => {
const { t } = useTranslation(); const { t } = useTranslation();
const { data, isFetching: loading } = useQuery({ const { data, isFetching: loading } = useQuery({
queryKey: ['tenantInfo'], queryKey: ['tenantInfo', showEmptyModelWarn],
initialData: {}, initialData: {},
gcTime: 0, gcTime: 0,
queryFn: async () => { queryFn: async () => {
@ -99,7 +99,6 @@ export const useSelectParserList = (): Array<{
label: string; label: string;
}> => { }> => {
const { data: tenantInfo } = useFetchTenantInfo(true); const { data: tenantInfo } = useFetchTenantInfo(true);
const parserList = useMemo(() => { const parserList = useMemo(() => {
const parserArray: Array<string> = tenantInfo?.parser_ids?.split(',') ?? []; const parserArray: Array<string> = tenantInfo?.parser_ids?.split(',') ?? [];
return parserArray.map((x) => { return parserArray.map((x) => {

View File

@ -3,7 +3,7 @@ export default {
common: { common: {
confirm: 'Confirm', confirm: 'Confirm',
back: 'Back', back: 'Back',
noResults: 'No results.', noResults: 'No results found',
selectPlaceholder: 'select value', selectPlaceholder: 'select value',
selectAll: 'Select all', selectAll: 'Select all',
delete: 'Delete', delete: 'Delete',
@ -51,7 +51,7 @@ export default {
remove: 'Remove', remove: 'Remove',
search: 'Search', search: 'Search',
noDataFound: 'No data found.', noDataFound: 'No data found.',
noData: 'No data', noData: 'No data available',
promptPlaceholder: `Please input or use / to quickly insert variables.`, promptPlaceholder: `Please input or use / to quickly insert variables.`,
mcp: { mcp: {
namePlaceholder: 'My MCP Server', namePlaceholder: 'My MCP Server',
@ -2026,6 +2026,7 @@ Important structured information may include: names, dates, locations, events, k
processingSuccessTip: 'Total successfully processed files', processingSuccessTip: 'Total successfully processed files',
processingFailedTip: 'Total failed processes', processingFailedTip: 'Total failed processes',
processing: 'Processing', processing: 'Processing',
noData: 'No log yet',
}, },
deleteModal: { deleteModal: {
@ -2039,6 +2040,15 @@ Important structured information may include: names, dates, locations, events, k
delMember: 'Delete member', delMember: 'Delete member',
}, },
empty: {
noMCP: 'No MCP servers available',
agentTitle: 'No agent app created yet',
datasetTitle: 'No dataset created yet',
chatTitle: 'No chat app created yet',
searchTitle: 'No search app created yet',
addNow: 'Add Now',
},
admin: { admin: {
loginTitle: 'Admin Console', loginTitle: 'Admin Console',
title: 'RAGFlow', title: 'RAGFlow',

View File

@ -3,7 +3,7 @@ export default {
common: { common: {
confirm: '确定', confirm: '确定',
back: '返回', back: '返回',
noResults: '结果', noResults: '未查到结果',
selectPlaceholder: '请选择', selectPlaceholder: '请选择',
selectAll: '全选', selectAll: '全选',
delete: '删除', delete: '删除',
@ -1878,6 +1878,27 @@ Tokenizer 会根据所选方式将内容存储为对应的数据结构。`,
downloadFailedTip: '下载失败总数', downloadFailedTip: '下载失败总数',
processingSuccessTip: '处理成功的文件总数', processingSuccessTip: '处理成功的文件总数',
processingFailedTip: '处理失败的文件总数', processingFailedTip: '处理失败的文件总数',
noData: '暂无日志',
},
deleteModal: {
delAgent: '删除智能体',
delDataset: '删除知识库',
delSearch: '删除搜索',
delFile: '删除文件',
delFiles: '删除文件',
delFilesContent: '已选择 {{count}} 个文件',
delChat: '删除聊天',
delMember: '删除成员',
},
empty: {
noMCP: '暂无 MCP 服务器可用',
agentTitle: '尚未创建智能体',
datasetTitle: '尚未创建数据集',
chatTitle: '尚未创建聊天应用',
searchTitle: '尚未创建搜索应用',
addNow: '立即添加',
}, },
deleteModal: { deleteModal: {

View File

@ -1,4 +1,6 @@
import { CardContainer } from '@/components/card-container'; import { CardContainer } from '@/components/card-container';
import { EmptyCardType } from '@/components/empty/constant';
import { EmptyAppCard } from '@/components/empty/empty';
import ListFilterBar from '@/components/list-filter-bar'; import ListFilterBar from '@/components/list-filter-bar';
import { RenameDialog } from '@/components/rename-dialog'; import { RenameDialog } from '@/components/rename-dialog';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
@ -14,7 +16,8 @@ import { useFetchAgentListByPage } from '@/hooks/use-agent-request';
import { t } from 'i18next'; import { t } from 'i18next';
import { pick } from 'lodash'; import { pick } from 'lodash';
import { Clipboard, ClipboardPlus, FileInput, Plus } from 'lucide-react'; import { Clipboard, ClipboardPlus, FileInput, Plus } from 'lucide-react';
import { useCallback } from 'react'; import { useCallback, useEffect } from 'react';
import { useSearchParams } from 'umi';
import { AgentCard } from './agent-card'; import { AgentCard } from './agent-card';
import { CreateAgentDialog } from './create-agent-dialog'; import { CreateAgentDialog } from './create-agent-dialog';
import { useCreateAgentOrPipeline } from './hooks/use-create-agent'; import { useCreateAgentOrPipeline } from './hooks/use-create-agent';
@ -67,9 +70,31 @@ export default function Agents() {
}, },
[setPagination], [setPagination],
); );
const [searchUrl, setSearchUrl] = useSearchParams();
const isCreate = searchUrl.get('isCreate') === 'true';
useEffect(() => {
if (isCreate) {
showCreatingModal();
searchUrl.delete('isCreate');
setSearchUrl(searchUrl);
}
}, [isCreate, showCreatingModal, searchUrl, setSearchUrl]);
return ( return (
<>
{(!data?.length || data?.length <= 0) && (
<div className="flex w-full items-center justify-center h-[calc(100vh-164px)]">
<EmptyAppCard
showIcon
size="large"
className="w-[480px] p-14"
type={EmptyCardType.Agent}
onClick={() => showCreatingModal()}
/>
</div>
)}
<section className="flex flex-col w-full flex-1"> <section className="flex flex-col w-full flex-1">
{!!data?.length && (
<>
<div className="px-8 pt-8 "> <div className="px-8 pt-8 ">
<ListFilterBar <ListFilterBar
title={t('flow.agents')} title={t('flow.agents')}
@ -133,6 +158,8 @@ export default function Agents() {
onChange={handlePageChange} onChange={handlePageChange}
></RAGFlowPagination> ></RAGFlowPagination>
</div> </div>
</>
)}
{agentRenameVisible && ( {agentRenameVisible && (
<RenameDialog <RenameDialog
hideModal={hideAgentRenameModal} hideModal={hideAgentRenameModal}
@ -157,5 +184,6 @@ export default function Agents() {
></UploadAgentDialog> ></UploadAgentDialog>
)} )}
</section> </section>
</>
); );
} }

View File

@ -1,3 +1,5 @@
import { EmptyType } from '@/components/empty/constant';
import Empty from '@/components/empty/empty';
import FileStatusBadge from '@/components/file-status-badge'; import FileStatusBadge from '@/components/file-status-badge';
import { FileIcon, IconFontFill } from '@/components/icon-font'; import { FileIcon, IconFontFill } from '@/components/icon-font';
import { RAGFlowAvatar } from '@/components/ragflow-avatar'; import { RAGFlowAvatar } from '@/components/ragflow-avatar';
@ -344,6 +346,7 @@ const FileLogsTable: FC<FileLogsTableProps> = ({
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]); const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
const [rowSelection, setRowSelection] = useState({}); const [rowSelection, setRowSelection] = useState({});
const { t } = useTranslate('knowledgeDetails'); const { t } = useTranslate('knowledgeDetails');
const { t: tDatasetOverview } = useTranslate('datasetOverview');
const [isModalVisible, setIsModalVisible] = useState(false); const [isModalVisible, setIsModalVisible] = useState(false);
const { navigateToDataflowResult } = useNavigatePage(); const { navigateToDataflowResult } = useNavigatePage();
const [logInfo, setLogInfo] = useState<IFileLogItem>(); const [logInfo, setLogInfo] = useState<IFileLogItem>();
@ -445,7 +448,10 @@ const FileLogsTable: FC<FileLogsTableProps> = ({
) : ( ) : (
<TableRow> <TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center"> <TableCell colSpan={columns.length} className="h-24 text-center">
No results. <Empty
type={EmptyType.Data}
text={tDatasetOverview('noData')}
/>
</TableCell> </TableCell>
</TableRow> </TableRow>
)} )}

View File

@ -14,6 +14,8 @@ import {
import * as React from 'react'; import * as React from 'react';
import { ChunkMethodDialog } from '@/components/chunk-method-dialog'; import { ChunkMethodDialog } from '@/components/chunk-method-dialog';
import { EmptyType } from '@/components/empty/constant';
import Empty from '@/components/empty/empty';
import { RenameDialog } from '@/components/rename-dialog'; import { RenameDialog } from '@/components/rename-dialog';
import { RAGFlowPagination } from '@/components/ui/ragflow-pagination'; import { RAGFlowPagination } from '@/components/ui/ragflow-pagination';
import { import {
@ -164,7 +166,7 @@ export function DatasetTable({
) : ( ) : (
<TableRow> <TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center"> <TableCell colSpan={columns.length} className="h-24 text-center">
No results. <Empty type={EmptyType.Data} />
</TableCell> </TableCell>
</TableRow> </TableRow>
)} )}

View File

@ -136,7 +136,7 @@ export function useDatasetTableColumns({
{ {
DataSourceInfo[ DataSourceInfo[
row.original.source_type as keyof typeof DataSourceInfo row.original.source_type as keyof typeof DataSourceInfo
].icon ]?.icon
} }
</div> </div>
)} )}

View File

@ -1,3 +1,4 @@
import { EmptyType } from '@/components/empty/constant';
import Empty from '@/components/empty/empty'; import Empty from '@/components/empty/empty';
import { FormContainer } from '@/components/form-container'; import { FormContainer } from '@/components/form-container';
import { FilterButton } from '@/components/list-filter-bar'; import { FilterButton } from '@/components/list-filter-bar';
@ -101,7 +102,7 @@ export function TestingResult({
{!data.chunks?.length && !loading && ( {!data.chunks?.length && !loading && (
<div className="flex justify-center items-center w-full h-[calc(100vh-241px)]"> <div className="flex justify-center items-center w-full h-[calc(100vh-241px)]">
<div> <div>
<Empty> <Empty type={EmptyType.SearchData}>
{data.isRuned && ( {data.isRuned && (
<div className="text-text-secondary"> <div className="text-text-secondary">
{t('knowledgeDetails.noTestResultsForRuned')} {t('knowledgeDetails.noTestResultsForRuned')}

View File

@ -1,13 +1,17 @@
import { CardContainer } from '@/components/card-container'; import { CardContainer } from '@/components/card-container';
import { EmptyCardType } from '@/components/empty/constant';
import { EmptyAppCard } from '@/components/empty/empty';
import ListFilterBar from '@/components/list-filter-bar'; import ListFilterBar from '@/components/list-filter-bar';
import { RenameDialog } from '@/components/rename-dialog'; import { RenameDialog } from '@/components/rename-dialog';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { RAGFlowPagination } from '@/components/ui/ragflow-pagination'; import { RAGFlowPagination } from '@/components/ui/ragflow-pagination';
import { useFetchNextKnowledgeListByPage } from '@/hooks/use-knowledge-request'; import { useFetchNextKnowledgeListByPage } from '@/hooks/use-knowledge-request';
import { useQueryClient } from '@tanstack/react-query';
import { pick } from 'lodash'; import { pick } from 'lodash';
import { Plus } from 'lucide-react'; import { Plus } from 'lucide-react';
import { useCallback } from 'react'; import { useCallback, useEffect } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useSearchParams } from 'umi';
import { DatasetCard } from './dataset-card'; import { DatasetCard } from './dataset-card';
import { DatasetCreatingDialog } from './dataset-creating-dialog'; import { DatasetCreatingDialog } from './dataset-creating-dialog';
import { useSaveKnowledge } from './hooks'; import { useSaveKnowledge } from './hooks';
@ -52,9 +56,33 @@ export default function Datasets() {
}, },
[setPagination], [setPagination],
); );
const [searchUrl, setSearchUrl] = useSearchParams();
const isCreate = searchUrl.get('isCreate') === 'true';
const queryClient = useQueryClient();
useEffect(() => {
if (isCreate) {
queryClient.invalidateQueries({ queryKey: ['tenantInfo'] });
showModal();
searchUrl.delete('isCreate');
setSearchUrl(searchUrl);
}
}, [isCreate, showModal, searchUrl, setSearchUrl]);
return ( return (
<>
<section className="py-4 flex-1 flex flex-col"> <section className="py-4 flex-1 flex flex-col">
{(!kbs?.length || kbs?.length <= 0) && (
<div className="flex w-full items-center justify-center h-[calc(100vh-164px)]">
<EmptyAppCard
showIcon
size="large"
className="w-[480px] p-14"
type={EmptyCardType.Dataset}
onClick={() => showModal()}
/>
</div>
)}
{!!kbs?.length && (
<>
<ListFilterBar <ListFilterBar
title={t('header.dataset')} title={t('header.dataset')}
searchString={searchString} searchString={searchString}
@ -90,6 +118,8 @@ export default function Datasets() {
onChange={handlePageChange} onChange={handlePageChange}
></RAGFlowPagination> ></RAGFlowPagination>
</div> </div>
</>
)}
{visible && ( {visible && (
<DatasetCreatingDialog <DatasetCreatingDialog
hideModal={hideModal} hideModal={hideModal}
@ -106,5 +136,6 @@ export default function Datasets() {
></RenameDialog> ></RenameDialog>
)} )}
</section> </section>
</>
); );
} }

View File

@ -3,11 +3,18 @@ import { MoreButton } from '@/components/more-button';
import { RenameDialog } from '@/components/rename-dialog'; import { RenameDialog } from '@/components/rename-dialog';
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks'; import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
import { useFetchAgentListByPage } from '@/hooks/use-agent-request'; import { useFetchAgentListByPage } from '@/hooks/use-agent-request';
import { useEffect } from 'react';
import { AgentDropdown } from '../agents/agent-dropdown'; import { AgentDropdown } from '../agents/agent-dropdown';
import { useRenameAgent } from '../agents/use-rename-agent'; import { useRenameAgent } from '../agents/use-rename-agent';
export function Agents() { export function Agents({
const { data } = useFetchAgentListByPage(); setListLength,
setLoading,
}: {
setListLength: (length: number) => void;
setLoading?: (loading: boolean) => void;
}) {
const { data, loading } = useFetchAgentListByPage();
const { navigateToAgent } = useNavigatePage(); const { navigateToAgent } = useNavigatePage();
const { const {
agentRenameLoading, agentRenameLoading,
@ -18,6 +25,11 @@ export function Agents() {
showAgentRenameModal, showAgentRenameModal,
} = useRenameAgent(); } = useRenameAgent();
useEffect(() => {
setListLength(data?.length || 0);
setLoading?.(loading || false);
}, [data, setListLength, loading, setLoading]);
return ( return (
<> <>
{data.slice(0, 10).map((x) => ( {data.slice(0, 10).map((x) => (

View File

@ -1,4 +1,6 @@
import { CardSineLineContainer } from '@/components/card-singleline-container'; import { CardSineLineContainer } from '@/components/card-singleline-container';
import { EmptyCardType } from '@/components/empty/constant';
import { EmptyAppCard } from '@/components/empty/empty';
import { HomeIcon } from '@/components/svg-icon'; import { HomeIcon } from '@/components/svg-icon';
import { Segmented, SegmentedValue } from '@/components/ui/segmented'; import { Segmented, SegmentedValue } from '@/components/ui/segmented';
import { Routes } from '@/routes'; import { Routes } from '@/routes';
@ -16,14 +18,29 @@ const IconMap = {
[Routes.Agents]: 'agents', [Routes.Agents]: 'agents',
}; };
const EmptyTypeMap = {
[Routes.Chats]: EmptyCardType.Chat,
[Routes.Searches]: EmptyCardType.Search,
[Routes.Agents]: EmptyCardType.Agent,
};
export function Applications() { export function Applications() {
const [val, setVal] = useState(Routes.Chats); const [val, setVal] = useState(Routes.Chats);
const { t } = useTranslation(); const { t } = useTranslation();
const navigate = useNavigate(); const navigate = useNavigate();
const [listLength, setListLength] = useState(0);
const [loading, setLoading] = useState(false);
const handleNavigate = useCallback(() => { const handleNavigate = useCallback(
({ isCreate }: { isCreate?: boolean }) => {
if (isCreate) {
navigate(val + '?isCreate=true');
} else {
navigate(val); navigate(val);
}, [navigate, val]); }
},
[navigate, val],
);
const options = useMemo( const options = useMemo(
() => [ () => [
@ -36,16 +53,14 @@ export function Applications() {
const handleChange = (path: SegmentedValue) => { const handleChange = (path: SegmentedValue) => {
setVal(path as Routes); setVal(path as Routes);
setListLength(0);
setLoading(true);
}; };
return ( return (
<section className="mt-12"> <section className="mt-12">
<div className="flex justify-between items-center mb-5"> <div className="flex justify-between items-center mb-5">
<h2 className="text-2xl font-semibold flex gap-2.5"> <h2 className="text-2xl font-semibold flex gap-2.5">
{/* <IconFont
name={IconMap[val as keyof typeof IconMap]}
className="size-8"
></IconFont> */}
<HomeIcon <HomeIcon
name={`${IconMap[val as keyof typeof IconMap]}`} name={`${IconMap[val as keyof typeof IconMap]}`}
width={'32'} width={'32'}
@ -63,11 +78,36 @@ export function Applications() {
</div> </div>
{/* <div className="flex flex-wrap gap-4"> */} {/* <div className="flex flex-wrap gap-4"> */}
<CardSineLineContainer> <CardSineLineContainer>
{val === Routes.Agents && <Agents></Agents>} {val === Routes.Agents && (
{val === Routes.Chats && <ChatList></ChatList>} <Agents
{val === Routes.Searches && <SearchList></SearchList>} setListLength={(length: number) => setListLength(length)}
{<SeeAllAppCard click={handleNavigate}></SeeAllAppCard>} setLoading={(loading: boolean) => setLoading(loading)}
></Agents>
)}
{val === Routes.Chats && (
<ChatList
setListLength={(length: number) => setListLength(length)}
setLoading={(loading: boolean) => setLoading(loading)}
></ChatList>
)}
{val === Routes.Searches && (
<SearchList
setListLength={(length: number) => setListLength(length)}
setLoading={(loading: boolean) => setLoading(loading)}
></SearchList>
)}
{listLength > 0 && (
<SeeAllAppCard
click={() => handleNavigate({ isCreate: false })}
></SeeAllAppCard>
)}
</CardSineLineContainer> </CardSineLineContainer>
{listLength <= 0 && !loading && (
<EmptyAppCard
type={EmptyTypeMap[val as keyof typeof EmptyTypeMap]}
onClick={() => handleNavigate({ isCreate: true })}
/>
)}
{/* </div> */} {/* </div> */}
</section> </section>
); );

View File

@ -3,13 +3,20 @@ import { MoreButton } from '@/components/more-button';
import { RenameDialog } from '@/components/rename-dialog'; import { RenameDialog } from '@/components/rename-dialog';
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks'; import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
import { useFetchDialogList } from '@/hooks/use-chat-request'; import { useFetchDialogList } from '@/hooks/use-chat-request';
import { useEffect } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { ChatDropdown } from '../next-chats/chat-dropdown'; import { ChatDropdown } from '../next-chats/chat-dropdown';
import { useRenameChat } from '../next-chats/hooks/use-rename-chat'; import { useRenameChat } from '../next-chats/hooks/use-rename-chat';
export function ChatList() { export function ChatList({
setListLength,
setLoading,
}: {
setListLength: (length: number) => void;
setLoading?: (loading: boolean) => void;
}) {
const { t } = useTranslation(); const { t } = useTranslation();
const { data } = useFetchDialogList(); const { data, loading } = useFetchDialogList();
const { navigateToChat } = useNavigatePage(); const { navigateToChat } = useNavigatePage();
const { const {
@ -20,7 +27,10 @@ export function ChatList() {
onChatRenameOk, onChatRenameOk,
chatRenameLoading, chatRenameLoading,
} = useRenameChat(); } = useRenameChat();
useEffect(() => {
setListLength(data?.dialogs?.length || 0);
setLoading?.(loading || false);
}, [data, setListLength, loading, setLoading]);
return ( return (
<> <>
{data.dialogs.slice(0, 10).map((x) => ( {data.dialogs.slice(0, 10).map((x) => (

View File

@ -1,4 +1,6 @@
import { CardSineLineContainer } from '@/components/card-singleline-container'; import { CardSineLineContainer } from '@/components/card-singleline-container';
import { EmptyCardType } from '@/components/empty/constant';
import { EmptyAppCard } from '@/components/empty/empty';
import { RenameDialog } from '@/components/rename-dialog'; import { RenameDialog } from '@/components/rename-dialog';
import { HomeIcon } from '@/components/svg-icon'; import { HomeIcon } from '@/components/svg-icon';
import { CardSkeleton } from '@/components/ui/skeleton'; import { CardSkeleton } from '@/components/ui/skeleton';
@ -35,6 +37,8 @@ export function Datasets() {
<CardSkeleton /> <CardSkeleton />
</div> </div>
) : ( ) : (
<>
{kbs?.length > 0 && (
<CardSineLineContainer> <CardSineLineContainer>
{kbs {kbs
?.slice(0, 6) ?.slice(0, 6)
@ -45,8 +49,20 @@ export function Datasets() {
showDatasetRenameModal={showDatasetRenameModal} showDatasetRenameModal={showDatasetRenameModal}
></DatasetCard> ></DatasetCard>
))} ))}
{<SeeAllAppCard click={navigateToDatasetList}></SeeAllAppCard>} {
<SeeAllAppCard
click={() => navigateToDatasetList({ isCreate: false })}
></SeeAllAppCard>
}
</CardSineLineContainer> </CardSineLineContainer>
)}
{kbs?.length <= 0 && (
<EmptyAppCard
type={EmptyCardType.Dataset}
onClick={() => navigateToDatasetList({ isCreate: true })}
/>
)}
</>
// </div> // </div>
)} )}
</div> </div>

View File

@ -3,11 +3,18 @@ import { IconFont } from '@/components/icon-font';
import { MoreButton } from '@/components/more-button'; import { MoreButton } from '@/components/more-button';
import { RenameDialog } from '@/components/rename-dialog'; import { RenameDialog } from '@/components/rename-dialog';
import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks'; import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks';
import { useEffect } from 'react';
import { useFetchSearchList, useRenameSearch } from '../next-searches/hooks'; import { useFetchSearchList, useRenameSearch } from '../next-searches/hooks';
import { SearchDropdown } from '../next-searches/search-dropdown'; import { SearchDropdown } from '../next-searches/search-dropdown';
export function SearchList() { export function SearchList({
const { data, refetch: refetchList } = useFetchSearchList(); setListLength,
setLoading,
}: {
setListLength: (length: number) => void;
setLoading?: (loading: boolean) => void;
}) {
const { data, refetch: refetchList, isLoading } = useFetchSearchList();
const { navigateToSearch } = useNavigatePage(); const { navigateToSearch } = useNavigatePage();
const { const {
openCreateModal, openCreateModal,
@ -22,6 +29,11 @@ export function SearchList() {
refetchList(); refetchList();
}); });
}; };
useEffect(() => {
setListLength(data?.data?.search_apps?.length || 0);
setLoading?.(isLoading || false);
}, [data, setListLength, isLoading, setLoading]);
return ( return (
<> <>
{data?.data.search_apps.slice(0, 10).map((x) => ( {data?.data.search_apps.slice(0, 10).map((x) => (

View File

@ -1,4 +1,6 @@
import { CardContainer } from '@/components/card-container'; import { CardContainer } from '@/components/card-container';
import { EmptyCardType } from '@/components/empty/constant';
import { EmptyAppCard } from '@/components/empty/empty';
import ListFilterBar from '@/components/list-filter-bar'; import ListFilterBar from '@/components/list-filter-bar';
import { RenameDialog } from '@/components/rename-dialog'; import { RenameDialog } from '@/components/rename-dialog';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
@ -6,8 +8,9 @@ import { RAGFlowPagination } from '@/components/ui/ragflow-pagination';
import { useFetchDialogList } from '@/hooks/use-chat-request'; import { useFetchDialogList } from '@/hooks/use-chat-request';
import { pick } from 'lodash'; import { pick } from 'lodash';
import { Plus } from 'lucide-react'; import { Plus } from 'lucide-react';
import { useCallback } from 'react'; import { useCallback, useEffect } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useSearchParams } from 'umi';
import { ChatCard } from './chat-card'; import { ChatCard } from './chat-card';
import { useRenameChat } from './hooks/use-rename-chat'; import { useRenameChat } from './hooks/use-rename-chat';
@ -35,8 +38,31 @@ export default function ChatList() {
showChatRenameModal(); showChatRenameModal();
}, [showChatRenameModal]); }, [showChatRenameModal]);
const [searchParams, setSearchParams] = useSearchParams();
const isCreate = searchParams.get('isCreate') === 'true';
useEffect(() => {
if (isCreate) {
handleShowCreateModal();
searchParams.delete('isCreate');
setSearchParams(searchParams);
}
}, [isCreate, handleShowCreateModal, searchParams, setSearchParams]);
return ( return (
<section className="flex flex-col w-full flex-1"> <section className="flex flex-col w-full flex-1">
{data.dialogs?.length <= 0 && (
<div className="flex w-full items-center justify-center h-[calc(100vh-164px)]">
<EmptyAppCard
showIcon
size="large"
className="w-[480px] p-14"
type={EmptyCardType.Chat}
onClick={() => handleShowCreateModal()}
/>
</div>
)}
{data.dialogs?.length > 0 && (
<>
<div className="px-8 pt-8"> <div className="px-8 pt-8">
<ListFilterBar <ListFilterBar
title={t('chat.chatApps')} title={t('chat.chatApps')}
@ -70,6 +96,8 @@ export default function ChatList() {
onChange={handlePageChange} onChange={handlePageChange}
></RAGFlowPagination> ></RAGFlowPagination>
</div> </div>
</>
)}
{chatRenameVisible && ( {chatRenameVisible && (
<RenameDialog <RenameDialog
hideModal={hideChatRenameModal} hideModal={hideChatRenameModal}

View File

@ -17,26 +17,39 @@ import {
import { Separator } from '@/components/ui/separator'; import { Separator } from '@/components/ui/separator';
import { import {
useAllTestingResult, useAllTestingResult,
useChunkIsTesting,
useSelectTestingResult, useSelectTestingResult,
} from '@/hooks/knowledge-hooks'; } from '@/hooks/knowledge-hooks';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import { CheckIcon, ChevronDown, Files, XIcon } from 'lucide-react'; import { CheckIcon, ChevronDown, Files, XIcon } from 'lucide-react';
import { useMemo, useState } from 'react'; import { useEffect, useMemo, useState } from 'react';
interface IProps { interface IProps {
onTesting(documentIds: string[]): void; onTesting(documentIds: string[]): void;
setSelectedDocumentIds(documentIds: string[]): void; setSelectedDocumentIds(documentIds: string[]): void;
selectedDocumentIds: string[]; selectedDocumentIds: string[];
setLoading?: (loading: boolean) => void;
} }
const RetrievalDocuments = ({ const RetrievalDocuments = ({
onTesting, onTesting,
selectedDocumentIds, selectedDocumentIds,
setSelectedDocumentIds, setSelectedDocumentIds,
setLoading,
}: IProps) => { }: IProps) => {
const { documents: documentsAll } = useAllTestingResult(); const { documents: documentsAll } = useAllTestingResult();
const { documents } = useSelectTestingResult(); const { documents } = useSelectTestingResult();
const isTesting = useChunkIsTesting();
const [isPopoverOpen, setIsPopoverOpen] = useState(false); const [isPopoverOpen, setIsPopoverOpen] = useState(false);
useEffect(() => {
if (isTesting) {
setLoading?.(true);
} else {
setLoading?.(false);
}
}, [isTesting, setLoading]);
const { documents: useDocuments } = { const { documents: useDocuments } = {
documents: documents:
documentsAll?.length > documents?.length ? documentsAll : documents, documentsAll?.length > documents?.length ? documentsAll : documents,
@ -45,6 +58,9 @@ const RetrievalDocuments = ({
useState<string[]>(selectedDocumentIds); useState<string[]>(selectedDocumentIds);
const multiOptions = useMemo(() => { const multiOptions = useMemo(() => {
if (!useDocuments || !useDocuments.length) {
return [];
}
return useDocuments?.map((item) => { return useDocuments?.map((item) => {
return { return {
label: item.doc_name, label: item.doc_name,
@ -97,6 +113,7 @@ const RetrievalDocuments = ({
return ( return (
<Popover open={isPopoverOpen} onOpenChange={setIsPopoverOpen}> <Popover open={isPopoverOpen} onOpenChange={setIsPopoverOpen}>
<PopoverTrigger asChild> <PopoverTrigger asChild>
{useDocuments?.length && (
<Button <Button
onClick={handleTogglePopover} onClick={handleTogglePopover}
className={cn( className={cn(
@ -127,6 +144,7 @@ const RetrievalDocuments = ({
</div> </div>
</div> </div>
</Button> </Button>
)}
</PopoverTrigger> </PopoverTrigger>
<PopoverContent <PopoverContent
className="w-auto p-0" className="w-auto p-0"

View File

@ -1,3 +1,5 @@
import { EmptyType } from '@/components/empty/constant';
import Empty from '@/components/empty/empty';
import { FileIcon } from '@/components/icon-font'; import { FileIcon } from '@/components/icon-font';
import { ImageWithPopover } from '@/components/image'; import { ImageWithPopover } from '@/components/image';
import { Input } from '@/components/originui/input'; import { Input } from '@/components/originui/input';
@ -65,6 +67,7 @@ export default function SearchingView({
// changeLanguage(); // changeLanguage();
// }, [i18n]); // }, [i18n]);
const [searchtext, setSearchtext] = useState<string>(''); const [searchtext, setSearchtext] = useState<string>('');
const [retrievalLoading, setRetrievalLoading] = useState(false);
useEffect(() => { useEffect(() => {
setSearchtext(searchStr); setSearchtext(searchStr);
@ -182,6 +185,9 @@ export default function SearchingView({
selectedDocumentIds={selectedDocumentIds} selectedDocumentIds={selectedDocumentIds}
setSelectedDocumentIds={setSelectedDocumentIds} setSelectedDocumentIds={setSelectedDocumentIds}
onTesting={handleTestChunk} onTesting={handleTestChunk}
setLoading={(loading: boolean) => {
setRetrievalLoading(loading);
}}
></RetrievalDocuments> ></RetrievalDocuments>
</div> </div>
{/* <div className="w-full border-b border-border-default/80 my-6"></div> */} {/* <div className="w-full border-b border-border-default/80 my-6"></div> */}
@ -264,6 +270,17 @@ export default function SearchingView({
</> </>
)} )}
</div> </div>
{!isSearchStrEmpty &&
!retrievalLoading &&
!answer.answer &&
!sendingLoading &&
total <= 0 &&
chunks?.length <= 0 &&
relatedQuestions?.length <= 0 && (
<div className="h-2/5 flex items-center justify-center">
<Empty type={EmptyType.SearchData} iconWidth={80} />
</div>
)}
</div> </div>
{total > 0 && ( {total > 0 && (

View File

@ -1,4 +1,6 @@
import { CardContainer } from '@/components/card-container'; import { CardContainer } from '@/components/card-container';
import { EmptyCardType } from '@/components/empty/constant';
import { EmptyAppCard } from '@/components/empty/empty';
import { IconFont } from '@/components/icon-font'; import { IconFont } from '@/components/icon-font';
import ListFilterBar from '@/components/list-filter-bar'; import ListFilterBar from '@/components/list-filter-bar';
import { RenameDialog } from '@/components/rename-dialog'; import { RenameDialog } from '@/components/rename-dialog';
@ -6,6 +8,8 @@ import { Button } from '@/components/ui/button';
import { RAGFlowPagination } from '@/components/ui/ragflow-pagination'; import { RAGFlowPagination } from '@/components/ui/ragflow-pagination';
import { useTranslate } from '@/hooks/common-hooks'; import { useTranslate } from '@/hooks/common-hooks';
import { Plus } from 'lucide-react'; import { Plus } from 'lucide-react';
import { useCallback, useEffect } from 'react';
import { useSearchParams } from 'umi';
import { useFetchSearchList, useRenameSearch } from './hooks'; import { useFetchSearchList, useRenameSearch } from './hooks';
import { SearchCard } from './search-card'; import { SearchCard } from './search-card';
@ -27,6 +31,7 @@ export default function SearchList() {
onSearchRenameOk, onSearchRenameOk,
initialSearchName, initialSearchName,
} = useRenameSearch(); } = useRenameSearch();
const handleSearchChange = (value: string) => { const handleSearchChange = (value: string) => {
console.log(value); console.log(value);
}; };
@ -35,17 +40,41 @@ export default function SearchList() {
refetchList(); refetchList();
}); });
}; };
const openCreateModalFun = () => { const openCreateModalFun = useCallback(() => {
// setIsEdit(false); // setIsEdit(false);
showSearchRenameModal(); showSearchRenameModal();
}; }, [showSearchRenameModal]);
const handlePageChange = (page: number, pageSize: number) => { const handlePageChange = (page: number, pageSize: number) => {
// setIsEdit(false); // setIsEdit(false);
setSearchListParams({ ...searchParams, page, page_size: pageSize }); setSearchListParams({ ...searchParams, page, page_size: pageSize });
}; };
const [searchUrl, setSearchUrl] = useSearchParams();
const isCreate = searchUrl.get('isCreate') === 'true';
useEffect(() => {
if (isCreate) {
openCreateModalFun();
searchUrl.delete('isCreate');
setSearchUrl(searchUrl);
}
}, [isCreate, openCreateModalFun, searchUrl, setSearchUrl]);
return ( return (
<section className="w-full h-full flex flex-col"> <section className="w-full h-full flex flex-col">
{(!list?.data?.search_apps?.length ||
list?.data?.search_apps?.length <= 0) && (
<div className="flex w-full items-center justify-center h-[calc(100vh-164px)]">
<EmptyAppCard
showIcon
size="large"
className="w-[480px] p-14"
type={EmptyCardType.Search}
onClick={() => openCreateModalFun()}
/>
</div>
)}
{!!list?.data?.search_apps?.length && (
<>
<div className="px-8 pt-8"> <div className="px-8 pt-8">
<ListFilterBar <ListFilterBar
icon="searches" icon="searches"
@ -89,7 +118,8 @@ export default function SearchList() {
/> />
</div> </div>
)} )}
</>
)}
{openCreateModal && ( {openCreateModal && (
<RenameDialog <RenameDialog
hideModal={hideSearchRenameModal} hideModal={hideSearchRenameModal}

View File

@ -96,6 +96,19 @@ export default function McpServer() {
</> </>
} }
> >
{!data.mcp_servers?.length && (
<div
className="flex items-center justify-between border border-dashed border-border-button rounded-md p-10 cursor-pointer w-[590px]"
onClick={showEditModal('')}
>
<div className="text-text-secondary text-sm">{t('empty.noMCP')}</div>
<Button variant={'ghost'} className="border border-border-button">
<Plus className="size-3.5 font-medium" /> {t('empty.addNow')}
</Button>
</div>
)}
{!!data.mcp_servers?.length && (
<>
{isSelectionMode && ( {isSelectionMode && (
<section className="pb-5 flex items-center"> <section className="pb-5 flex items-center">
<Checkbox id="all" onCheckedChange={handleSelectAll} /> <Checkbox id="all" onCheckedChange={handleSelectAll} />
@ -152,6 +165,8 @@ export default function McpServer() {
onChange={handlePageChange} onChange={handlePageChange}
></RAGFlowPagination> ></RAGFlowPagination>
</div> </div>
</>
)}
{editVisible && ( {editVisible && (
<EditMcpDialog <EditMcpDialog
hideModal={hideEditModal} hideModal={hideEditModal}

View File

@ -75,7 +75,9 @@ export const ModelProviderCard: FC<IModelCardProps> = ({
<div className="flex items-center space-x-3"> <div className="flex items-center space-x-3">
<LlmIcon name={item.name} /> <LlmIcon name={item.name} />
<div> <div>
<div className="font-medium text-xl">{item.name}</div> <div className="font-medium text-xl text-text-primary">
{item.name}
</div>
</div> </div>
</div> </div>