Merge pull request #153 from langflow-ai/120-design-sweep-polish-setting-screen-needs-to-match-design-spec

120 + 122 design sweep polish setting screen needs to match design spec
This commit is contained in:
boneill-ds 2025-10-02 13:16:47 -06:00 committed by GitHub
commit 6fe3538be9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 682 additions and 185 deletions

View file

@ -9,7 +9,7 @@ const Card = React.forwardRef<
ref={ref}
className={cn(
"rounded-xl border border-border bg-card text-card-foreground shadow-sm",
className,
className
)}
{...props}
/>
@ -33,8 +33,8 @@ const CardTitle = React.forwardRef<
<h3
ref={ref}
className={cn(
"text-base font-semibold leading-tight tracking-tight",
className,
"text-base font-semibold leading-tight tracking-tight text-[14px]",
className
)}
{...props}
/>

View file

@ -26,7 +26,7 @@ const SelectTrigger = React.forwardRef<
<SelectPrimitive.Trigger
ref={ref}
className={cn(
"flex h-10 w-full items-center justify-between rounded-md border border-input px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:bg-muted [&>span]:line-clamp-1",
"flex h-10 w-full items-center justify-between rounded-md border border-input px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:bg-muted [&>span]:line-clamp-1 disabled:border-none",
className
)}
{...props}
@ -34,7 +34,7 @@ const SelectTrigger = React.forwardRef<
{children}
<SelectPrimitive.Icon asChild>
{props.disabled ? (
<LockIcon className="text-base h-5 w-5 opacity-50" />
<LockIcon className="text-base h-4 w-4 opacity-50" />
) : (
<ChevronsUpDown className="text-base h-5 w-5" />
)}

View file

@ -0,0 +1,36 @@
const GoogleDriveIcon = () => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="18"
height="16"
viewBox="0 0 18 16"
fill="none"
>
<path
d="M2.03338 13.2368L2.75732 14.4872C2.90774 14.7504 3.12398 14.9573 3.37783 15.1077L5.9633 10.6325H0.792358C0.792358 10.9239 0.867572 11.2154 1.018 11.4786L2.03338 13.2368Z"
fill="#0066DA"
/>
<path
d="M9.00005 5.36753L6.41458 0.892312C6.16073 1.04274 5.94449 1.24958 5.79407 1.51283L1.018 9.78633C0.870339 10.0439 0.792555 10.3356 0.792358 10.6325H5.9633L9.00005 5.36753Z"
fill="#00AC47"
/>
<path
d="M14.6223 15.1077C14.8761 14.9573 15.0924 14.7504 15.2428 14.4872L15.5436 13.9701L16.9821 11.4786C17.1325 11.2154 17.2077 10.9239 17.2077 10.6325H12.0364L13.1368 12.7949L14.6223 15.1077Z"
fill="#EA4335"
/>
<path
d="M9.00005 5.36753L11.5855 0.892313C11.3317 0.741885 11.0402 0.666672 10.7394 0.666672H7.26074C6.95988 0.666672 6.66843 0.751287 6.41458 0.892312L9.00005 5.36753Z"
fill="#00832D"
/>
<path
d="M12.0368 10.6325H5.9633L3.37783 15.1077C3.63167 15.2581 3.92313 15.3333 4.22398 15.3333H13.7761C14.077 15.3333 14.3684 15.2487 14.6223 15.1077L12.0368 10.6325Z"
fill="#2684FC"
/>
<path
d="M14.5941 5.64958L12.206 1.51283C12.0556 1.24958 11.8394 1.04274 11.5855 0.892313L9.00005 5.36753L12.0368 10.6325L17.1983 10.6325C17.1983 10.341 17.1231 10.0496 16.9727 9.78633L14.5941 5.64958Z"
fill="#FFBA00"
/>
</svg>
);
export default GoogleDriveIcon;

View file

