Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/mrq deployments #651

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions backend/pipeline/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from django.conf import settings
from django.db import connection, models
from utils.models.base_model import BaseModel
from workflow_manager.endpoint.models import WorkflowEndpoint
from workflow_manager.workflow.models.workflow import Workflow

from backend.constants import FieldLengthConstants as FieldLength
Expand Down Expand Up @@ -93,7 +94,17 @@ def api_key_data(self):
def api_endpoint(self):
org_schema = connection.get_tenant().schema_name
deployment_endpoint = settings.API_DEPLOYMENT_PATH_PREFIX + "/pipeline/api"

# Check if the WorkflowEndpoint has a connection_type of MANUALREVIEW
workflow_endpoint = WorkflowEndpoint.objects.filter(
workflow=self.workflow,
connection_type=WorkflowEndpoint.ConnectionType.MANUALREVIEW,
).first()
api_endpoint = f"{deployment_endpoint}/{org_schema}/{self.id}/"
if workflow_endpoint:
deployment_endpoint = f"mr/api/{org_schema}/approved/result"
api_endpoint = f"{deployment_endpoint}/{self.workflow_id}/"

return api_endpoint

def __str__(self) -> str:
Expand Down
28 changes: 27 additions & 1 deletion backend/pipeline/views.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import json
import logging
from typing import Optional
from typing import Any, Optional

from account.custom_exceptions import DuplicateData
from api.exceptions import NoActiveAPIKeyError
Expand Down Expand Up @@ -36,6 +36,8 @@ class PipelineViewSet(viewsets.ModelViewSet):
def get_queryset(self) -> Optional[QuerySet]:
type = self.request.query_params.get(PipelineConstants.TYPE)
if type is not None:
if type == "MRQ":
type = "ETL"
queryset = Pipeline.objects.filter(
created_by=self.request.user, pipeline_type=type
)
Expand All @@ -50,6 +52,30 @@ def get_serializer_class(self) -> serializers.Serializer:
else:
return PipelineSerializer

def list(self, request: Request, *args: Any, **kwargs: Any) -> Response:
queryset = self.get_queryset()
serializer = self.get_serializer(queryset, many=True)
data = serializer.data

# Check if the request is for 'MRQ'
etl_type = request.query_params.get(PipelineConstants.TYPE)
if etl_type == "MRQ":
# Filter the data based on 'destination_name'
filtered_data = [
item for item in data if item["destination_name"] == "Manual Review"
]
return Response(filtered_data)

if etl_type == "ETL":
# Filter the data to exclude those with
# 'destination_name' == "Manual Review"
filtered_data = [
item for item in data if item["destination_name"] != "Manual Review"
]
return Response(filtered_data)
# If 'type' is not 'MRQ', return the default list
return super().list(request, *args, **kwargs)

