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

poc: paragon init #37063

Closed
wants to merge 13 commits into from
Closed
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions app/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@
"@uppy/url": "^1.5.16",
"@uppy/utils": "^6.0.2",
"@uppy/webcam": "^1.8.4",
"@useparagon/connect": "^1.0.18",
"@welldone-software/why-did-you-render": "^4.2.5",
"acorn": "8.10.0",
"acorn-walk": "8.2.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,11 @@ const QueryResponseTab = (props: Props) => {
// Pass the error to be shown in the error tab
error = actionResponse.readableError
? getErrorAsString(actionResponse.readableError)
: getErrorAsString(actionResponse.body);
: getErrorAsString(
(actionResponse.body as any)?.message
? (actionResponse.body as any).message
: actionResponse.body,
);
} else if (isString(actionResponse.body)) {
//reset error.
error = "";
Expand Down Expand Up @@ -278,7 +282,10 @@ const QueryResponseTab = (props: Props) => {
</>
) : (
actionResponse.body && (
<div data-testid="t--query-error">{actionResponse.body}</div>
<div data-testid="t--query-error">
{(actionResponse.body as any).message ||
actionResponse.body}
</div>
)
))}
<LogHelper
Expand Down
17 changes: 16 additions & 1 deletion app/client/src/ce/api/WorkspaceApi.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import type { AxiosProgressEvent, AxiosPromise } from "axios";
import Api from "api/Api";
import type { ApiResponse } from "api/ApiResponses";
import type { WorkspaceRole, Workspace } from "ee/constants/workspaceConstants";
import type {
WorkspaceRole,
Workspace,
WorkspaceToken,
} from "ee/constants/workspaceConstants";