@ -0,0 +1,164 @@
const OneDriveIcon = () => (
<svg
width="17"
height="12"
viewBox="0 0 17 12"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g clip-path="url(#clip0_3016_367)">
<path
d="M5.2316 2.32803C2.88332 2.3281 1.128 4.25034 0.99585 6.39175C1.07765 6.85315 1.34653 7.7643 1.76759 7.71751C2.29391 7.65902 3.61947 7.71751 4.75008 5.67068C5.57599 4.17546 7.27498 2.328 5.2316 2.32803Z"
fill="url(#paint0_radial_3016_367)"
/>
<path
d="M4.68864 3.12741C3.89927 4.37718 2.83674 6.16798 2.47813 6.7315C2.05185 7.40136 0.922937 7.11678 1.01646 6.15663C1.00724 6.23457 1.00016 6.31315 0.995274 6.39226C0.840839 8.89029 2.82143 10.9648 5.28604 10.9648C8.00238 10.9648 14.4806 7.58038 13.825 4.18931C13.134 2.19599 11.1918 0.766266 8.99072 0.766266C6.78965 0.766266 5.37899 2.03436 4.68864 3.12741Z"
fill="url(#paint1_radial_3016_367)"
/>
<path
d="M4.68864 3.12741C3.89927 4.37718 2.83674 6.16798 2.47813 6.7315C2.05185 7.40136 0.922937 7.11678 1.01646 6.15663C1.00724 6.23457 1.00016 6.31315 0.995274 6.39226C0.840839 8.89029 2.82143 10.9648 5.28604 10.9648C8.00238 10.9648 14.4806 7.58038 13.825 4.18931C13.134 2.19599 11.1918 0.766266 8.99072 0.766266C6.78965 0.766266 5.37899 2.03436 4.68864 3.12741Z"
fill="url(#paint2_radial_3016_367)"
fill-opacity="0.4"
/>
<path
d="M4.68864 3.12741C3.89927 4.37718 2.83674 6.16798 2.47813 6.7315C2.05185 7.40136 0.922937 7.11678 1.01646 6.15663C1.00724 6.23457 1.00016 6.31315 0.995274 6.39226C0.840839 8.89029 2.82143 10.9648 5.28604 10.9648C8.00238 10.9648 14.4806 7.58038 13.825 4.18931C13.134 2.19599 11.1918 0.766266 8.99072 0.766266C6.78965 0.766266 5.37899 2.03436 4.68864 3.12741Z"
fill="url(#paint3_radial_3016_367)"
/>
<path
d="M4.68864 3.12741C3.89927 4.37718 2.83674 6.16798 2.47813 6.7315C2.05185 7.40136 0.922937 7.11678 1.01646 6.15663C1.00724 6.23457 1.00016 6.31315 0.995274 6.39226C0.840839 8.89029 2.82143 10.9648 5.28604 10.9648C8.00238 10.9648 14.4806 7.58038 13.825 4.18931C13.134 2.19599 11.1918 0.766266 8.99072 0.766266C6.78965 0.766266 5.37899 2.03436 4.68864 3.12741Z"
fill="url(#paint4_radial_3016_367)"
fill-opacity="0.6"
/>
<path
d="M4.68864 3.12741C3.89927 4.37718 2.83674 6.16798 2.47813 6.7315C2.05185 7.40136 0.922937 7.11678 1.01646 6.15663C1.00724 6.23457 1.00016 6.31315 0.995274 6.39226C0.840839 8.89029 2.82143 10.9648 5.28604 10.9648C8.00238 10.9648 14.4806 7.58038 13.825 4.18931C13.134 2.19599 11.1918 0.766266 8.99072 0.766266C6.78965 0.766266 5.37899 2.03436 4.68864 3.12741Z"
fill="url(#paint5_radial_3016_367)"
fill-opacity="0.9"
/>
<path
d="M5.24634 10.9659C5.24634 10.9659 11.7322 10.9786 12.8323 10.9786C14.8288 10.9786 16.3467 9.34866 16.3468 7.44669C16.3468 5.54468 14.7983 3.92459 12.8323 3.92459C10.8663 3.92459 9.73412 5.39542 8.88374 7.00089C7.8873 8.88221 6.61615 10.9433 5.24634 10.9659Z"
fill="url(#paint6_linear_3016_367)"
/>
<path
d="M5.24634 10.9659C5.24634 10.9659 11.7322 10.9786 12.8323 10.9786C14.8288 10.9786 16.3467 9.34866 16.3468 7.44669C16.3468 5.54468 14.7983 3.92459 12.8323 3.92459C10.8663 3.92459 9.73412 5.39542 8.88374 7.00089C7.8873 8.88221 6.61615 10.9433 5.24634 10.9659Z"
fill="url(#paint7_radial_3016_367)"
fill-opacity="0.4"
/>
<path
d="M5.24634 10.9659C5.24634 10.9659 11.7322 10.9786 12.8323 10.9786C14.8288 10.9786 16.3467 9.34866 16.3468 7.44669C16.3468 5.54468 14.7983 3.92459 12.8323 3.92459C10.8663 3.92459 9.73412 5.39542 8.88374 7.00089C7.8873 8.88221 6.61615 10.9433 5.24634 10.9659Z"
fill="url(#paint8_radial_3016_367)"
fill-opacity="0.9"
/>
</g>
<defs>
<radialGradient
id="paint0_radial_3016_367"
cx="0"
cy="0"
r="1"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(1.28709 2.88928) rotate(50.1526) scale(4.84121 8.03004)"
>
<stop stop-color="#4894FE" />
<stop offset="0.695072" stop-color="#0934B3" />
</radialGradient>
<radialGradient
id="paint1_radial_3016_367"
cx="0"
cy="0"
r="1"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(14.2836 -2.68456) rotate(130.923) scale(20.8177 15.4261)"
>
<stop offset="0.165327" stop-color="#23C0FE" />
<stop offset="0.534" stop-color="#1C91FF" />
</radialGradient>
<radialGradient
id="paint2_radial_3016_367"
cx="0"
cy="0"
r="1"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(4.42852 3.16495) rotate(-139.986) scale(4.23243 9.68892)"
>
<stop stop-color="white" />
<stop offset="0.660528" stop-color="#ADC0FF" stop-opacity="0" />
</radialGradient>
<radialGradient
id="paint3_radial_3016_367"
cx="0"
cy="0"
r="1"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(9.03076 8.16737) rotate(-139.764) scale(4.77056 7.24512)"
>
<stop stop-color="#033ACC" />
<stop offset="1" stop-color="#368EFF" stop-opacity="0" />
</radialGradient>
<radialGradient
id="paint4_radial_3016_367"
cx="0"
cy="0"
r="1"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(4.14837 0.44361) rotate(66.5713) scale(10.4677 11.3005)"
>
<stop offset="0.592618" stop-color="#3464E3" stop-opacity="0" />
<stop offset="1" stop-color="#033ACC" />
</radialGradient>
<radialGradient
id="paint5_radial_3016_367"
cx="0"
cy="0"
r="1"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(14.1157 -1.59739) rotate(135) scale(15.3977 24.123)"
>
<stop stop-color="#4BFDE8" />
<stop offset="0.543937" stop-color="#4BFDE8" stop-opacity="0" />
</radialGradient>
<linearGradient
id="paint6_linear_3016_367"
x1="10.8"
y1="10.9715"
x2="10.8"
y2="4.00825"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#0086FF" />
<stop offset="0.49" stop-color="#00BBFF" />
</linearGradient>
<radialGradient
id="paint7_radial_3016_367"
cx="0"
cy="0"
r="1"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(7.16132 4.75417) rotate(21.6324) scale(6.97728 13.2126)"
>
<stop stop-color="white" />
<stop offset="0.785262" stop-color="white" stop-opacity="0" />
</radialGradient>
<radialGradient
id="paint8_radial_3016_367"
cx="0"
cy="0"
r="1"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(16.1298 3.37785) rotate(139.243) scale(9.56565 9.59808)"
>
<stop stop-color="#4BFDE8" />
<stop offset="0.584724" stop-color="#4BFDE8" stop-opacity="0" />
</radialGradient>
<clipPath id="clip0_3016_367">
<rect
width="15.6444"
height="10.6667"
fill="white"
transform="translate(0.844482 0.666672)"
/>
</clipPath>
</defs>
</svg>
);
export default OneDriveIcon;

