diff --git a/frontend/src/components/helpers/auth/RequireAuth.js b/frontend/src/components/helpers/auth/RequireAuth.js index 48a6e7f7b..d98ba3c56 100644 --- a/frontend/src/components/helpers/auth/RequireAuth.js +++ b/frontend/src/components/helpers/auth/RequireAuth.js @@ -3,6 +3,7 @@ import { useEffect } from "react"; import { getOrgNameFromPathname, + homePagePath, onboardCompleted, } from "../../../helpers/GetStaticData"; import { useSessionStore } from "../../../store/session-store"; @@ -53,7 +54,7 @@ const RequireAuth = () => { if (isLlmWhisperer) { navigateTo = `/llm-whisperer/${orgName}/playground`; } else if (onboardCompleted(adapters)) { - navigateTo = `/${orgName}/tools`; + navigateTo = `/${orgName}/${homePagePath}`; } if ( sessionDetails.role === "unstract_reviewer" || diff --git a/frontend/src/components/helpers/auth/RequireGuest.js b/frontend/src/components/helpers/auth/RequireGuest.js index 00b1fa62c..a49c02035 100644 --- a/frontend/src/components/helpers/auth/RequireGuest.js +++ b/frontend/src/components/helpers/auth/RequireGuest.js @@ -1,6 +1,10 @@ import { Navigate, Outlet, useLocation } from "react-router-dom"; -import { publicRoutes, onboardCompleted } from "../../../helpers/GetStaticData"; +import { + publicRoutes, + onboardCompleted, + homePagePath, +} from "../../../helpers/GetStaticData"; import { useSessionStore } from "../../../store/session-store"; let selectedProductStore; let isLlmWhisperer; @@ -28,7 +32,7 @@ const RequireGuest = () => { if (isLlmWhisperer) { navigateTo = `/llm-whisperer/${orgName}/playground`; } else if (onboardCompleted(adapters)) { - navigateTo = `/${orgName}/tools`; + navigateTo = `/${orgName}/${homePagePath}`; } if ( sessionDetails.role === "unstract_reviewer" || diff --git a/frontend/src/components/input-output/add-source/AddSource.jsx b/frontend/src/components/input-output/add-source/AddSource.jsx index eb56d76a2..ddaff0a34 100644 --- a/frontend/src/components/input-output/add-source/AddSource.jsx +++ b/frontend/src/components/input-output/add-source/AddSource.jsx @@ -10,6 +10,22 @@ import { EmptyState } from "../../widgets/empty-state/EmptyState"; import { ConfigureDs } from "../configure-ds/ConfigureDs"; import { useExceptionHandler } from "../../../hooks/useExceptionHandler"; +let transformLlmWhispererJsonSchema; +let LLMW_V2_ID; +let PLAN_TYPES; +let unstractSubscriptionPlanStore; +try { + transformLlmWhispererJsonSchema = + require("../../../plugins/unstract-subscription/helper/transformLlmWhispererJsonSchema").transformLlmWhispererJsonSchema; + LLMW_V2_ID = + require("../../../plugins/unstract-subscription/helper/transformLlmWhispererJsonSchema").LLMW_V2_ID; + PLAN_TYPES = + require("../../../plugins/unstract-subscription/helper/constants").PLAN_TYPES; + unstractSubscriptionPlanStore = require("../../../plugins/store/unstract-subscription-plan-store"); +} catch (err) { + // Ignore if not available +} + function AddSource({ selectedSourceId, selectedSourceName, @@ -32,6 +48,13 @@ function AddSource({ const axiosPrivate = useAxiosPrivate(); const handleException = useExceptionHandler(); + let planType; + if (unstractSubscriptionPlanStore?.useUnstractSubscriptionPlanStore) { + planType = unstractSubscriptionPlanStore?.useUnstractSubscriptionPlanStore( + (state) => state?.unstractSubscriptionPlan?.planType + ); + } + useEffect(() => { if (!selectedSourceId) { setSpec({}); @@ -56,7 +79,19 @@ function AddSource({ .then((res) => { const data = res?.data; setFormData(metadata || {}); - setSpec(data?.json_schema || {}); + + if ( + LLMW_V2_ID && + transformLlmWhispererJsonSchema && + PLAN_TYPES && + selectedSourceId === LLMW_V2_ID && + planType === PLAN_TYPES?.PAID + ) { + setSpec(transformLlmWhispererJsonSchema(data?.json_schema || {})); + } else { + setSpec(data?.json_schema || {}); + } + if (data?.oauth) { setOAuthProvider(data?.python_social_auth_backend); } else { diff --git a/frontend/src/components/navigations/side-nav-bar/SideNavBar.jsx b/frontend/src/components/navigations/side-nav-bar/SideNavBar.jsx index 0a1997d9d..2d58d5cd8 100644 --- a/frontend/src/components/navigations/side-nav-bar/SideNavBar.jsx +++ b/frontend/src/components/navigations/side-nav-bar/SideNavBar.jsx @@ -31,6 +31,14 @@ try { // Plugin unavailable. } +let dashboardSideMenuItem; +try { + dashboardSideMenuItem = + require("../../../plugins/unstract-subscription/helper/constants").dashboardSideMenuItem; +} catch (err) { + // Plugin unavailable. +} + const SideNavBar = ({ collapsed }) => { const navigate = useNavigate(); const { sessionDetails } = useSessionStore(); @@ -40,7 +48,7 @@ const SideNavBar = ({ collapsed }) => { menu = sideMenu.useSideMenu(); } - const data = menu || [ + const unstractMenuItems = [ { id: 1, mainTitle: "MANAGE", @@ -155,6 +163,12 @@ const SideNavBar = ({ collapsed }) => { }, ]; + if (dashboardSideMenuItem) { + unstractMenuItems[2].subMenu.push(dashboardSideMenuItem(orgName)); + } + + const data = menu || unstractMenuItems; + if (getMenuItem && flags?.app_deployment) { data[0]?.subMenu?.splice(1, 0, getMenuItem?.default(orgName)); } diff --git a/frontend/src/components/navigations/top-nav-bar/TopNavBar.jsx b/frontend/src/components/navigations/top-nav-bar/TopNavBar.jsx index 7bbd63be8..2dd2d23ed 100644 --- a/frontend/src/components/navigations/top-nav-bar/TopNavBar.jsx +++ b/frontend/src/components/navigations/top-nav-bar/TopNavBar.jsx @@ -16,7 +16,7 @@ import { FileProtectOutlined, LikeOutlined, } from "@ant-design/icons"; -import { useEffect, useState } from "react"; +import { useEffect, useState, useMemo, useCallback } from "react"; import { useNavigate, useLocation } from "react-router-dom"; import axios from "axios"; import PropTypes from "prop-types"; @@ -24,6 +24,7 @@ import PropTypes from "prop-types"; import { UnstractLogo } from "../../../assets/index.js"; import { getBaseUrl, + homePagePath, onboardCompleted, } from "../../../helpers/GetStaticData.js"; import useLogout from "../../../hooks/useLogout.js"; @@ -37,12 +38,13 @@ import { useExceptionHandler } from "../../../hooks/useExceptionHandler.jsx"; let TrialDaysInfo; try { TrialDaysInfo = - require("../../../plugins/subscription/trial-helper/TrialDaysInfo.jsx").default; + require("../../../plugins/unstract-subscription/components/TrialDaysInfo.jsx").default; } catch (err) { // Plugin not found } -let selectedProduct; + let selectedProductStore; +let selectedProduct; try { selectedProductStore = require("../../../plugins/llm-whisperer/store/select-product-store.js"); @@ -51,7 +53,6 @@ try { } let PlatformDropdown; - try { PlatformDropdown = require("../../../plugins/platform-dropdown/PlatformDropDown.jsx").PlatformDropdown; @@ -59,12 +60,6 @@ try { // Plugin not found } -try { - selectedProductStore = require("../../../plugins/llm-whisperer/store/select-product-store.js"); -} catch { - // Ignore if hook not available -} - let WhispererLogo; try { WhispererLogo = @@ -76,10 +71,9 @@ try { function TopNavBar({ isSimpleLayout, topNavBarOptions }) { const navigate = useNavigate(); const { sessionDetails } = useSessionStore(); - const { orgName, remainingTrialDays, allOrganization, orgId } = - sessionDetails; + const { orgName, allOrganization, orgId } = sessionDetails; const baseUrl = getBaseUrl(); - const onBoardUrl = baseUrl + `/${orgName}/onboard`; + const onBoardUrl = `${baseUrl}/${orgName}/onboard`; const logout = useLogout(); const [showOnboardBanner, setShowOnboardBanner] = useState(false); const [approverStatus, setApproverStatus] = useState(false); @@ -97,27 +91,29 @@ function TopNavBar({ isSimpleLayout, topNavBarOptions }) { const isUnstract = !(selectedProduct && selectedProduct !== "unstract"); + // Check user role and whether the onboarding is incomplete useEffect(() => { - const isUnstractReviewer = sessionDetails.role === "unstract_reviewer"; - const isUnstractSupervisor = sessionDetails.role === "unstract_supervisor"; - const isUnstractAdmin = sessionDetails.role === "unstract_admin"; + const { role } = sessionDetails; + const isReviewer = role === "unstract_reviewer"; + const isSupervisor = role === "unstract_supervisor"; + const isAdmin = role === "unstract_admin"; setShowOnboardBanner( !onboardCompleted(sessionDetails?.adapters) && - !isUnstractReviewer && - !isUnstractSupervisor + !isReviewer && + !isSupervisor ); - - setApproverStatus(isUnstractAdmin || isUnstractSupervisor); - setReviewerStatus(isUnstractReviewer); + setApproverStatus(isAdmin || isSupervisor); + setReviewerStatus(isReviewer); }, [sessionDetails]); + // Determine review page header useEffect(() => { - const checkReviewPage = location.pathname.split("review"); - if (checkReviewPage.length > 1) { - if (checkReviewPage[1].includes("/approve")) { + const pathSegments = location.pathname.split("review"); + if (pathSegments.length > 1) { + if (pathSegments[1].includes("/approve")) { setReviewPageHeader("Approve"); - } else if (checkReviewPage[1].includes("/download_and_sync")) { + } else if (pathSegments[1].includes("/download_and_sync")) { setReviewPageHeader("Download and syncmanager"); } else { setReviewPageHeader("Review"); @@ -130,33 +126,8 @@ function TopNavBar({ isSimpleLayout, topNavBarOptions }) { } }, [location]); - const cascadeOptions = allOrganization?.map((org) => { - return { - key: org?.id, - label: - org?.id === sessionDetails?.orgId ? ( -
- setAlertDetails({ - type: "error", - content: `You are already in ${org?.display_name}`, - }) - } - > - {org?.display_name} -
- ) : ( - handleContinue(org?.id)} - content={`Want to switch to ${org?.display_name} `} - > -
{org?.display_name}
-
- ), - }; - }); - - const handleContinue = async (selectedOrg) => { + // Switch organization + const handleContinue = useCallback(async (selectedOrg) => { const requestOptions = { method: "POST", url: `/api/v1/organization/${selectedOrg}/set`, @@ -164,51 +135,89 @@ function TopNavBar({ isSimpleLayout, topNavBarOptions }) { "X-CSRFToken": sessionDetails?.csrfToken, }, }; - await axios(requestOptions) - .then(() => { - navigate("/"); - window.location.reload(); - }) - .catch((err) => { - setAlertDetails(handleException(err)); + try { + await axios(requestOptions); + navigate("/"); + window.location.reload(); + } catch (err) { + setAlertDetails(handleException(err)); + } + }, []); + + // Prepare org list for switching + const cascadeOptions = useMemo(() => { + return allOrganization?.map((org) => { + return { + key: org?.id, + label: + org?.id === sessionDetails?.orgId ? ( +
+ setAlertDetails({ + type: "error", + content: `You are already in ${org?.display_name}`, + }) + } + > + {org?.display_name} +
+ ) : ( + handleContinue(org?.id)} + content={`Want to switch to ${org?.display_name}?`} + > +
{org?.display_name}
+
+ ), + }; + }); + }, [allOrganization, handleContinue]); + + // Build dropdown menu items + const items = useMemo(() => { + const menuItems = []; + + // Profile + if (isUnstract && !isSimpleLayout) { + menuItems.push({ + key: "1", + label: ( + + ), + }); + } + + // Switch Organization + if (allOrganization?.length > 1) { + menuItems.push({ + key: "3", + label: ( + +
+ Switch Org +
+
+ ), }); - }; + } - // Profile Dropdown items - const items = [ - isUnstract && { - key: "1", - label: ( - - ), - }, - allOrganization?.length > 1 && { - key: "3", - label: ( - -
- {" "} - Switch Org -
-
- ), - }, - isUnstract && - (reviewerStatus || approverStatus) && { + // Review + if (isUnstract && !isSimpleLayout && (reviewerStatus || approverStatus)) { + menuItems.push({ key: "4", label: ( ), - }, - isUnstract && - approverStatus && { + }); + } + + // Approve + if (isUnstract && !isSimpleLayout && approverStatus) { + menuItems.push({ key: "5", label: ( ), - }, - isUnstract && - approverStatus && { + }); + + menuItems.push({ key: "6", label: ( ), - }, - { + }); + } + + // Logout + menuItems.push({ key: "2", label: ( ), - }, - ]; + }); + + return menuItems.filter(Boolean); // remove any undefined items + }, [ + isUnstract, + isSimpleLayout, + reviewerStatus, + approverStatus, + allOrganization, + cascadeOptions, + orgName, + orgId, + ]); // Function to get the initials from the user name - const getInitials = (name) => { + const getInitials = useCallback((name) => { const names = name?.split(" "); - const initials = names + return names ?.map((n) => n.charAt(0)) ?.join("") ?.toUpperCase(); - return initials; - }; + }, []); return ( {isUnstract ? ( - + + navigate(`/${sessionDetails?.orgName}/${homePagePath}`) + } + /> ) : ( WhispererLogo && )} @@ -279,61 +309,55 @@ function TopNavBar({ isSimpleLayout, topNavBarOptions }) { )} {PlatformDropdown && } - {!isSimpleLayout && ( - <> - - {isUnstract && showOnboardBanner && ( - - - Your setup process is incomplete. Now, that's a - bummer! - - - Complete it to start using Unstract - - - } - showIcon - /> - )} - - - - - {topNavBarOptions} - {isUnstract && TrialDaysInfo && ( - - )} - -
- {sessionDetails?.picture ? ( - - ) : ( - - {getInitials(sessionDetails?.name)} - - )} -
-
-
-
- - + + {isSimpleLayout ? ( + + ) : ( + + {isUnstract && showOnboardBanner && ( + + + Your setup process is incomplete. Now, that's a bummer! + + + Complete it to start using Unstract + + + } + showIcon + /> + )} + )} + + + + + {topNavBarOptions} + {isUnstract && TrialDaysInfo && } + +
+ {sessionDetails?.picture ? ( + + ) : ( + + {getInitials(sessionDetails?.name)} + + )} +
+
+
+
+
); } diff --git a/frontend/src/components/onboard/OnBoard.jsx b/frontend/src/components/onboard/OnBoard.jsx index 79f0afd1c..cf6a02534 100644 --- a/frontend/src/components/onboard/OnBoard.jsx +++ b/frontend/src/components/onboard/OnBoard.jsx @@ -8,7 +8,7 @@ import ConnectLLM from "../../assets/connect_llm.svg"; import ConnectVectorDb from "../../assets/connect_vector_db.svg"; import ConnectEmbedding from "../../assets/connect_embedding.svg"; import ConnectTextExtractor from "../../assets/connect_x2text.svg"; -import { onboardCompleted } from "../../helpers/GetStaticData.js"; +import { homePagePath, onboardCompleted } from "../../helpers/GetStaticData.js"; import { useSessionStore } from "../../store/session-store.js"; import { AddSourceModal } from "../input-output/add-source-modal/AddSourceModal.jsx"; import { CustomButton } from "../widgets/custom-button/CustomButton.jsx"; @@ -22,7 +22,7 @@ function OnBoard() { const [openAddSourcesModal, setOpenAddSourcesModal] = useState(false); const [editItemId, setEditItemId] = useState(null); const [type, setType] = useState(null); - const homePageUrl = `/${orgName}/tools`; + const homePageUrl = `/${orgName}/${homePagePath}`; const [adaptersList, setAdaptersList] = useState(adapters || []); useEffect(() => { if (onboardCompleted(adaptersList)) { diff --git a/frontend/src/components/rjsf-custom-widgets/alt-date-time-widget/AltDateTimeWidget.jsx b/frontend/src/components/rjsf-custom-widgets/alt-date-time-widget/AltDateTimeWidget.jsx index 25112fa3b..3a20feb3a 100644 --- a/frontend/src/components/rjsf-custom-widgets/alt-date-time-widget/AltDateTimeWidget.jsx +++ b/frontend/src/components/rjsf-custom-widgets/alt-date-time-widget/AltDateTimeWidget.jsx @@ -11,6 +11,7 @@ const AltDateTimeWidget = ({ label, schema, required, + readonly, }) => { const description = schema?.description || ""; const handleDateChange = (date) => { @@ -34,10 +35,12 @@ const AltDateTimeWidget = ({ id={id} value={value ? moment(value) : null} onChange={handleDateChange} + disabled={readonly} /> ); @@ -49,7 +52,8 @@ AltDateTimeWidget.propTypes = { onChange: PropTypes.func.isRequired, label: PropTypes.string.isRequired, schema: PropTypes.object.isRequired, - required: PropTypes.bool, + required: PropTypes.bool.isRequired, + readonly: PropTypes.bool.isRequired, }; export { AltDateTimeWidget }; diff --git a/frontend/src/components/rjsf-custom-widgets/alt-date-widget/AltDateWidget.jsx b/frontend/src/components/rjsf-custom-widgets/alt-date-widget/AltDateWidget.jsx index 7c996c060..d683ed55d 100644 --- a/frontend/src/components/rjsf-custom-widgets/alt-date-widget/AltDateWidget.jsx +++ b/frontend/src/components/rjsf-custom-widgets/alt-date-widget/AltDateWidget.jsx @@ -4,7 +4,8 @@ import PropTypes from "prop-types"; import { RjsfWidgetLayout } from "../../../layouts/rjsf-widget-layout/RjsfWidgetLayout.jsx"; -const AltDateWidget = ({ id, value, onChange, label, schema, required }) => { +const AltDateWidget = (props) => { + const { id, value, onChange, label, schema, required, readonly } = props; const description = schema?.description || ""; const handleDateChange = (date) => { @@ -21,6 +22,7 @@ const AltDateWidget = ({ id, value, onChange, label, schema, required }) => { id={id} value={value ? moment(value) : null} onChange={handleDateChange} + disabled={readonly} /> ); @@ -33,6 +35,7 @@ AltDateWidget.propTypes = { label: PropTypes.string.isRequired, schema: PropTypes.object.isRequired, required: PropTypes.bool, + readonly: PropTypes.bool.isRequired, }; export { AltDateWidget }; diff --git a/frontend/src/components/rjsf-custom-widgets/array-field/ArrayField.jsx b/frontend/src/components/rjsf-custom-widgets/array-field/ArrayField.jsx index 434847c50..bc91174c7 100644 --- a/frontend/src/components/rjsf-custom-widgets/array-field/ArrayField.jsx +++ b/frontend/src/components/rjsf-custom-widgets/array-field/ArrayField.jsx @@ -7,7 +7,7 @@ import { RjsfWidgetLayout } from "../../../layouts/rjsf-widget-layout/RjsfWidget import "./ArrayField.css"; const ArrayField = (props) => { - const { schema, formData, onChange, required } = props; + const { schema, formData, onChange, required, readonly } = props; const [dropdownList, setDropdownList] = useState([]); const [options, setOptions] = useState([]); @@ -54,6 +54,7 @@ const ArrayField = (props) => { value={formData} onChange={handleChange} options={options} + disabled={readonly} /> ); @@ -65,6 +66,7 @@ ArrayField.propTypes = { formData: PropTypes.array, onChange: PropTypes.func.isRequired, required: PropTypes.bool, + readonly: PropTypes.bool.isRequired, }; export { ArrayField }; diff --git a/frontend/src/components/rjsf-custom-widgets/checkbox-widget/CheckboxWidget.jsx b/frontend/src/components/rjsf-custom-widgets/checkbox-widget/CheckboxWidget.jsx index 4ea6ba0b1..5d508cde4 100644 --- a/frontend/src/components/rjsf-custom-widgets/checkbox-widget/CheckboxWidget.jsx +++ b/frontend/src/components/rjsf-custom-widgets/checkbox-widget/CheckboxWidget.jsx @@ -1,8 +1,17 @@ import { Checkbox, Space, Typography } from "antd"; import PropTypes from "prop-types"; + import "./CheckboxWidget.css"; import CustomMarkdown from "../../helpers/custom-markdown/CustomMarkdown"; -const CheckboxWidget = ({ id, value, onChange, label, schema, required }) => { +const CheckboxWidget = ({ + id, + value, + onChange, + label, + schema, + required, + readonly, +}) => { const description = schema?.description || ""; const handleCheckboxChange = (event) => { onChange(event.target.checked); @@ -10,7 +19,12 @@ const CheckboxWidget = ({ id, value, onChange, label, schema, required }) => { return ( - + {required && * } {label} @@ -34,6 +48,7 @@ CheckboxWidget.propTypes = { label: PropTypes.string.isRequired, schema: PropTypes.object.isRequired, required: PropTypes.bool, + readonly: PropTypes.bool.isRequired, }; export { CheckboxWidget }; diff --git a/frontend/src/components/rjsf-custom-widgets/checkboxes-widget/CheckboxesWidget.jsx b/frontend/src/components/rjsf-custom-widgets/checkboxes-widget/CheckboxesWidget.jsx index 76fbf0873..3fb43bb6f 100644 --- a/frontend/src/components/rjsf-custom-widgets/checkboxes-widget/CheckboxesWidget.jsx +++ b/frontend/src/components/rjsf-custom-widgets/checkboxes-widget/CheckboxesWidget.jsx @@ -11,6 +11,7 @@ const CheckboxesWidget = ({ label, schema, required, + readonly, }) => { const description = schema?.description || ""; const handleCheckboxChange = (optionValue) => { @@ -35,6 +36,7 @@ const CheckboxesWidget = ({ key={option.value} checked={value?.includes(option.value)} onChange={() => handleCheckboxChange(option.value)} + disabled={readonly} > {option.label} @@ -51,6 +53,7 @@ CheckboxesWidget.propTypes = { label: PropTypes.string.isRequired, schema: PropTypes.object.isRequired, required: PropTypes.bool, + readonly: PropTypes.bool.isRequired, }; export { CheckboxesWidget }; diff --git a/frontend/src/components/rjsf-custom-widgets/color-widget/ColorWidget.jsx b/frontend/src/components/rjsf-custom-widgets/color-widget/ColorWidget.jsx index d6a1b4750..7bb0ea6db 100644 --- a/frontend/src/components/rjsf-custom-widgets/color-widget/ColorWidget.jsx +++ b/frontend/src/components/rjsf-custom-widgets/color-widget/ColorWidget.jsx @@ -3,7 +3,15 @@ import { Input } from "antd"; import { RjsfWidgetLayout } from "../../../layouts/rjsf-widget-layout/RjsfWidgetLayout.jsx"; -const ColorWidget = ({ id, value, onChange, schema, label, required }) => { +const ColorWidget = ({ + id, + value, + onChange, + schema, + label, + required, + readonly, +}) => { const description = schema?.description || ""; const handleColorChange = (event) => { @@ -16,7 +24,13 @@ const ColorWidget = ({ id, value, onChange, schema, label, required }) => { description={description} required={required} > - + ); }; @@ -28,6 +42,7 @@ ColorWidget.propTypes = { schema: PropTypes.object.isRequired, label: PropTypes.string.isRequired, required: PropTypes.bool, + readonly: PropTypes.bool.isRequired, }; export { ColorWidget }; diff --git a/frontend/src/components/rjsf-custom-widgets/date-time-widget/DateTimeWidget.jsx b/frontend/src/components/rjsf-custom-widgets/date-time-widget/DateTimeWidget.jsx index a3b2df307..74d28bc99 100644 --- a/frontend/src/components/rjsf-custom-widgets/date-time-widget/DateTimeWidget.jsx +++ b/frontend/src/components/rjsf-custom-widgets/date-time-widget/DateTimeWidget.jsx @@ -4,7 +4,15 @@ import PropTypes from "prop-types"; import { RjsfWidgetLayout } from "../../../layouts/rjsf-widget-layout/RjsfWidgetLayout.jsx"; -const DateTimeWidget = ({ id, value, onChange, label, schema, required }) => { +const DateTimeWidget = ({ + id, + value, + onChange, + label, + schema, + required, + readonly, +}) => { const description = schema?.description || ""; const handleDateTimeChange = (dateTime) => { onChange(dateTime?.toISOString()); @@ -21,6 +29,7 @@ const DateTimeWidget = ({ id, value, onChange, label, schema, required }) => { id={id} value={value ? moment(value) : null} onChange={handleDateTimeChange} + disabled={readonly} /> ); @@ -33,6 +42,7 @@ DateTimeWidget.propTypes = { label: PropTypes.string.isRequired, schema: PropTypes.object.isRequired, required: PropTypes.bool, + readonly: PropTypes.bool.isRequired, }; export { DateTimeWidget }; diff --git a/frontend/src/components/rjsf-custom-widgets/date-widget/DateWidget.jsx b/frontend/src/components/rjsf-custom-widgets/date-widget/DateWidget.jsx index 06ea0a494..5e4e5cd11 100644 --- a/frontend/src/components/rjsf-custom-widgets/date-widget/DateWidget.jsx +++ b/frontend/src/components/rjsf-custom-widgets/date-widget/DateWidget.jsx @@ -4,7 +4,15 @@ import PropTypes from "prop-types"; import { RjsfWidgetLayout } from "../../../layouts/rjsf-widget-layout/RjsfWidgetLayout.jsx"; -const DateWidget = ({ id, value, onChange, label, schema, required }) => { +const DateWidget = ({ + id, + value, + onChange, + label, + schema, + required, + readonly, +}) => { const description = schema?.description || ""; const handleDateChange = (date) => { onChange(date?.toISOString()); @@ -20,6 +28,7 @@ const DateWidget = ({ id, value, onChange, label, schema, required }) => { id={id} value={value ? moment(value) : null} onChange={handleDateChange} + disabled={readonly} /> ); @@ -32,6 +41,7 @@ DateWidget.propTypes = { label: PropTypes.string.isRequired, schema: PropTypes.object.isRequired, required: PropTypes.bool, + readonly: PropTypes.bool.isRequired, }; export { DateWidget }; diff --git a/frontend/src/components/rjsf-custom-widgets/email-widget/EmailWidget.jsx b/frontend/src/components/rjsf-custom-widgets/email-widget/EmailWidget.jsx index 711cb0b5d..183e0c0b7 100644 --- a/frontend/src/components/rjsf-custom-widgets/email-widget/EmailWidget.jsx +++ b/frontend/src/components/rjsf-custom-widgets/email-widget/EmailWidget.jsx @@ -3,7 +3,15 @@ import PropTypes from "prop-types"; import { RjsfWidgetLayout } from "../../../layouts/rjsf-widget-layout/RjsfWidgetLayout.jsx"; -const EmailWidget = ({ id, value, onChange, label, schema, required }) => { +const EmailWidget = ({ + id, + value, + onChange, + label, + schema, + required, + readonly, +}) => { const description = schema?.description || ""; const handleEmailChange = (event) => { onChange(event.target.value); @@ -15,7 +23,13 @@ const EmailWidget = ({ id, value, onChange, label, schema, required }) => { description={description} required={required} > - + ); }; @@ -27,6 +41,7 @@ EmailWidget.propTypes = { label: PropTypes.string.isRequired, schema: PropTypes.object.isRequired, required: PropTypes.bool, + readonly: PropTypes.bool.isRequired, }; export { EmailWidget }; diff --git a/frontend/src/components/rjsf-custom-widgets/file-widget/FileWidget.jsx b/frontend/src/components/rjsf-custom-widgets/file-widget/FileWidget.jsx index 4a43ed121..9a43dcaaa 100644 --- a/frontend/src/components/rjsf-custom-widgets/file-widget/FileWidget.jsx +++ b/frontend/src/components/rjsf-custom-widgets/file-widget/FileWidget.jsx @@ -4,7 +4,7 @@ import PropTypes from "prop-types"; import { RjsfWidgetLayout } from "../../../layouts/rjsf-widget-layout/RjsfWidgetLayout.jsx"; -const FileWidget = ({ id, onChange, label, schema, required }) => { +const FileWidget = ({ id, onChange, label, schema, required, readonly }) => { const description = schema?.description || ""; const handleFileChange = (info) => { if (info.file.status === "done") { @@ -19,7 +19,7 @@ const FileWidget = ({ id, onChange, label, schema, required }) => { description={description} required={required} > - + @@ -32,6 +32,7 @@ FileWidget.propTypes = { label: PropTypes.string.isRequired, schema: PropTypes.object.isRequired, required: PropTypes.bool, + readonly: PropTypes.bool.isRequired, }; export { FileWidget }; diff --git a/frontend/src/components/rjsf-custom-widgets/password-widget/PasswordWidget.jsx b/frontend/src/components/rjsf-custom-widgets/password-widget/PasswordWidget.jsx index e7f8f53db..b21d5339a 100644 --- a/frontend/src/components/rjsf-custom-widgets/password-widget/PasswordWidget.jsx +++ b/frontend/src/components/rjsf-custom-widgets/password-widget/PasswordWidget.jsx @@ -3,7 +3,15 @@ import PropTypes from "prop-types"; import { RjsfWidgetLayout } from "../../../layouts/rjsf-widget-layout/RjsfWidgetLayout.jsx"; -const PasswordWidget = ({ id, value, onChange, label, schema, required }) => { +const PasswordWidget = ({ + id, + value, + onChange, + label, + schema, + required, + readonly, +}) => { const description = schema?.description || ""; const handlePasswordChange = (event) => { onChange(event.target.value); @@ -15,7 +23,12 @@ const PasswordWidget = ({ id, value, onChange, label, schema, required }) => { description={description} required={required} > - + ); }; @@ -27,6 +40,7 @@ PasswordWidget.propTypes = { label: PropTypes.string.isRequired, schema: PropTypes.object.isRequired, required: PropTypes.bool, + readonly: PropTypes.bool.isRequired, }; export { PasswordWidget }; diff --git a/frontend/src/components/rjsf-custom-widgets/select-widget/SelectWidget.jsx b/frontend/src/components/rjsf-custom-widgets/select-widget/SelectWidget.jsx index 49af88ee7..6540dfdab 100644 --- a/frontend/src/components/rjsf-custom-widgets/select-widget/SelectWidget.jsx +++ b/frontend/src/components/rjsf-custom-widgets/select-widget/SelectWidget.jsx @@ -1,10 +1,12 @@ import { Form, Select, Space, Typography } from "antd"; import PropTypes from "prop-types"; + import CustomMarkdown from "../../helpers/custom-markdown/CustomMarkdown"; const { Option } = Select; const SelectWidget = (props) => { - const { id, value, options, onChange, label, schema, rawErrors } = props; + const { id, value, options, onChange, label, schema, rawErrors, readonly } = + props; const description = schema?.description || ""; const handleSelectChange = (selectedValue) => { @@ -22,6 +24,7 @@ const SelectWidget = (props) => { value={value} onChange={handleSelectChange} showSearch + disabled={readonly} > {options?.enumOptions && options.enumOptions.map((option, index) => ( @@ -51,6 +54,7 @@ SelectWidget.propTypes = { rawErrors: PropTypes.array, label: PropTypes.string.isRequired, schema: PropTypes.object.isRequired, + readonly: PropTypes.bool.isRequired, }; export { SelectWidget }; diff --git a/frontend/src/components/rjsf-custom-widgets/text-widget/TextWidget.jsx b/frontend/src/components/rjsf-custom-widgets/text-widget/TextWidget.jsx index 6951b7c64..30017f32b 100644 --- a/frontend/src/components/rjsf-custom-widgets/text-widget/TextWidget.jsx +++ b/frontend/src/components/rjsf-custom-widgets/text-widget/TextWidget.jsx @@ -4,7 +4,7 @@ import PropTypes from "prop-types"; import { RjsfWidgetLayout } from "../../../layouts/rjsf-widget-layout/RjsfWidgetLayout.jsx"; const TextWidget = (props) => { - const { id, value, onChange, label, schema, required } = props; + const { id, value, onChange, label, schema, required, readonly } = props; const description = schema?.description || ""; const handleTextChange = (event) => { onChange(event.target.value); @@ -16,7 +16,12 @@ const TextWidget = (props) => { description={description} required={required} > - + ); }; @@ -28,6 +33,7 @@ TextWidget.propTypes = { label: PropTypes.string.isRequired, schema: PropTypes.object.isRequired, required: PropTypes.bool, + readonly: PropTypes.bool.isRequired, }; export { TextWidget }; diff --git a/frontend/src/components/rjsf-custom-widgets/time-widget/TimeWidget.jsx b/frontend/src/components/rjsf-custom-widgets/time-widget/TimeWidget.jsx index bad749ffa..81c371c76 100644 --- a/frontend/src/components/rjsf-custom-widgets/time-widget/TimeWidget.jsx +++ b/frontend/src/components/rjsf-custom-widgets/time-widget/TimeWidget.jsx @@ -4,7 +4,15 @@ import PropTypes from "prop-types"; import { RjsfWidgetLayout } from "../../../layouts/rjsf-widget-layout/RjsfWidgetLayout.jsx"; -const TimeWidget = ({ id, value, onChange, label, schema, required }) => { +const TimeWidget = ({ + id, + value, + onChange, + label, + schema, + required, + readonly, +}) => { const description = schema?.description || ""; const handleTimeChange = (time) => { onChange(time?.toISOString()); @@ -20,6 +28,7 @@ const TimeWidget = ({ id, value, onChange, label, schema, required }) => { id={id} value={value ? moment(value) : null} onChange={handleTimeChange} + disabled={readonly} /> ); @@ -32,6 +41,7 @@ TimeWidget.propTypes = { label: PropTypes.string.isRequired, schema: PropTypes.object.isRequired, required: PropTypes.bool, + readonly: PropTypes.bool.isRequired, }; export { TimeWidget }; diff --git a/frontend/src/components/rjsf-custom-widgets/up-down-widget/UpDownWidget.jsx b/frontend/src/components/rjsf-custom-widgets/up-down-widget/UpDownWidget.jsx index 23f0cf8e8..e33f8b0ae 100644 --- a/frontend/src/components/rjsf-custom-widgets/up-down-widget/UpDownWidget.jsx +++ b/frontend/src/components/rjsf-custom-widgets/up-down-widget/UpDownWidget.jsx @@ -3,7 +3,15 @@ import PropTypes from "prop-types"; import { RjsfWidgetLayout } from "../../../layouts/rjsf-widget-layout/RjsfWidgetLayout.jsx"; -const UpDownWidget = ({ id, value, onChange, label, schema, required }) => { +const UpDownWidget = ({ + id, + value, + onChange, + label, + schema, + required, + readonly, +}) => { const description = schema?.description || ""; const handleNumberChange = (numberValue) => { onChange(numberValue); @@ -15,7 +23,12 @@ const UpDownWidget = ({ id, value, onChange, label, schema, required }) => { description={description} required={required} > - + ); }; @@ -27,6 +40,7 @@ UpDownWidget.propTypes = { label: PropTypes.string.isRequired, schema: PropTypes.object.isRequired, required: PropTypes.bool, + readonly: PropTypes.bool.isRequired, }; export { UpDownWidget }; diff --git a/frontend/src/components/rjsf-custom-widgets/url-widget/URLWidget.jsx b/frontend/src/components/rjsf-custom-widgets/url-widget/URLWidget.jsx index ab1425713..4b501203e 100644 --- a/frontend/src/components/rjsf-custom-widgets/url-widget/URLWidget.jsx +++ b/frontend/src/components/rjsf-custom-widgets/url-widget/URLWidget.jsx @@ -1,9 +1,10 @@ import { Input } from "antd"; import PropTypes from "prop-types"; + import { RjsfWidgetLayout } from "../../../layouts/rjsf-widget-layout/RjsfWidgetLayout"; const URLWidget = (props) => { - const { id, value, onChange, label, schema, required } = props; + const { id, value, onChange, label, schema, required, readonly } = props; const description = schema?.description || ""; const handleURLChange = (event) => { onChange(event.target.value); @@ -15,7 +16,13 @@ const URLWidget = (props) => { description={description} required={required} > - + ); }; @@ -27,6 +34,7 @@ URLWidget.propTypes = { label: PropTypes.string.isRequired, schema: PropTypes.object.isRequired, required: PropTypes.bool, + readonly: PropTypes.bool.isRequired, }; export { URLWidget }; diff --git a/frontend/src/components/settings/invite/InviteEditUser.jsx b/frontend/src/components/settings/invite/InviteEditUser.jsx index e533063eb..f8d5e3fee 100644 --- a/frontend/src/components/settings/invite/InviteEditUser.jsx +++ b/frontend/src/components/settings/invite/InviteEditUser.jsx @@ -12,6 +12,7 @@ import { TopBar } from "../../widgets/top-bar/TopBar.jsx"; import "./InviteEditUser.css"; import { useExceptionHandler } from "../../../hooks/useExceptionHandler.jsx"; import usePostHogEvents from "../../../hooks/usePostHogEvents.js"; +import { homePagePath } from "../../../helpers/GetStaticData.js"; function InviteEditUser() { const axiosPrivate = useAxiosPrivate(); @@ -145,7 +146,7 @@ function InviteEditUser() { useEffect(() => { if (!isInvite && !location.state) { - navigate(`/${sessionDetails?.orgName}/tools`); + navigate(`/${sessionDetails?.orgName}/${homePagePath}`); } getUserRoles(); }, []); diff --git a/frontend/src/components/widgets/spinner-loader/SpinnerLoader.css b/frontend/src/components/widgets/spinner-loader/SpinnerLoader.css index 113372065..ba9d75887 100644 --- a/frontend/src/components/widgets/spinner-loader/SpinnerLoader.css +++ b/frontend/src/components/widgets/spinner-loader/SpinnerLoader.css @@ -1,23 +1,17 @@ /* Styles for SpinnerLoader */ -.spinner-loader-layout { - display: flex; - width: 100%; - height: 100%; -} - .spinner-loader-layout .ant-spin-dot-item { - background-color: #FFB400 !important; /* Change the color of the first dot */ + background-color: #ffb400 !important; /* Change the color of the first dot */ } .spinner-loader-layout .ant-spin-dot-item:nth-child(2) { - background-color: #00A6ED !important; /* Change the color of the second dot */ + background-color: #00a6ed !important; /* Change the color of the second dot */ } .spinner-loader-layout .ant-spin-dot-item:nth-child(3) { - background-color: #7FB800 !important; /* Change the color of the third dot */ + background-color: #7fb800 !important; /* Change the color of the third dot */ } .spinner-loader-layout .ant-spin-dot-item:nth-child(4) { - background-color: #FF4D6D !important; /* Change the color of the fourth dot */ + background-color: #ff4d6d !important; /* Change the color of the fourth dot */ } diff --git a/frontend/src/components/widgets/spinner-loader/SpinnerLoader.jsx b/frontend/src/components/widgets/spinner-loader/SpinnerLoader.jsx index a7b290627..27d57bdc5 100644 --- a/frontend/src/components/widgets/spinner-loader/SpinnerLoader.jsx +++ b/frontend/src/components/widgets/spinner-loader/SpinnerLoader.jsx @@ -18,12 +18,14 @@ function SpinnerLoader({ align = "center", }) { return ( -
- +
+
+ +
); } diff --git a/frontend/src/helpers/GetSessionData.js b/frontend/src/helpers/GetSessionData.js index 5ee6b9291..baed64a49 100644 --- a/frontend/src/helpers/GetSessionData.js +++ b/frontend/src/helpers/GetSessionData.js @@ -20,7 +20,6 @@ function getSessionData(sessionData) { isAdmin: sessionData.isAdmin, adapters: sessionData?.adapters, logEventsId: sessionData?.logEventsId, - remainingTrialDays: sessionData?.remainingTrialDays, allOrganization: sessionData?.allOrganization, isPlatformAdmin: sessionData?.isPlatformAdmin, loginOnboardingMessage: sessionData?.loginOnboardingMessage, diff --git a/frontend/src/helpers/GetStaticData.js b/frontend/src/helpers/GetStaticData.js index 1fcf4fece..e75e1e560 100644 --- a/frontend/src/helpers/GetStaticData.js +++ b/frontend/src/helpers/GetStaticData.js @@ -2,6 +2,14 @@ import moment from "moment"; import momentTz from "moment-timezone"; import { v4 as uuidv4 } from "uuid"; +let cloudHomePagePath; +try { + cloudHomePagePath = + require("../plugins/unstract-subscription/helper/constants").cloudHomePagePath; +} catch (err) { + // Ignore if plugin not available +} + const THEME = { DARK: "dark", LIGHT: "light", @@ -565,6 +573,10 @@ const generateCoverageKey = (promptId, profileId) => { return `coverage_${promptId}_${profileId}`; }; +const TRIAL_PLAN = "TRIAL"; + +const homePagePath = cloudHomePagePath || "tools"; + export { CONNECTOR_TYPE_MAP, O_AUTH_PROVIDERS, @@ -616,4 +628,6 @@ export { generateApiRunStatusId, base64toBlobWithMime, generateCoverageKey, + TRIAL_PLAN, + homePagePath, }; diff --git a/frontend/src/hooks/useExceptionHandler.jsx b/frontend/src/hooks/useExceptionHandler.jsx index c9472015c..94ceb071e 100644 --- a/frontend/src/hooks/useExceptionHandler.jsx +++ b/frontend/src/hooks/useExceptionHandler.jsx @@ -51,7 +51,7 @@ const useExceptionHandler = () => { } break; case "subscription_error": - navigate("/trial-expired"); + navigate("/subscription-expired"); return { title: title, type: "error", diff --git a/frontend/src/hooks/useRequestUrl.js b/frontend/src/hooks/useRequestUrl.js new file mode 100644 index 000000000..1bb202f2f --- /dev/null +++ b/frontend/src/hooks/useRequestUrl.js @@ -0,0 +1,16 @@ +import { useSessionStore } from "../store/session-store"; + +const useRequestUrl = () => { + const { sessionDetails } = useSessionStore(); + + const getUrl = (url) => { + if (!url) return null; + + const baseUrl = `/api/v1/${sessionDetails?.orgId}/`; + return baseUrl + url.replace(/^\//, ""); + }; + + return { getUrl }; +}; + +export default useRequestUrl; diff --git a/frontend/src/hooks/useUserSession.js b/frontend/src/hooks/useUserSession.js index de8782da2..0ba0d1956 100644 --- a/frontend/src/hooks/useUserSession.js +++ b/frontend/src/hooks/useUserSession.js @@ -24,7 +24,7 @@ const useUserSession = () => { } if (error?.response?.data?.type === "subscription_error") { - navigate("/trial-expired"); + navigate("/subscription-expired"); return; } diff --git a/frontend/src/index.css b/frontend/src/index.css index 49221c103..65d62801d 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -15,6 +15,10 @@ body { min-width: 1024px; } +.page-bg-2 { + background-color: var(--page-bg-2); +} + .center { display: grid; width: inherit; diff --git a/frontend/src/routes/Router.jsx b/frontend/src/routes/Router.jsx index e2936ec54..08c9dd2cb 100644 --- a/frontend/src/routes/Router.jsx +++ b/frontend/src/routes/Router.jsx @@ -19,9 +19,9 @@ let SimplePromptStudioHelper; let SimplePromptStudio; let SpsLanding; let SpsUpload; -let TrialRoutes; let PaymentSuccessful; let SelectProduct; +let UnstractSubscriptionEndPage; try { SimplePromptStudioHelper = require("../plugins/simple-prompt-studio/SimplePromptStudioHelper.jsx").SimplePromptStudioHelper; @@ -57,8 +57,8 @@ try { } try { - TrialRoutes = - require("../plugins/subscription/trial-page/TrialEndPage.jsx").TrialEndPage; + UnstractSubscriptionEndPage = + require("../plugins/unstract-subscription/pages/UnstractSubscriptionEndPage.jsx").UnstractSubscriptionEndPage; } catch (err) { // Do nothing, Not-found Page will be triggered. } @@ -116,14 +116,17 @@ function Router() { {SelectProduct && ( } /> )} - {TrialRoutes && ( - } /> + {UnstractSubscriptionEndPage && ( + } + /> )} {PaymentSuccessful && ( } /> )} }> - {MainAppRoute} + {MainAppRoute} {llmWhispererRouter && ( {llmWhispererRouter()} )} diff --git a/frontend/src/routes/useMainAppRoutes.js b/frontend/src/routes/useMainAppRoutes.js index 039591f29..f77e96ad5 100644 --- a/frontend/src/routes/useMainAppRoutes.js +++ b/frontend/src/routes/useMainAppRoutes.js @@ -32,6 +32,9 @@ let PRODUCT_NAMES = {}; let ManualReviewPage; let SimpleManualReviewPage; let ReviewLayout; +let UnstractUsagePage; +let UnstractSubscriptionPage; +let UnstractSubscriptionCheck; try { RequirePlatformAdmin = @@ -62,7 +65,7 @@ try { try { OnboardProduct = - require("../plugins/llm-whisperer/components/onboard-product/OnboardProduct.jsx").OnboardProduct; + require("../plugins/onboard-product/OnboardProduct.jsx").OnboardProduct; PRODUCT_NAMES = require("../plugins/llm-whisperer/helper.js").PRODUCT_NAMES; } catch (err) { // Do nothing. @@ -79,6 +82,17 @@ try { // Do nothing, Not-found Page will be triggered. } +try { + UnstractSubscriptionPage = + require("../plugins/unstract-subscription/pages/UnstractSubscriptionPage.jsx").UnstractSubscriptionPage; + UnstractUsagePage = + require("../plugins/unstract-subscription/pages/UnstractUsagePage.jsx").UnstractUsagePage; + UnstractSubscriptionCheck = + require("../plugins/unstract-subscription/components/UnstractSubscriptionCheck.jsx").UnstractSubscriptionCheck; +} catch (err) { + // Do nothing, Not-found Page will be triggered. +} + function useMainAppRoutes() { const routes = ( <> @@ -91,6 +105,12 @@ function useMainAppRoutes() { )} }> + {UnstractUsagePage && ( + } /> + )} + {UnstractSubscriptionPage && ( + } /> + )} } /> } > - {routes} + }> + {routes} + ); } else {