From 104a82bbcd10518a0aa4eccca813c61d84e7dd9c Mon Sep 17 00:00:00 2001
From: Tahier Hussain <89440263+tahierhussain@users.noreply.github.com>
Date: Thu, 23 Jan 2025 16:30:59 +0530
Subject: [PATCH 1/2] FEAT: Unstract Payment Integration (FE) (#1053)
* Implemented changes related to unstract subscription
* Have different home pages for OSS and Cloud
* Renamed the unstract subscription pages and replaced '<>>' with ''
* Updated import path of the TrialDaysInfo component
* Implemented the to structure the API path
* Rearranged the onboard and subscription check APIs
---------
Co-authored-by: Jaseem Jas <89440144+jaseemjaskp@users.noreply.github.com>
---
.../components/helpers/auth/RequireAuth.js | 3 +-
.../components/helpers/auth/RequireGuest.js | 8 +-
.../navigations/side-nav-bar/SideNavBar.jsx | 16 +-
.../navigations/top-nav-bar/TopNavBar.jsx | 352 ++++++++++--------
frontend/src/components/onboard/OnBoard.jsx | 4 +-
.../settings/invite/InviteEditUser.jsx | 3 +-
.../widgets/spinner-loader/SpinnerLoader.css | 14 +-
.../widgets/spinner-loader/SpinnerLoader.jsx | 14 +-
frontend/src/helpers/GetSessionData.js | 1 -
frontend/src/helpers/GetStaticData.js | 14 +
frontend/src/hooks/useExceptionHandler.jsx | 2 +-
frontend/src/hooks/useRequestUrl.js | 16 +
frontend/src/hooks/useUserSession.js | 2 +-
frontend/src/index.css | 4 +
frontend/src/routes/Router.jsx | 15 +-
frontend/src/routes/useMainAppRoutes.js | 26 +-
16 files changed, 296 insertions(+), 198 deletions(-)
create mode 100644 frontend/src/hooks/useRequestUrl.js
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/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}
-
- ) : (
-
+ setAlertDetails({
+ type: "error",
+ content: `You are already in ${org?.display_name}`,
+ })
+ }
+ >
+ {org?.display_name}
+
+ ) : (
+
-
+
);
}
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 {
From 89697c41c9c876fa8a607a5d53c60041d4b4d7ff Mon Sep 17 00:00:00 2001
From: Tahier Hussain <89440263+tahierhussain@users.noreply.github.com>
Date: Thu, 23 Jan 2025 16:31:44 +0530
Subject: [PATCH 2/2] FEAT: Add readonly support for custom RJSF widgets and
transform LLMWhisperer v2 JSON schema form for cloud (#1059)
* Support 'readonly' parameter for all custom RJSF widgets
* Transform the JSON schema for the LLM Whisperer V2 adapter for cloud
* Fixed Eslint issues
* Code quality improvement
* Allow JSON schema transform for LLMW V2 only for paid plan users
* Allow JSON schema transform for LLMW V2 only for paid plan users
* Fix sonar issue
---------
Co-authored-by: vishnuszipstack <117254672+vishnuszipstack@users.noreply.github.com>
Co-authored-by: Jaseem Jas <89440144+jaseemjaskp@users.noreply.github.com>
---
.../input-output/add-source/AddSource.jsx | 37 ++++++++++++++++++-
.../AltDateTimeWidget.jsx | 6 ++-
.../alt-date-widget/AltDateWidget.jsx | 5 ++-
.../array-field/ArrayField.jsx | 4 +-
.../checkbox-widget/CheckboxWidget.jsx | 19 +++++++++-
.../checkboxes-widget/CheckboxesWidget.jsx | 3 ++
.../color-widget/ColorWidget.jsx | 19 +++++++++-
.../date-time-widget/DateTimeWidget.jsx | 12 +++++-
.../date-widget/DateWidget.jsx | 12 +++++-
.../email-widget/EmailWidget.jsx | 19 +++++++++-
.../file-widget/FileWidget.jsx | 5 ++-
.../password-widget/PasswordWidget.jsx | 18 ++++++++-
.../select-widget/SelectWidget.jsx | 6 ++-
.../text-widget/TextWidget.jsx | 10 ++++-
.../time-widget/TimeWidget.jsx | 12 +++++-
.../up-down-widget/UpDownWidget.jsx | 18 ++++++++-
.../url-widget/URLWidget.jsx | 12 +++++-
17 files changed, 193 insertions(+), 24 deletions(-)
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/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}
>
-
+
}>Upload File
@@ -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 };