View file

@ -0,0 +1,211 @@
const SharePointIcon = () => (
<svg
width="15"
height="16"
viewBox="0 0 15 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g clip-path="url(#clip0_3016_409)">
<path
d="M6.1335 9.6C8.78446 9.6 10.9335 7.45096 10.9335 4.8C10.9335 2.14903 8.78446 0 6.1335 0C3.48254 0 1.3335 2.14903 1.3335 4.8C1.3335 7.45096 3.48254 9.6 6.1335 9.6Z"
fill="url(#paint0_linear_3016_409)"
/>
<path
d="M6.1335 9.6C8.78446 9.6 10.9335 7.45096 10.9335 4.8C10.9335 2.14903 8.78446 0 6.1335 0C3.48254 0 1.3335 2.14903 1.3335 4.8C1.3335 7.45096 3.48254 9.6 6.1335 9.6Z"
fill="url(#paint1_radial_3016_409)"
fill-opacity="0.2"
/>
<path
d="M6.1335 9.6C8.78446 9.6 10.9335 7.45096 10.9335 4.8C10.9335 2.14903 8.78446 0 6.1335 0C3.48254 0 1.3335 2.14903 1.3335 4.8C1.3335 7.45096 3.48254 9.6 6.1335 9.6Z"
fill="url(#paint2_radial_3016_409)"
fill-opacity="0.31"
/>
<path
d="M6.1335 9.6C8.78446 9.6 10.9335 7.45096 10.9335 4.8C10.9335 2.14903 8.78446 0 6.1335 0C3.48254 0 1.3335 2.14903 1.3335 4.8C1.3335 7.45096 3.48254 9.6 6.1335 9.6Z"
fill="url(#paint3_radial_3016_409)"
fill-opacity="0.7"
/>
<path
d="M10.5117 12.8C12.7209 12.8 14.5117 11.0091 14.5117 8.8C14.5117 6.59088 12.7209 4.8 10.5117 4.8C8.3026 4.8 6.51172 6.59088 6.51172 8.8C6.51172 11.0091 8.3026 12.8 10.5117 12.8Z"
fill="url(#paint4_linear_3016_409)"
/>
<path
d="M10.5117 12.8C12.7209 12.8 14.5117 11.0091 14.5117 8.8C14.5117 6.59088 12.7209 4.8 10.5117 4.8C8.3026 4.8 6.51172 6.59088 6.51172 8.8C6.51172 11.0091 8.3026 12.8 10.5117 12.8Z"
fill="url(#paint5_radial_3016_409)"
fill-opacity="0.5"
/>
<path
d="M10.5117 12.8C12.7209 12.8 14.5117 11.0091 14.5117 8.8C14.5117 6.59088 12.7209 4.8 10.5117 4.8C8.3026 4.8 6.51172 6.59088 6.51172 8.8C6.51172 11.0091 8.3026 12.8 10.5117 12.8Z"
fill="url(#paint6_radial_3016_409)"
fill-opacity="0.7"
/>
<path
d="M6.7335 16C8.61126 16 10.1335 14.4778 10.1335 12.6C10.1335 10.7222 8.61126 9.2 6.7335 9.2C4.85574 9.2 3.3335 10.7222 3.3335 12.6C3.3335 14.4778 4.85574 16 6.7335 16Z"
fill="url(#paint7_linear_3016_409)"
/>
<path
d="M6.7335 16C8.61126 16 10.1335 14.4778 10.1335 12.6C10.1335 10.7222 8.61126 9.2 6.7335 9.2C4.85574 9.2 3.3335 10.7222 3.3335 12.6C3.3335 14.4778 4.85574 16 6.7335 16Z"
fill="url(#paint8_linear_3016_409)"
fill-opacity="0.32"
/>
<path
d="M5.23354 7.60001H1.43354C0.715575 7.60001 0.133545 8.18204 0.133545 8.90001V12.7C0.133545 13.418 0.715575 14 1.43354 14H5.23354C5.95151 14 6.53354 13.418 6.53354 12.7V8.90001C6.53354 8.18204 5.95151 7.60001 5.23354 7.60001Z"
fill="url(#paint9_radial_3016_409)"
/>
<path
d="M5.23354 7.60001H1.43354C0.715575 7.60001 0.133545 8.18204 0.133545 8.90001V12.7C0.133545 13.418 0.715575 14 1.43354 14H5.23354C5.95151 14 6.53354 13.418 6.53354 12.7V8.90001C6.53354 8.18204 5.95151 7.60001 5.23354 7.60001Z"
fill="url(#paint10_radial_3016_409)"
fill-opacity="0.6"
/>
<path
d="M1.95581 11.8734L2.64917 11.523C2.72733 11.676 2.82929 11.7887 2.95505 11.8611C3.08249 11.9335 3.22185 11.9697 3.37309 11.9697C3.54133 11.9697 3.66965 11.9368 3.75801 11.871C3.84641 11.8036 3.89057 11.7024 3.89057 11.5675C3.89057 11.4622 3.84809 11.3733 3.76313 11.301C3.67817 11.2269 3.52777 11.171 3.31193 11.1332C2.90069 11.0608 2.60157 10.9341 2.41465 10.7531C2.22941 10.5722 2.13679 10.3468 2.13679 10.077C2.13679 9.74136 2.25915 9.4732 2.50387 9.27248C2.74857 9.0718 3.07145 8.97144 3.47253 8.97144C3.74273 8.97144 3.98065 9.02492 4.18629 9.13184C4.39189 9.23876 4.55505 9.39176 4.67569 9.59084L3.99765 9.92892C3.92285 9.81704 3.84213 9.73644 3.75549 9.68708C3.66881 9.63608 3.56005 9.61056 3.42917 9.61056C3.27285 9.61056 3.15389 9.64348 3.07233 9.70928C2.99245 9.77508 2.95249 9.86064 2.95249 9.96592C2.95249 10.0564 2.99073 10.1362 3.06721 10.2053C3.14537 10.2727 3.30173 10.3278 3.53625 10.3706C3.93053 10.443 4.22449 10.5746 4.41825 10.7654C4.61369 10.9546 4.71137 11.194 4.71137 11.4836C4.71137 11.8356 4.59497 12.1145 4.36217 12.3201C4.12933 12.5258 3.79713 12.6286 3.36545 12.6286C3.05277 12.6286 2.77065 12.5628 2.51916 12.4312C2.26935 12.2979 2.08157 12.112 1.95581 11.8734Z"
fill="white"
/>
<path
d="M1.95483 11.9088L2.64867 11.5466C2.72687 11.7047 2.82891 11.8212 2.95475 11.896C3.08227 11.9709 3.22171 12.0083 3.37307 12.0083C3.54143 12.0083 3.66983 11.9743 3.75823 11.9062C3.84667 11.8365 3.89087 11.732 3.89087 11.5925C3.89087 11.4837 3.84835 11.3918 3.76335 11.317C3.67831 11.2405 3.52783 11.1827 3.31187 11.1436C2.90031 11.0688 2.60103 10.9378 2.41397 10.7508C2.22862 10.5637 2.13594 10.3307 2.13594 10.0518C2.13594 9.70491 2.25838 9.42775 2.50325 9.22027C2.74815 9.01279 3.07123 8.90907 3.47255 8.90907C3.74295 8.90907 3.98099 8.96435 4.18679 9.07487C4.39255 9.18539 4.55579 9.34355 4.67651 9.54931L3.99803 9.89879C3.92319 9.78315 3.84243 9.69983 3.75571 9.64879C3.66895 9.59607 3.56015 9.56971 3.42919 9.56971C3.27275 9.56971 3.15371 9.60375 3.07207 9.67175C2.99215 9.73979 2.95219 9.82819 2.95219 9.93703C2.95219 10.0306 2.99047 10.113 3.06699 10.1845C3.14519 10.2542 3.30167 10.3112 3.53631 10.3554C3.93083 10.4302 4.22503 10.5662 4.41891 10.7635C4.61447 10.959 4.71223 11.2065 4.71223 11.5058C4.71223 11.8697 4.59575 12.1579 4.36279 12.3705C4.12979 12.583 3.79735 12.6893 3.36543 12.6893C3.05251 12.6893 2.77023 12.6213 2.51856 12.4853C2.26858 12.3475 2.08067 12.1554 1.95483 11.9088Z"
fill="white"
/>
</g>
<defs>
<linearGradient
id="paint0_linear_3016_409"
x1="2.5335"
y1="1.2"
x2="8.9335"
y2="9.6"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#00E3DF" />
<stop offset="0.410156" stop-color="#0097A8" />
<stop offset="1" stop-color="#007791" />
</linearGradient>
<radialGradient
id="paint1_radial_3016_409"
cx="0"
cy="0"
r="1"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(7.60222 10.9279) rotate(-112.448) scale(7.37044 13.2516)"
>
<stop offset="0.28573" stop-color="#003B5D" />
<stop offset="0.612265" stop-color="#004A6C" stop-opacity="0.688298" />
<stop offset="0.968041" stop-color="#006F94" stop-opacity="0" />
</radialGradient>
<radialGradient
id="paint2_radial_3016_409"
cx="0"
cy="0"
r="1"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(7.77166 8.81012) rotate(-112.063) scale(6.22076 11.1709)"
>
<stop offset="0.259744" stop-color="#002A42" />
<stop offset="0.612265" stop-color="#004261" stop-opacity="0.688298" />
<stop offset="0.968041" stop-color="#006F94" stop-opacity="0" />
</radialGradient>
<radialGradient
id="paint3_radial_3016_409"
cx="0"
cy="0"
r="1"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(8.87294 0.508276) rotate(124.447) scale(5.20428)"
>
<stop stop-color="#78EDFF" />
<stop offset="1" stop-color="#2CCFCA" stop-opacity="0" />
</radialGradient>
<linearGradient
id="paint4_linear_3016_409"
x1="7.51172"
y1="5.8"
x2="12.845"
y2="12.8"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#00E3DF" />
<stop offset="0.476427" stop-color="#00A2B8" />
<stop offset="0.945063" stop-color="#00637C" />
</linearGradient>
<radialGradient
id="paint5_radial_3016_409"
cx="0"
cy="0"
r="1"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(8.22004 12.1333) rotate(-70.8012) scale(4.94148 8.90348)"
>
<stop stop-color="#003B5D" />
<stop offset="0.492035" stop-color="#004C6C" stop-opacity="0.72" />
<stop offset="0.968041" stop-color="#007A86" stop-opacity="0" />
</radialGradient>
<radialGradient
id="paint6_radial_3016_409"
cx="0"
cy="0"
r="1"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(12.7946 5.22356) rotate(124.447) scale(4.33692)"
>
<stop stop-color="#78EDFF" />
<stop offset="1" stop-color="#2CCFCA" stop-opacity="0" />
</radialGradient>
<linearGradient
id="paint7_linear_3016_409"
x1="4.3535"
y1="9.54"
x2="7.7535"
y2="16.34"
gradientUnits="userSpaceOnUse"
>
<stop offset="0.0534989" stop-color="#75FFF6" />
<stop offset="0.51144" stop-color="#00C7D1" />
<stop offset="0.96002" stop-color="#0096AD" />
</linearGradient>
<linearGradient
id="paint8_linear_3016_409"
x1="10.1179"
y1="16.0003"
x2="8.30102"
y2="13.4503"
gradientUnits="userSpaceOnUse"
>
<stop offset="0.259744" stop-color="#0E5A5D" />
<stop offset="0.535716" stop-color="#126C6B" stop-opacity="0.688298" />
<stop offset="0.968041" stop-color="#1C948A" stop-opacity="0" />
</linearGradient>
<radialGradient
id="paint9_radial_3016_409"
cx="0"
cy="0"
r="1"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(0.133545 7.60001) rotate(45) scale(9.05096)"
>
<stop offset="0.0625" stop-color="#00B6BD" />
<stop offset="0.890131" stop-color="#00495C" />
</radialGradient>
<radialGradient
id="paint10_radial_3016_409"
cx="0"
cy="0"
r="1"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(3.33354 11.44) rotate(90) scale(4.48 5.1)"
>
<stop offset="0.566964" stop-color="#1E8581" stop-opacity="0" />
<stop offset="0.973806" stop-color="#1ECBE6" />
</radialGradient>
<clipPath id="clip0_3016_409">
<rect
width="14.4"
height="16"
fill="white"
transform="translate(0.133545)"
/>
</clipPath>
</defs>
</svg>
);
export default SharePointIcon;

View file

@ -1,7 +1,8 @@
"use client";
import { ArrowUpRight, Loader2, PlugZap, Plus, RefreshCw } from "lucide-react";
import { ArrowUpRight, Loader2, Plus, Minus } from "lucide-react";
import { useRouter, useSearchParams } from "next/navigation";
import Link from "next/link";
import { Suspense, useCallback, useEffect, useState } from "react";
import { useUpdateFlowSettingMutation } from "@/app/api/mutations/useUpdateFlowSettingMutation";
import {
@ -12,7 +13,6 @@ import {
import { useGetSettingsQuery } from "@/app/api/queries/useGetSettingsQuery";
import { ConfirmationDialog } from "@/components/confirmation-dialog";
import { ProtectedRoute } from "@/components/protected-route";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
Card,
@ -21,7 +21,6 @@ import {
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Checkbox } from "@/components/ui/checkbox";
import { Switch } from "@/components/ui/switch";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
@ -44,6 +43,10 @@ import { getFallbackModels, type ModelProvider } from "./helpers/model-helpers";
import { ModelSelectItems } from "./helpers/model-select-item";
import { LabelWrapper } from "@/components/label-wrapper";
import GoogleDriveIcon from "./icons/google-drive-icon";
import OneDriveIcon from "./icons/one-drive-icon";
import SharePointIcon from "./icons/share-point-icon";
const { MAX_SYSTEM_PROMPT_CHARS } = UI_CONSTANTS;
interface GoogleDriveFile {
@ -92,6 +95,33 @@ interface Connection {
last_sync?: string;
}
const DEFAULT_CONNECTORS: Connector[] = [
{
id: "google_drive",
name: "Google Drive",
description: "Google Drive is not configured.",
icon: <GoogleDriveIcon />,
status: "not_connected",
type: "google_drive",
},
{
id: "one_drive",
name: "OneDrive",
description: "OneDrive is not configured.",
icon: <OneDriveIcon />,
status: "not_connected",
type: "one_drive",
},
{
id: "amazon_s3",
name: "SharePoint",
description: "SharePoint is not configured.",
icon: <SharePointIcon />,
status: "not_connected",
type: "sharepoint",
},
];
function KnowledgeSourcesPage() {
const { isAuthenticated, isNoAuthMode } = useAuth();
const { addTask, tasks } = useTask();
@ -114,7 +144,8 @@ function KnowledgeSourcesPage() {
const [chunkOverlap, setChunkOverlap] = useState<number>(50);
const [tableStructure, setTableStructure] = useState<boolean>(false);
const [ocr, setOcr] = useState<boolean>(false);
const [pictureDescriptions, setPictureDescriptions] = useState<boolean>(false);
const [pictureDescriptions, setPictureDescriptions] =
useState<boolean>(false);
// Fetch settings using React Query
const { data: settings = {} } = useGetSettingsQuery({
@ -164,7 +195,7 @@ function KnowledgeSourcesPage() {
onSuccess: () => {
console.log("Setting updated successfully");
},
onError: error => {
onError: (error) => {
console.error("Failed to update setting:", error.message);
},
});
@ -261,22 +292,20 @@ function KnowledgeSourcesPage() {
updateFlowSettingMutation.mutate({ picture_descriptions: checked });
};
console.log({ connectors });
// Helper function to get connector icon
const getConnectorIcon = useCallback((iconName: string) => {
const iconMap: { [key: string]: React.ReactElement } = {
"google-drive": (
<div className="w-8 h-8 bg-blue-600 rounded flex items-center justify-center text-white font-bold leading-none shrink-0">
G
</div>
),
"google-drive": <GoogleDriveIcon />,
sharepoint: (
<div className="w-8 h-8 bg-blue-700 rounded flex items-center justify-center text-white font-bold leading-none shrink-0">
SP
</div>
),
onedrive: (
<div className="w-8 h-8 bg-blue-400 rounded flex items-center justify-center text-white font-bold leading-none shrink-0">
OD
<div className="w-8 h-8 bg-white border border-gray-300 rounded flex items-center justify-center">
<OneDriveIcon />
</div>
),
};
@ -303,8 +332,8 @@ function KnowledgeSourcesPage() {
// Initialize connectors list with metadata from backend
const initialConnectors = connectorTypes
.filter(type => connectorsResult.connectors[type].available) // Only show available connectors
.map(type => ({
.filter((type) => connectorsResult.connectors[type].available) // Only show available connectors
.map((type) => ({
id: type,
name: connectorsResult.connectors[type].name,
description: connectorsResult.connectors[type].description,
@ -312,7 +341,7 @@ function KnowledgeSourcesPage() {
status: "not_connected" as const,
type: type,
}));
console.log({ initialConnectors });
setConnectors(initialConnectors);
// Check status for each connector type
@ -327,8 +356,8 @@ function KnowledgeSourcesPage() {
);
const isConnected = activeConnection !== undefined;
setConnectors(prev =>
prev.map(c =>
setConnectors((prev) =>
prev.map((c) =>
c.type === connectorType
? {
...c,
@ -347,7 +376,7 @@ function KnowledgeSourcesPage() {
const handleConnect = async (connector: Connector) => {
setIsConnecting(connector.id);
setSyncResults(prev => ({ ...prev, [connector.id]: null }));
setSyncResults((prev) => ({ ...prev, [connector.id]: null }));
try {
// Use the shared auth callback URL, same as connectors page
@ -453,34 +482,13 @@ function KnowledgeSourcesPage() {
const getStatusBadge = (status: Connector["status"]) => {
switch (status) {
case "connected":
return (
<Badge
variant="default"
className="bg-green-500/20 text-green-400 border-green-500/30"
>
Connected
</Badge>
);
return <div className="h-2 w-2 bg-green-500 rounded-full" />;
case "connecting":
return (
<Badge
variant="secondary"
className="bg-yellow-500/20 text-yellow-400 border-yellow-500/30"
>
Connecting...
</Badge>
);
return <div className="h-2 w-2 bg-yellow-500 rounded-full" />;
case "error":
return <Badge variant="destructive">Error</Badge>;
return <div className="h-2 w-2 bg-red-500 rounded-full" />;
default:
return (
<Badge
variant="outline"
className="bg-muted/20 text-muted-foreground border-muted whitespace-nowrap"
>
Not Connected
</Badge>
);
return <div className="h-2 w-2 bg-muted rounded-full" />;
}
};
@ -508,9 +516,9 @@ function KnowledgeSourcesPage() {
// Watch for task completions and refresh stats
useEffect(() => {
// Find newly completed tasks by comparing with previous state
const newlyCompletedTasks = tasks.filter(task => {
const newlyCompletedTasks = tasks.filter((task) => {
const wasCompleted =
prevTasks.find(prev => prev.task_id === task.task_id)?.status ===
prevTasks.find((prev) => prev.task_id === task.task_id)?.status ===
"completed";
return task.status === "completed" && !wasCompleted;
});
@ -564,7 +572,7 @@ function KnowledgeSourcesPage() {
fetch(`/api/reset-flow/retrieval`, {
method: "POST",
})
.then(response => {
.then((response) => {
if (response.ok) {
return response.json();
}
@ -577,7 +585,7 @@ function KnowledgeSourcesPage() {
handleModelChange(DEFAULT_AGENT_SETTINGS.llm_model);
closeDialog(); // Close after successful completion
})
.catch(error => {
.catch((error) => {
console.error("Error restoring retrieval flow:", error);
closeDialog(); // Close even on error (could show error toast instead)
});
@ -587,7 +595,7 @@ function KnowledgeSourcesPage() {
fetch(`/api/reset-flow/ingest`, {
method: "POST",
})
.then(response => {
.then((response) => {
if (response.ok) {
return response.json();
}
@ -602,7 +610,7 @@ function KnowledgeSourcesPage() {
setPictureDescriptions(false);
closeDialog(); // Close after successful completion
})
.catch(error => {
.catch((error) => {
console.error("Error restoring ingest flow:", error);
closeDialog(); // Close even on error (could show error toast instead)
});
@ -613,7 +621,7 @@ function KnowledgeSourcesPage() {
{/* Connectors Section */}
<div className="space-y-6">
<div>
<h2 className="text-2xl font-semibold tracking-tight mb-2">
<h2 className="text-lg font-semibold tracking-tight mb-2">
Cloud Connectors
</h2>
</div>
@ -700,73 +708,85 @@ function KnowledgeSourcesPage() {
{/* Connectors Grid */}
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
{connectors.map(connector => (
<Card key={connector.id} className="relative flex flex-col">
<CardHeader>
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
{connector.icon}
<div>
<CardTitle className="text-lg">
{DEFAULT_CONNECTORS.map((connector) => {
const actualConnector = connectors.find(
(c) => c.id === connector.id
);
return (
<Card key={connector.id} className="relative flex flex-col">
<CardHeader>
<div className="flex flex-col items-start justify-between">
<div className="flex flex-col gap-3">
<div className="mb-1">
<div
className={`w-8 h-8 ${
actualConnector ? "bg-white" : "bg-muted grayscale"
} rounded flex items-center justify-center`}
>
{connector.icon}
</div>
</div>
<CardTitle className="flex flex-row items-center gap-2">
{connector.name}
{actualConnector &&
getStatusBadge(actualConnector.status)}
</CardTitle>
<CardDescription className="text-sm">
{connector.description}
<CardDescription className="text-[13px]">
{actualConnector?.description
? `${actualConnector.name} is configured.`
: connector.description}
</CardDescription>
</div>
</div>
{getStatusBadge(connector.status)}
</div>
</CardHeader>
<CardContent className="flex-1 flex flex-col justify-end space-y-4">
{connector.status === "connected" ? (
<div className="space-y-3">
<Button
onClick={() => navigateToKnowledgePage(connector)}
disabled={isSyncing === connector.id}
className="w-full"
variant="outline"
>
<Plus className="h-4 w-4" />
Add Knowledge
</Button>
</CardHeader>
<CardContent className="flex-1 flex flex-col justify-end space-y-4">
{actualConnector?.status === "connected" ? (
<div className="space-y-3">
<Button
onClick={() => navigateToKnowledgePage(connector)}
disabled={isSyncing === connector.id}
className="w-full cursor-pointer"
size="sm"
>
<Plus className="h-4 w-4" />
Add Knowledge
</Button>
{syncResults[connector.id] && (
<div className="text-xs text-muted-foreground bg-muted/50 p-2 rounded">
<div>
Processed: {syncResults[connector.id]?.processed || 0}
{syncResults[connector.id] && (
<div className="text-xs text-muted-foreground bg-muted/50 p-2 rounded">
<div>
Processed:{" "}
{syncResults[connector.id]?.processed || 0}
</div>
<div>
Added: {syncResults[connector.id]?.added || 0}
</div>
{syncResults[connector.id]?.errors && (
<div>
Errors: {syncResults[connector.id]?.errors}
</div>
)}
</div>
<div>
Added: {syncResults[connector.id]?.added || 0}
</div>
{syncResults[connector.id]?.errors && (
<div>Errors: {syncResults[connector.id]?.errors}</div>
)}
</div>
)}
</div>
) : (
<Button
onClick={() => handleConnect(connector)}
disabled={isConnecting === connector.id}
className="w-full"
>
{isConnecting === connector.id ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Connecting...
</>
) : (
<>
<PlugZap className="mr-2 h-4 w-4" />
Connect
</>
)}
</Button>
)}
</CardContent>
</Card>
))}
)}
</div>
) : (
<div className="text-[13px] text-muted-foreground">
<p>
See our{" "}
<Link
className="text-accent-pink-foreground"
href="https://github.com/langflow-ai/openrag/pull/96/files#diff-06889aa94ccf8dac64e70c8cc30a2ceed32cc3c0c2c14a6ff0336fe882a9c2ccR41"
>
Cloud Connectors installation guide
</Link>{" "}
for more detail.
</p>
</div>
)}
</CardContent>
</Card>
);
})}
</div>
</div>
{/* Agent Behavior Section */}
@ -834,7 +854,7 @@ function KnowledgeSourcesPage() {
}
confirmText="Proceed"
confirmIcon={<ArrowUpRight />}
onConfirm={closeDialog =>
onConfirm={(closeDialog) =>
handleEditInLangflow("chat", closeDialog)
}
variant="warning"
@ -854,7 +874,8 @@ function KnowledgeSourcesPage() {
<Select
value={
settings.agent?.llm_model ||
modelsData?.language_models?.find(m => m.default)?.value ||
modelsData?.language_models?.find((m) => m.default)
?.value ||
"gpt-4"
}
onValueChange={handleModelChange}
@ -875,32 +896,31 @@ function KnowledgeSourcesPage() {
</LabelWrapper>
</div>
<div className="space-y-2">
<Label htmlFor="system-prompt" className="text-base font-medium">
Agent Instructions
</Label>
<Textarea
id="system-prompt"
placeholder="Enter your agent instructions here..."
value={systemPrompt}
onChange={e => setSystemPrompt(e.target.value)}
rows={6}
className={`resize-none ${
systemPrompt.length > MAX_SYSTEM_PROMPT_CHARS
? "border-red-500 focus:border-red-500"
: ""
}`}
/>
<div className="flex justify-start">
<span
className={`text-xs ${
<LabelWrapper label="Agent Instructions" id="system-prompt">
<Textarea
id="system-prompt"
placeholder="Enter your agent instructions here..."
value={systemPrompt}
onChange={(e) => setSystemPrompt(e.target.value)}
rows={6}
className={`resize-none ${
systemPrompt.length > MAX_SYSTEM_PROMPT_CHARS
? "text-red-500"
: "text-muted-foreground"
? "border-red-500 focus:border-red-500"
: ""
}`}
>
{systemPrompt.length}/{MAX_SYSTEM_PROMPT_CHARS} characters
</span>
</div>
/>
<div className="flex justify-start">
<span
className={`text-xs ${
systemPrompt.length > MAX_SYSTEM_PROMPT_CHARS
? "text-red-500"
: "text-muted-foreground"
}`}
>
{systemPrompt.length}/{MAX_SYSTEM_PROMPT_CHARS} characters
</span>
</div>
</LabelWrapper>
</div>
<div className="flex justify-end pt-2">
<Button
@ -932,7 +952,9 @@ function KnowledgeSourcesPage() {
<CardHeader>
<div className="flex items-center justify-between">
<div>
<CardTitle className="text-lg mb-4">Knowledge</CardTitle>
<CardTitle className="text-lg mb-4">
Knowledge ingestion and retrieval
</CardTitle>
<CardDescription>
Quick knowledge settings. Edit in Langflow for full control.
</CardDescription>
@ -993,7 +1015,7 @@ function KnowledgeSourcesPage() {
confirmText="Proceed"
confirmIcon={<ArrowUpRight />}
variant="warning"
onConfirm={closeDialog =>
onConfirm={(closeDialog) =>
handleEditInLangflow("ingest", closeDialog)
}
/>
@ -1013,7 +1035,8 @@ function KnowledgeSourcesPage() {
disabled={true}
value={
settings.knowledge?.embedding_model ||
modelsData?.embedding_models?.find(m => m.default)?.value ||
modelsData?.embedding_models?.find((m) => m.default)
?.value ||
"text-embedding-ada-002"
}
onValueChange={handleEmbeddingModelChange}
@ -1042,47 +1065,94 @@ function KnowledgeSourcesPage() {
</div>
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<Label htmlFor="chunk-size" className="text-base font-medium">
Chunk size
</Label>
<div className="relative">
<Input
id="chunk-size"
type="number"
min="1"
value={chunkSize}
onChange={e => handleChunkSizeChange(e.target.value)}
className="w-full pr-20"
/>
<div className="absolute inset-y-0 right-0 flex items-center pr-8 pointer-events-none">
<span className="text-sm text-muted-foreground">
characters
</span>
<LabelWrapper id="chunk-size" label="Chunk size">
<div className="relative">
<Input
id="chunk-size"
type="number"
min="1"
value={chunkSize}
onChange={(e) => handleChunkSizeChange(e.target.value)}
className="w-full pr-20 [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none"
/>
<div className="absolute inset-y-0 right-0 flex items-center">
<span className="text-sm text-placeholder-foreground mr-4 pointer-events-none">
characters
</span>
<div className="flex flex-col">
<Button
aria-label="Increase value"
className="h-5 rounded-l-none rounded-br-none border-input border-b-[0.5px] focus-visible:relative"
variant="outline"
size="iconSm"
onClick={() =>
handleChunkSizeChange((chunkSize + 1).toString())
}
>
<Plus className="text-muted-foreground" size={8} />
</Button>
<Button
aria-label="Decrease value"
className="h-5 rounded-l-none rounded-tr-none border-input border-t-[0.5px] focus-visible:relative"
variant="outline"
size="iconSm"
onClick={() =>
handleChunkSizeChange((chunkSize - 1).toString())
}
>
<Minus className="text-muted-foreground" size={8} />
</Button>
</div>
</div>
</div>
</div>
</LabelWrapper>
</div>
<div className="space-y-2">
<Label
htmlFor="chunk-overlap"
className="text-base font-medium"
>
Chunk overlap
</Label>
<div className="relative">
<Input
id="chunk-overlap"
type="number"
min="0"
value={chunkOverlap}
onChange={e => handleChunkOverlapChange(e.target.value)}
className="w-full pr-20"
/>
<div className="absolute inset-y-0 right-0 flex items-center pr-8 pointer-events-none">
<span className="text-sm text-muted-foreground">
characters
</span>
<LabelWrapper id="chunk-overlap" label="Chunk overlap">
<div className="relative">
<Input
id="chunk-overlap"
type="number"
min="0"
value={chunkOverlap}
onChange={(e) => handleChunkOverlapChange(e.target.value)}
className="w-full pr-20 [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none"
/>
<div className="absolute inset-y-0 right-0 flex items-center">
<span className="text-sm text-placeholder-foreground mr-4 pointer-events-none">
characters
</span>
<div className="flex flex-col">
<Button
aria-label="Increase value"
className="h-5 rounded-l-none rounded-br-none border-input border-b-[0.5px] focus-visible:relative"
variant="outline"
size="iconSm"
onClick={() =>
handleChunkOverlapChange(
(chunkOverlap + 1).toString()
)
}
>
<Plus className="text-muted-foreground" size={8} />
</Button>
<Button
aria-label="Decrease value"
className="h-5 rounded-l-none rounded-tr-none border-input border-t-[0.5px] focus-visible:relative"
variant="outline"
size="iconSm"
onClick={() =>
handleChunkOverlapChange(
(chunkOverlap - 1).toString()
)
}
>
<Minus className="text-muted-foreground" size={8} />
</Button>
</div>
</div>
</div>
</div>
</LabelWrapper>
</div>
</div>
<div className="">
@ -1113,7 +1183,8 @@ function KnowledgeSourcesPage() {
OCR
</Label>
<div className="text-sm text-muted-foreground">
Extracts text from images/PDFs. Ingest is slower when enabled.
Extracts text from images/PDFs. Ingest is slower when
enabled.
</div>
</div>
<Switch

View file

@ -2,7 +2,10 @@
import { Bell, Loader2 } from "lucide-react";
import { usePathname } from "next/navigation";
import { useGetConversationsQuery, type ChatConversation } from "@/app/api/queries/useGetConversationsQuery";
import {
useGetConversationsQuery,
type ChatConversation,
} from "@/app/api/queries/useGetConversationsQuery";
import { useGetSettingsQuery } from "@/app/api/queries/useGetSettingsQuery";
import { KnowledgeFilterPanel } from "@/components/knowledge-filter-panel";
import Logo from "@/components/logo/logo";
@ -16,6 +19,7 @@ import { useKnowledgeFilter } from "@/contexts/knowledge-filter-context";
// import { GitHubStarButton } from "@/components/github-star-button"
// import { DiscordLink } from "@/components/discord-link"
import { useTask } from "@/contexts/task-context";
import { cn } from "@/lib/utils";
export function LayoutWrapper({ children }: { children: React.ReactNode }) {
const pathname = usePathname();
@ -48,12 +52,16 @@ export function LayoutWrapper({ children }: { children: React.ReactNode }) {
const authPaths = ["/login", "/auth/callback", "/onboarding"];
const isAuthPage = authPaths.includes(pathname);
// List of paths with smaller max-width
const smallWidthPaths = ["/settings", "/settings/connector/new"];
const isSmallWidthPath = smallWidthPaths.includes(pathname);
// Calculate active tasks for the bell icon
const activeTasks = tasks.filter(
(task) =>
task.status === "pending" ||
task.status === "running" ||
task.status === "processing",
task.status === "processing"
);
// Show loading state when backend isn't ready
@ -139,7 +147,14 @@ export function LayoutWrapper({ children }: { children: React.ReactNode }) {
"md:pr-0" // Neither open: 24px
}`}
>
<div className="container py-6 lg:py-8 px-4 lg:px-6">{children}</div>
<div
className={cn(
"py-6 lg:py-8 px-4 lg:px-6",
isSmallWidthPath ? "max-w-[850px]" : "container"
)}
>
{children}
</div>
</main>
<TaskNotificationMenu />
<KnowledgeFilterPanel />