# TODO: Refactor to perform an action with explicit arguments
# For eg, passing pipeline ID and with_log=False -> executes pipeline
# For FE however we call the same API twice
Expand Down
13 changes: 6 additions & 7 deletions frontend/src/components/agency/actions/Actions.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ function Actions({ statusBarMsg, initializeWfComp, stepLoader }) {
const axiosPrivate = useAxiosPrivate();
const { posthogWfDeploymentEventText, setPostHogCustomEvent } =
usePostHogEvents();

const isManualReview = destination?.connection_type === "MANUALREVIEW";
useEffect(() => {
// Enable Deploy as API only when
// Source & Destination connection_type are selected as API
Expand All @@ -84,7 +84,7 @@ function Actions({ statusBarMsg, initializeWfComp, stepLoader }) {
source?.connector_instance &&
((destination?.connection_type === "DATABASE" &&
destination.connector_instance) ||
destination.connection_type === "MANUALREVIEW")
isManualReview)
);
}, [source, destination]);
useEffect(() => {
Expand Down Expand Up @@ -307,10 +307,7 @@ function Actions({ statusBarMsg, initializeWfComp, stepLoader }) {
) {
return false;
}
if (
source?.connection_type === "FILESYSTEM" &&
destination?.connection_type === "MANUALREVIEW"
) {
if (source?.connection_type === "FILESYSTEM" && isManualReview) {
return false;
}
return !source?.connector_instance || !destination?.connector_instance;
Expand Down Expand Up @@ -497,7 +494,9 @@ function Actions({ statusBarMsg, initializeWfComp, stepLoader }) {
<ApiOutlined />
</Button>
</Tooltip>
<Tooltip title="Deploy as ETL Pipeline">
<Tooltip
title={`Deploy as ${isManualReview ? "MRQ" : ""} ETL Pipeline`}
>
<Button
disabled={isIncompleteWorkflow() || !canAddETLPipeline}
onClick={() => handleDeployBtnClick("ETL")}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import PropTypes from "prop-types";
import {
CodeOutlined,
CopyOutlined,
Expand Down Expand Up @@ -30,7 +31,7 @@ import { useAxiosPrivate } from "../../../hooks/useAxiosPrivate.js";
import usePipelineHelper from "../../../hooks/usePipelineHelper.js";
import { NotificationModal } from "../../pipelines-or-deployments/notification-modal/NotificationModal.jsx";

function ApiDeployment() {
function ApiDeployment({ type }) {
const { sessionDetails } = useSessionStore();
const { setAlertDetails } = useAlertStore();
const navigate = useNavigate();
Expand Down Expand Up @@ -378,7 +379,7 @@ function ApiDeployment() {
return (
<>
<Layout
type="api"
type={type}
columns={columns}
tableData={tableData}
isTableLoading={isTableLoading}
Expand Down Expand Up @@ -432,4 +433,8 @@ function ApiDeployment() {
);
}

ApiDeployment.propTypes = {
type: PropTypes.string.isRequired,
};

export { ApiDeployment };
11 changes: 10 additions & 1 deletion frontend/src/components/navigations/side-nav-bar/SideNavBar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,19 @@ import TextExtractorIcon from "../../../assets/text-extractor.svg";
import { useSessionStore } from "../../../store/session-store";

let getMenuItem;
let getMRQMenuItem;
try {
getMenuItem = require("../../../plugins/app-deployment/getMenuItem");
} catch (err) {
// Plugin unavailable.
}

try {
getMRQMenuItem = require("../../../plugins/manual-review/getMenuItem");
} catch (err) {
// Plugin unavailable.
}

const SideNavBar = ({ collapsed }) => {
const navigate = useNavigate();
const { sessionDetails } = useSessionStore();
Expand Down Expand Up @@ -147,7 +154,9 @@ const SideNavBar = ({ collapsed }) => {
if (getMenuItem && flags.app_deployment) {
data[0].subMenu.splice(1, 0, getMenuItem.default(orgName));
}

if (getMRQMenuItem) {
data[0].subMenu.splice(3, 0, getMRQMenuItem.default(orgName));
}
return (
<Sider
trigger={null}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,17 +108,11 @@ const EtlTaskDeploy = ({
return [];
});
const getWorkflows = () => {
const connectorType = type === "task" ? "FILESYSTEM" : "DATABASE";
let connectorType = type === "task" ? "FILESYSTEM" : "DATABASE";
connectorType = type === "mrq" ? "MANUALREVIEW" : connectorType;
setWorkflowList([]);
fetchWorkflows(connectorType).then((data) => {
if (connectorType === "DATABASE") {
fetchWorkflows("MANUALREVIEW").then((manualReviewData) => {
const combinedData = [...data, ...manualReviewData];
setWorkflowList(combinedData);
});
} else {
setWorkflowList(data);
}
setWorkflowList(data);
});
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useAxiosPrivate } from "../../hooks/useAxiosPrivate";
import { useSessionStore } from "../../store/session-store";

function pipelineService() {
function pipelineService(mrq = false) {
const axiosPrivate = useAxiosPrivate();
const { sessionDetails } = useSessionStore();
const path = `/api/v1/unstract/${sessionDetails?.orgId.replaceAll('"', "")}`;
Expand All @@ -14,34 +14,46 @@ function pipelineService() {

return {
getApiKeys: (id) => {
const basePipelineUrl = mrq
? `${path}/manual_review/api/keys/`
: `${path}/api/keys/pipeline/${id}/`;
const requestOptions = {
url: `${path}/api/keys/pipeline/${id}/`,
url: basePipelineUrl,
method: "GET",
};
return axiosPrivate(requestOptions);
},
createApiKey: (apiId, record) => {
const basePipelineUrl = mrq
? `${path}/manual_review/api/key/`
: `${path}/api/keys/pipeline/${apiId}/`;
const requestOptions = {
method: "POST",
url: `${path}/api/keys/pipeline/${apiId}/`,
url: basePipelineUrl,
headers: requestHeaders,
data: record,
};
return axiosPrivate(requestOptions);
},
updateApiKey: (keyId, record) => {
const basePipelineUrl = mrq
? `${path}/manual_review/api/key/${keyId}/`
: `${path}/api/keys/${keyId}/`;
const requestOptions = {
method: "PUT",
url: `${path}/api/keys/${keyId}/`,
method: mrq ? "PATCH" : "PUT",
url: basePipelineUrl,
headers: requestHeaders,
data: record,
};
return axiosPrivate(requestOptions);
},
deleteApiKey: (keyId) => {
const basePipelineUrl = mrq
? `${path}/manual_review/api/key/${keyId}/`
: `${path}/api/keys/${keyId}/`;
const requestOptions = {
method: "DELETE",
url: `${path}/api/keys/${keyId}/`,
url: basePipelineUrl,
headers: requestHeaders,
};
return axiosPrivate(requestOptions);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ function Pipelines({ type }) {
const { fetchExecutionLogs } = require("../log-modal/fetchExecutionLogs.js");
const [openManageKeysModal, setOpenManageKeysModal] = useState(false);
const [apiKeys, setApiKeys] = useState([]);
const pipelineApiService = pipelineService();
const pipelineApiService = pipelineService(type === "mrq");
const { getApiKeys, downloadPostmanCollection, copyUrl } =
usePipelineHelper();
const [openNotificationModal, setOpenNotificationModal] = useState(false);
Expand Down
5 changes: 5 additions & 0 deletions frontend/src/helpers/GetStaticData.js
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,11 @@ const deploymentsStaticContent = {
addBtn: "App Deployment",
isLogsRequired: false,
},
mrq: {
title: "MRQ Deployments",
addBtn: "MRQ Deployment",
isLogsRequired: false,
},
};

const endpointType = {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/pages/DeploymentsPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Pipelines } from "../components/pipelines-or-deployments/pipelines/Pipe

function DeploymentsPage({ type }) {
if (type === "api") {
return <ApiDeployment />;
return <ApiDeployment type="api" />;
} else {
return <Pipelines type={type} />;
}
Expand Down
9 changes: 9 additions & 0 deletions frontend/src/routes/Router.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ let ManualReviewPage;
let ReviewLayout;
let PublicPromptStudioHelper;
let ManualReviewSettings;
let ManualReviewDeployment;

try {
TrialRoutes =
Expand Down Expand Up @@ -69,6 +70,8 @@ try {
require("../plugins/manual-review/review-layout/ReviewLayout.jsx").ReviewLayout;
ManualReviewSettings =
require("../plugins/manual-review/settings/Settings.jsx").ManualReviewSettings;
ManualReviewDeployment =
require("../plugins/manual-review/components/deployment/ManualReviewDeployment.jsx").ManualReviewDeployment;
} catch (err) {
// Do nothing, Not-found Page will be triggered.
}
Expand Down Expand Up @@ -163,6 +166,12 @@ function Router() {
{AppDeployments && (
<Route path="app" element={<AppDeployments type="app" />} />
)}
{ManualReviewDeployment && (
<Route
path="mrq"
element={<ManualReviewDeployment type="mrq" />}
/>
)}
<Route path="workflows" element={<WorkflowsPage />} />
<Route path="workflows/:id" element={<ProjectHelper />}>
<Route path="" element={<AgencyPage />} />
Expand Down
Loading