export interface FetchWorkspacesResponse extends ApiResponse {
data: Workspace[];
Expand All @@ -18,6 +22,10 @@ export interface FetchAllRolesResponse extends ApiResponse {
data: Workspace[];
}

export interface FetchWorkspaceTokenResponse extends ApiResponse {
data: WorkspaceToken;
}

export interface FetchWorkspaceRequest {
workspaceId: string;
skipValidation?: boolean;
Expand Down Expand Up @@ -147,5 +155,12 @@ class WorkspaceApi extends Api {
): Promise<AxiosPromise<ApiResponse>> {
return Api.delete(`${WorkspaceApi.workspacesURL}/${workspaceId}`);
}
static async fetchWorkspaceToken(
request: FetchWorkspaceRequest,
): Promise<AxiosPromise<FetchWorkspaceTokenResponse>> {
return Api.get(
WorkspaceApi.workspacesURL + "/" + request.workspaceId + "/token",
);
}
}
export default WorkspaceApi;
8 changes: 7 additions & 1 deletion app/client/src/ce/constants/workspaceConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export interface WorkspaceRole {
isDefault?: boolean;
}

export interface Workspace {
export interface Workspace extends WorkspaceToken {
id: string;
name: string;
website?: string;
Expand Down Expand Up @@ -37,6 +37,12 @@ export interface WorkspaceUser {
roles: WorkspaceUserRoles[];
}

export interface WorkspaceToken {
workspaceId?: string;
token?: string;
projectId?: string;
}

export enum ENTITY_TYPE {
WORKSPACE = "Workspace",
APPLICATION = "Application",
Expand Down
11 changes: 10 additions & 1 deletion app/client/src/ce/sagas/WorkspaceSagas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import type {
FetchAllRolesRequest,
SaveWorkspaceLogo,
FetchWorkspacesResponse,
FetchWorkspaceTokenResponse,
} from "ee/api/WorkspaceApi";
import WorkspaceApi from "ee/api/WorkspaceApi";
import type { ApiResponse } from "api/ApiResponses";
Expand Down Expand Up @@ -118,10 +119,18 @@ export function* fetchWorkspaceSaga(
const isValidResponse: boolean = yield request.skipValidation ||
validateResponse(response);

const responseToken: FetchWorkspaceTokenResponse = yield call(
WorkspaceApi.fetchWorkspaceToken,
request,
);

if (isValidResponse && response) {
yield put({
type: ReduxActionTypes.FETCH_WORKSPACE_SUCCESS,
payload: response.data || {},
payload: {
...(response.data || {}),
...(responseToken.data || {}),
},
});
}
} catch (error) {
Expand Down
9 changes: 9 additions & 0 deletions app/client/src/ce/utils/autocomplete/EntityDefinitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,15 @@ export const entityDefinitions = {
"https://docs.appsmith.com/reference/appsmith-framework/context-object#geolocationclearwatch",
},
},
datasource: {
"!doc": "Object to enable running custom datasources",
"!url": "",
request: {
"!type":
"fn(requestType: string, apiPath: string, options: object) -> +Promise|void",
"!url": "",
},
},
...eeAppsmithAutocompleteDefs(generatedTypeDef),
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export enum APPSMITH_NAMESPACED_FUNCTIONS {
getGeolocation = "appsmith.geolocation.getCurrentPosition",
watchGeolocation = "appsmith.geolocation.watchPosition",
stopWatchGeolocation = "appsmith.geolocation.clearWatch",
datasourceRequest = "appsmith.datasource.request",
}

export enum APPSMITH_INTEGRATIONS {
Expand Down
20 changes: 20 additions & 0 deletions app/client/src/pages/Editor/APIEditor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useDispatch, useSelector } from "react-redux";
import type { RouteComponentProps } from "react-router";

import {
getDatasource,
getIsActionConverting,
getPageList,
getPluginSettingConfigs,
Expand Down Expand Up @@ -39,6 +40,8 @@ import { ENTITY_ICON_SIZE, EntityIcon } from "../Explorer/ExplorerIcons";
import { getIDEViewMode } from "selectors/ideSelectors";
import { EditorViewMode } from "ee/entities/IDE/constants";
import { AppPluginActionEditor } from "pages/Editor/AppPluginActionEditor";
import { getCurrentEnvironmentId } from "ce/selectors/environmentSelectors";
import QueryEditor from "pages/Editor/QueryEditor";

type ApiEditorWrapperProps = RouteComponentProps<APIEditorRouteParams>;

Expand All @@ -60,6 +63,23 @@ function ApiEditorWrapper(props: ApiEditorWrapperProps) {
const apiName = action?.name || "";
const pluginId = get(action, "pluginId", "");
const datasourceId = action?.datasource.id || "";
if (datasourceId) {
const currentEnvironment = useSelector(getCurrentEnvironmentId);
const datasource = useSelector((state) =>
getDatasource(state, datasourceId),
);
const datasourceConfigurationProps =
datasource?.datasourceStorages?.[currentEnvironment]
?.datasourceConfiguration?.properties;
if (
datasourceConfigurationProps &&
datasourceConfigurationProps.some(
({ key }) => key === "integrationId" || key === "integrationType",
)
) {
return <QueryEditor {...props} />;
}
}
const plugins = useSelector(getPlugins);
const pages = useSelector(getPageList);
const pageName = getPageName(pages, basePageId);
Expand Down
41 changes: 41 additions & 0 deletions app/client/src/pages/Editor/DataSourceEditor/DSFormHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import type { PluginType } from "entities/Action";
import { useEditorType } from "ee/hooks";
import { useHistory } from "react-router";
import { useHeaderActions } from "ee/hooks/datasourceEditorHooks";
import { paragon } from "@useparagon/connect";

export const ActionWrapper = styled.div`
display: flex;
Expand Down Expand Up @@ -172,6 +173,32 @@ export const DSFormHeader = (props: DSFormHeaderProps) => {
showReconnectButton,
});

const onClickConnect = () => {
const datasourceConfigurationProps = (datasource as Datasource)
?.datasourceStorages?.[currentEnv]?.datasourceConfiguration?.properties;

const integrationId =
datasourceConfigurationProps?.find(({ key }) => key === "integrationId")
?.value || "";
const integrationType =
datasourceConfigurationProps?.find(({ key }) => key === "integrationType")
?.value || "";

if (!integrationId || !integrationType) return;

paragon.connect(integrationType, {
// selectedCredentialId: integrationId,
// allowMultipleCredentials: true,
accountType: "default",
onSuccess: (event, user) => {
console.log(event);
},
onError: (err) => {
console.log(err);
},
});
};

return (
<Header noBottomBorder={!!noBottomBorder}>
<FormTitleContainer>
Expand Down Expand Up @@ -232,6 +259,20 @@ export const DSFormHeader = (props: DSFormHeaderProps) => {
{headerActions && headerActions.generatePageButton
? headerActions.generatePageButton
: null}
<Button
className={"t--connect-paragon"}
kind="secondary"
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
onClick={(e: any) => {
e.stopPropagation();
e.preventDefault();
onClickConnect();
}}
size="md"
>
Connect Paragon
</Button>
</ActionWrapper>
)}
</Header>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,20 @@ import { getHasCreateDatasourcePermission } from "ee/utils/BusinessFeatures/perm
import {
getDatasources,
getMockDatasources,
getPlugins,
} from "ee/selectors/entitiesSelector";
import {
getCurrentApplicationId,
getCurrentPageId,
} from "selectors/editorSelectors";
import { connect } from "react-redux";
import { connect, useDispatch, useSelector } from "react-redux";
import type { Datasource, MockDatasource } from "entities/Datasource";
import scrollIntoView from "scroll-into-view-if-needed";
import { Text } from "@appsmith/ads";
import MockDataSources from "./MockDataSources";
import NewApiScreen from "./NewApi";
import NewApiScreen, { ApiCard, CardContentWrapper } from "./NewApi";
import NewQueryScreen from "./NewQuery";
import { isAirgapped } from "ee/utils/airgapHelpers";
import { getAssetUrl, isAirgapped } from "ee/utils/airgapHelpers";
import { showDebuggerFlag } from "selectors/debuggerSelectors";
import {
createMessage,
Expand All @@ -40,6 +41,14 @@ import { useParentEntityInfo } from "ee/hooks/datasourceEditorHooks";
import AIDataSources from "./AIDataSources";
import Debugger from "../DataSourceEditor/Debugger";
import { isPluginActionCreating } from "PluginActionEditor/store";
import { paragon } from "@useparagon/connect";
import AnalyticsUtil from "ee/utils/AnalyticsUtil";
import { useParagonIntegrations } from "utils/paragonHooks";
import { DATASOURCE_NAME_DEFAULT_PREFIX } from "constants/Datasource";
import { ReduxActionTypes } from "ce/constants/ReduxActionConstants";
import { PluginPackageName } from "entities/Action";
import type { Plugin } from "api/PluginApi";
import { getNextEntityName } from "utils/AppsmithUtils";

const NewIntegrationsContainer = styled.div`
${thinScrollbar};
Expand Down Expand Up @@ -174,6 +183,88 @@ function CreateNewDatasource({
);
}

function ParagonIntegrations() {
const { integrations } = useParagonIntegrations();
const dispatch = useDispatch();
const dsList: Datasource[] = useSelector(getDatasources);
const plugins: Plugin[] = useSelector(getPlugins);
const apiPlugin = plugins.find(
(plugin) => plugin.packageName === PluginPackageName.REST_API,
);
const datasourceName = getNextEntityName(
DATASOURCE_NAME_DEFAULT_PREFIX,
dsList.map((el: Datasource) => el.name),
);
const handleOnClick = (type: string) => {
paragon.installIntegration(type, {
allowMultipleCredentials: true,
accountType: "default",
onSuccess: (event, user) => {
console.log(event);
dispatch({
type: ReduxActionTypes.CREATE_DATASOURCE_FROM_FORM_INIT,
payload: {
type: "API",
pluginId: apiPlugin!.id,
datasourceStorages: {
unused_env: {
environmentId: "unused_env",
isValid: false,
datasourceConfiguration: {
url: "https://proxy.useparagon.com",
properties: Object.keys(event).reduce((acc, key) => {
// @ts-expect-error
acc.push({
key: key as string,
// @ts-expect-error
value: event[key] as any,
});
return acc;
}, []),
},
toastMessage: "EMPTY_TOAST_MESSAGE",
},
},
name: datasourceName,
},
});
},
onError: (err) => {
console.log(err);
},
});
};

return (
<>
{integrations.map((integration) => (
<ApiCard
className={`t--create-${integration.type}`}
key={integration.name}
onClick={() => {
AnalyticsUtil.logEvent("CREATE_DATA_SOURCE_CLICK", {
pluginName: integration.name,
pluginPackageName: integration.type,
});
handleOnClick(integration.type);
}}
>
<CardContentWrapper>
<img
alt={integration.name}
className={
"content-icon saasImage t--saas-" + integration.type + "-image"
}
src={getAssetUrl(integration.icon)}
/>
<p className="t--plugin-name textBtn">{integration.name}</p>
</CardContentWrapper>
</ApiCard>
))}
</>
);
}

function CreateNewSaasIntegration({
active,
isCreating,
Expand Down Expand Up @@ -210,7 +301,9 @@ function CreateNewSaasIntegration({
pageId={pageId}
showSaasAPIs
showUnsupportedPluginDialog={showUnsupportedPluginDialog}
/>
>
<ParagonIntegrations />
</NewApiScreen>
</div>
</>
) : null;
Expand Down
Loading
Loading