chore: Updating styles and adding docs link for REST API plugin for better UI/UX (#37941)

## Description

- Adding docs link for REST API plugin
- Updating styles for JS function popover when the name is too long
- Updating styles for response pane
- Removing edit configuration button next to URL for an API, and adding
the datasource tab for API editor as well for a saved API. Also, adding
a new icon button in schema tab (now datasource tab) for editing DS
configuration.

Fixes [#37925](https://github.com/appsmithorg/appsmith/issues/37925) 
Fixes [#37928](https://github.com/appsmithorg/appsmith/issues/37928)
Fixes [#37926](https://github.com/appsmithorg/appsmith/issues/37926)
Fixes [#37927](https://github.com/appsmithorg/appsmith/issues/37927)

## Automation

/ok-to-test tags="@tag.Datasource, @tag.IDE"

### 🔍 Cypress test results
<!-- This is an auto-generated comment: Cypress test results  -->
> [!TIP]
> 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉
> Workflow run:
<https://github.com/appsmithorg/appsmith/actions/runs/12234851157>
> Commit: 925369c4282e6c2c408283be416ffc0f50608e4c
> <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=12234851157&attempt=1"
target="_blank">Cypress dashboard</a>.
> Tags: `@tag.Datasource, @tag.IDE`
> Spec:
> <hr>Mon, 09 Dec 2024 12:28:22 UTC
<!-- end of auto-generated comment: Cypress test results  -->


## Communication
Should the DevRel and Marketing teams inform users about this change?
- [ ] Yes
- [ ] No


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

## Release Notes

- **New Features**
- Introduced a new `Datasource` component, enhancing the management of
datasource configurations.
- Added a new icon, `DatasourceConfigIcon`, to improve visual
representation.
- Implemented a new `DatasourceInfo` component for displaying datasource
details and editing options.
- Added a new `DatasourceSelector` component to streamline datasource
selection based on plugin context.

- **Improvements**
- Updated default tab selection logic to prioritize the `Datasource`
tab.
- Enhanced styling for the `StatusBar` and `StyledSwitchLabel`
components for better UI consistency.
  - Added new access-related messages to the `StatusDisplay` component.
- Refined rendering logic for the `StoreAsDatasource` component to
improve user interaction.

- **Bug Fixes**
- Fixed rendering logic for the debugger tabs to ensure accurate display
based on user interactions.
- Streamlined test logic for the "Edit Datasource" button functionality.

- **Documentation**
  - Updated constant messages for improved clarity and user guidance.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Trisha Anand <trisha@appsmith.com>
Co-authored-by: Hetu Nandu <hetu@appsmith.com>
This commit is contained in:
Ankita Kinger 2024-12-09 18:12:09 +05:30 committed by GitHub
parent cbfe89ef83
commit 26b05343b4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
32 changed files with 303 additions and 61 deletions

View File

@ -17,10 +17,10 @@ describe(
dataSources.FillAuthAPIUrl();
dataSources.SaveDatasource();
apiPage.CreateApi("API" + uid, "GET", true);
agHelper.AssertElementAbsence(apiPage._saveAsDS);
apiPage.SelectPaneTab("Authentication");
agHelper.AssertElementEnabledDisabled(apiPage._saveAsDS, 0, false);
// Last one if present on the authentication tab.
agHelper.AssertElementEnabledDisabled(apiPage._saveAsDS, 1, false);
agHelper.AssertElementEnabledDisabled(apiPage._saveAsDS, 0, false);
});
});
},

View File

@ -305,6 +305,7 @@ describe(
variable: GRAPHQL_VARIABLES,
});
apiPage.RunAPI();
apiPage.SelectPaneTab("Authentication");
agHelper.GetNClick(locators._saveDatasource);
dataSources.AssertDataSourceInfo([
dataManager.dsValues[

View File

@ -206,7 +206,7 @@ export class DataSources {
".t--datasource-name:contains('" + dsName + "')";
_mandatoryMark = "//span[text()='*']";
_deleteDSHostPort = ".t--delete-field";
_dsTabSchema = "[data-testid='t--tab-SCHEMA_TAB']";
_dsTabSchema = "[data-testid='t--tab-DATASOURCE_TAB']";
private _pageSelectionMenu = "[data-testid='t--page-selection']";
private _pageSelectMenuItem = ".ads-v2-menu__menu-item";
@ -1891,7 +1891,9 @@ export class DataSources {
cy.intercept("GET", "/api/v1/datasources/*/structure?ignoreCache=*").as(
`getDatasourceStructureUpdated_${ds_entity_name}`,
);
cy.get("[data-testid=t--tab-SCHEMA_TAB]").first().click({ force: true });
cy.get("[data-testid=t--tab-DATASOURCE_TAB]")
.first()
.click({ force: true });
this.RefreshDatasourceSchema();
this.assertHelper
.WaitForNetworkCall(`@getDatasourceStructureUpdated_${ds_entity_name}`)

View File

@ -1033,6 +1033,10 @@ const DashboardLineIcon = importSvg(
async () => import("../__assets__/icons/ads/dashboard-line.svg"),
);
const DatasourceConfigIcon = importSvg(
async () => import("../__assets__/icons/ads/datasource-config.svg"),
);
// v3 icons
const JsSquareV3Icon = importSvg(
async () => import("../__assets__/icons/ads/js-square-v3-icon.svg"),
@ -1173,6 +1177,7 @@ const ICON_LOOKUP = {
"cut-control": CutIcon,
"dashboard-line": DashboardLineIcon,
"database-2-line": Database2Line,
"datasource-config": DatasourceConfigIcon,
"datasource-v3": DatasourceV3Icon,
"datasources-2": Datasources2,
"decrease-control": DecreaseIcon,

View File

@ -31,6 +31,7 @@ export const StyledSwitchLabel = styled(Text)<{
justify-content: space-between;
min-width: 9rem;
cursor: pointer;
word-break: break-all;
${({ isDisabled }) =>
isDisabled &&

View File

@ -0,0 +1,10 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.5273 4.91831C12.5456 4.36996 12.8 3.81352 12.8 3.5C12.8 3.18648 12.5456 2.63004 11.5273 2.08169C10.5578 1.55967 9.13609 1.2 7.5 1.2C5.86391 1.2 4.4422 1.55967 3.47273 2.08169C2.45437 2.63004 2.2 3.18648 2.2 3.5C2.2 3.81352 2.45437 4.36996 3.47273 4.91831C4.4422 5.44033 5.86391 5.8 7.5 5.8C9.13609 5.8 10.5578 5.44033 11.5273 4.91831ZM7.5 7C11.0899 7 14 5.433 14 3.5C14 1.567 11.0899 0 7.5 0C3.91015 0 1 1.567 1 3.5C1 5.433 3.91015 7 7.5 7Z" fill="currentColor"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.2 3.5V7.5C2.2 7.51705 2.20921 7.59285 2.31238 7.73222C2.41306 7.86821 2.57568 8.0264 2.80319 8.19397C3.25752 8.5286 3.89813 8.84764 4.5904 9.07469C4.90527 9.17796 5.0768 9.51692 4.97353 9.83179C4.87027 10.1467 4.5313 10.3182 4.21643 10.2149C3.43047 9.95715 2.66937 9.58576 2.09155 9.16018C1.80298 8.94764 1.54192 8.70827 1.34793 8.44624C1.15644 8.18759 1 7.86492 1 7.5V3.5H2.2Z" fill="currentColor"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.2 7.5V11.5C2.2 11.8823 2.41755 12.2833 2.98457 12.6612C3.55483 13.0412 4.41304 13.3459 5.4954 13.5122C5.82293 13.5626 6.04764 13.8689 5.9973 14.1964C5.94697 14.5239 5.64066 14.7487 5.31313 14.6983C4.12801 14.5162 3.08409 14.1696 2.31909 13.6597C1.55084 13.1478 1 12.4204 1 11.5V7.5H2.2Z" fill="currentColor"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.5273 4.91831C12.5456 4.36996 12.8 3.81352 12.8 3.5C12.8 3.18648 12.5456 2.63004 11.5273 2.08169C10.5578 1.55967 9.13609 1.2 7.5 1.2C5.86391 1.2 4.4422 1.55967 3.47273 2.08169C2.45437 2.63004 2.2 3.18648 2.2 3.5C2.2 3.81352 2.45437 4.36996 3.47273 4.91831C4.4422 5.44033 5.86391 5.8 7.5 5.8C9.13609 5.8 10.5578 5.44033 11.5273 4.91831ZM7.5 7C11.0899 7 14 5.433 14 3.5C14 1.567 11.0899 0 7.5 0C3.91015 0 1 1.567 1 3.5C1 5.433 3.91015 7 7.5 7Z" fill="currentColor"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.7998 6.4V3.5H13.9998V6.4C13.9998 6.73137 13.7312 7 13.3998 7C13.0684 7 12.7998 6.73137 12.7998 6.4Z" fill="currentColor"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.2 3.5V7.5C2.2 7.51705 2.20921 7.59285 2.31238 7.73222C2.41306 7.86821 2.57568 8.0264 2.80319 8.19397C3.25752 8.5286 3.89813 8.84764 4.5904 9.07469C4.90527 9.17796 5.0768 9.51692 4.97353 9.83179C4.87027 10.1467 4.5313 10.3182 4.21643 10.2149C3.43047 9.95715 2.66937 9.58576 2.09155 9.16018C1.80298 8.94764 1.54192 8.70827 1.34793 8.44624C1.15644 8.18759 1 7.86492 1 7.5V3.5H2.2Z" fill="currentColor"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.2 7.5V11.5C2.2 11.8823 2.41755 12.2833 2.98457 12.6612C3.55483 13.0412 4.41304 13.3459 5.4954 13.5122C5.82293 13.5626 6.04764 13.8689 5.9973 14.1964C5.94697 14.5239 5.64066 14.7487 5.31313 14.6983C4.12801 14.5162 3.08409 14.1696 2.31909 13.6597C1.55084 13.1478 1 12.4204 1 11.5V7.5H2.2Z" fill="currentColor"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.0179 8.5C11.0179 8.22386 11.2417 8 11.5179 8H11.7179C11.994 8 12.2179 8.22386 12.2179 8.5V8.77256C12.2179 9.00885 12.3852 9.20851 12.6072 9.28943C12.9252 9.40537 13.2172 9.57554 13.4718 9.78876C13.6526 9.9401 13.9086 9.98468 14.1128 9.86681L14.3489 9.73047C14.588 9.5924 14.8938 9.67433 15.0319 9.91348L15.1319 10.0867C15.27 10.3258 15.188 10.6316 14.9489 10.7697L14.7166 10.9038C14.5119 11.022 14.4226 11.267 14.4638 11.4999C14.4929 11.6644 14.508 11.8336 14.508 12.0064C14.508 12.1759 14.4934 12.3419 14.4655 12.5034C14.4252 12.7356 14.5146 12.9796 14.7187 13.0974L14.9489 13.2303C15.188 13.3684 15.27 13.6742 15.1319 13.9133L15.0319 14.0865C14.8938 14.3257 14.588 14.4076 14.3489 14.2695L14.1217 14.1384C13.9169 14.0201 13.6601 14.0654 13.4793 14.2178C13.2229 14.4339 12.9283 14.6063 12.6072 14.7234C12.3852 14.8043 12.2179 15.004 12.2179 15.2402V15.5C12.2179 15.7761 11.994 16 11.7179 16H11.5179C11.2417 16 11.0179 15.7761 11.0179 15.5V15.2409C11.0179 15.0044 10.8503 14.8047 10.6282 14.7239C10.3068 14.6069 10.012 14.4345 9.75538 14.2183C9.57457 14.066 9.3178 14.0208 9.11305 14.139L8.88672 14.2697C8.64758 14.4078 8.34178 14.3258 8.20371 14.0867L8.10371 13.9135C7.96564 13.6743 8.04758 13.3685 8.28672 13.2305L8.51547 13.0984C8.71966 12.9805 8.80901 12.7365 8.7687 12.5042C8.74063 12.3425 8.72601 12.1761 8.72601 12.0064C8.72601 11.8333 8.74122 11.6638 8.77037 11.4991C8.8116 11.2662 8.72239 11.0211 8.51756 10.9028L8.2867 10.7695C8.04756 10.6315 7.96562 10.3257 8.10369 10.0865L8.20369 9.91331C8.34176 9.67417 8.64756 9.59223 8.8867 9.7303L9.12203 9.86616C9.32614 9.98401 9.58207 9.93949 9.76283 9.78823C10.0177 9.57495 10.3099 9.40478 10.6282 9.28893C10.8503 9.20808 11.0179 9.00836 11.0179 8.77196V8.5ZM11.617 13.7769C12.5996 13.7769 13.3961 12.9804 13.3961 11.9978C13.3961 11.0153 12.5996 10.2188 11.617 10.2188C10.6345 10.2188 9.83796 11.0153 9.83796 11.9978C9.83796 12.9804 10.6345 13.7769 11.617 13.7769Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

@ -593,7 +593,7 @@ class EmbeddedDatasourcePathComponent extends React.Component<
</Text>
</StyledTooltip>
)}
{displayValue && (
{displayValue && shouldSave && (
<StoreAsDatasource
datasourceId={
datasourceObject && "id" in datasourceObject

View File

@ -60,7 +60,7 @@ function PluginActionResponse() {
dispatch(
setPluginActionEditorDebuggerState({
open: true,
selectedTab: DEBUGGER_TAB_KEYS.SCHEMA_TAB,
selectedTab: DEBUGGER_TAB_KEYS.DATASOURCE_TAB,
}),
);
}

View File

@ -15,15 +15,16 @@ import { datasourcesEditorIdURL } from "ee/RouteBuilder";
import { DatasourceComponentTypes } from "api/PluginApi";
import { getPluginActionDebuggerState } from "PluginActionEditor/store";
import { SchemaDisplayStatus, StatusDisplay } from "./StatusDisplay";
import DatasourceSelector from "./DatasourceSelector";
import { SchemaTables } from "./SchemaTables";
import { DatasourceTables } from "./DatasourceTables";
import { DatasourceEditEntryPoints } from "constants/Datasource";
import AnalyticsUtil from "ee/utils/AnalyticsUtil";
import { isEmpty, omit } from "lodash";
import { getQueryParams } from "utils/URLUtils";
import { getCurrentPageId } from "selectors/editorSelectors";
import { TableColumns } from "./TableColumns";
import { BOTTOMBAR_HEIGHT } from "./constants";
import { useEditorType } from "ee/hooks";
import { useParentEntityInfo } from "ee/hooks/datasourceEditorHooks";
import DatasourceInfo from "./DatasourceInfo";
interface Props {
datasourceId: string;
@ -31,7 +32,7 @@ interface Props {
currentActionId: string;
}
const Schema = (props: Props) => {
const Datasource = (props: Props) => {
const dispatch = useDispatch();
const datasourceStructure = useSelector((state) =>
@ -44,7 +45,8 @@ const Schema = (props: Props) => {
getPluginIdFromDatasourceId(state, props.datasourceId),
);
const currentPageId = useSelector(getCurrentPageId);
const editorType = useEditorType(location.pathname);
const { parentEntityId } = useParentEntityInfo(editorType);
const [selectedTable, setSelectedTable] = useState<string>();
@ -107,7 +109,7 @@ const Schema = (props: Props) => {
});
const url = datasourcesEditorIdURL({
basePageId: currentPageId,
baseParentEntityId: parentEntityId,
datasourceId: props.datasourceId,
params: { ...omit(getQueryParams(), "viewMode"), viewMode: false },
generateEditorPath: true,
@ -137,13 +139,12 @@ const Schema = (props: Props) => {
}
return (
<>
<Flex padding="spaces-3">
<DatasourceSelector
datasourceId={props.datasourceId}
datasourceName={props.datasourceName}
/>
</Flex>
<Flex flexDirection="column" padding="spaces-3">
<DatasourceInfo
datasourceId={props.datasourceId}
datasourceName={props.datasourceName}
showEditButton={!isLoading}
/>
<StatusDisplay
editDatasource={editDatasource}
errorMessage={
@ -153,7 +154,7 @@ const Schema = (props: Props) => {
}
state={statusState}
/>
</>
</Flex>
);
};
@ -164,7 +165,7 @@ const Schema = (props: Props) => {
return (
<Flex h="100%">
<SchemaTables
<DatasourceTables
currentActionId={props.currentActionId}
datasourceId={props.datasourceId}
datasourceName={props.datasourceName}
@ -194,4 +195,4 @@ const Schema = (props: Props) => {
);
};
export { Schema };
export { Datasource };

View File

@ -0,0 +1,69 @@
import React from "react";
import { Button, Flex, Tooltip } from "@appsmith/ads";
import DatasourceSelector from "./DatasourceSelector";
import { createMessage, EDIT_DS_CONFIG } from "ee/constants/messages";
import { DatasourceEditEntryPoints } from "constants/Datasource";
import AnalyticsUtil from "ee/utils/AnalyticsUtil";
import { datasourcesEditorIdURL } from "ee/RouteBuilder";
import { omit } from "lodash";
import { getQueryParams } from "utils/URLUtils";
import history from "utils/history";
import { useEditorType } from "ee/hooks";
import { useParentEntityInfo } from "ee/hooks/datasourceEditorHooks";
interface Props {
datasourceId: string;
datasourceName: string;
showEditButton: boolean;
}
const DatasourceInfo = ({
datasourceId,
datasourceName,
showEditButton,
}: Props) => {
const editorType = useEditorType(location.pathname);
const { parentEntityId } = useParentEntityInfo(editorType);
// eslint-disable-next-line react-perf/jsx-no-new-function-as-prop
const editDatasource = () => {
const entryPoint = DatasourceEditEntryPoints.QUERY_EDITOR_DATASOURCE_SCHEMA;
AnalyticsUtil.logEvent("EDIT_DATASOURCE_CLICK", {
datasourceId: datasourceId,
pluginName: "",
entryPoint: entryPoint,
});
const url = datasourcesEditorIdURL({
baseParentEntityId: parentEntityId,
datasourceId: datasourceId,
params: { ...omit(getQueryParams(), "viewMode"), viewMode: false },
generateEditorPath: true,
});
history.push(url);
};
return (
<Flex alignItems={"center"} gap="spaces-2">
<DatasourceSelector
datasourceId={datasourceId}
datasourceName={datasourceName}
/>
{showEditButton && (
<Tooltip content={createMessage(EDIT_DS_CONFIG)} placement="top">
<Button
isIconButton
kind="tertiary"
onClick={editDatasource}
size="sm"
startIcon="datasource-config"
/>
</Tooltip>
)}
</Flex>
);
};
export default DatasourceInfo;

View File

@ -0,0 +1,13 @@
import { API_EDITOR_FORM_NAME } from "ee/constants/forms";
import { type Action } from "entities/Action";
import { reduxForm } from "redux-form";
import {
PluginDatasourceSelector,
type CustomProps,
} from "./PluginDatasourceSelector";
export default reduxForm<Action, CustomProps>({
form: API_EDITOR_FORM_NAME,
destroyOnUnmount: false,
enableReinitialize: true,
})(PluginDatasourceSelector);

View File

@ -20,18 +20,17 @@ import type { AppState } from "ee/reducers";
import { getCurrentAppWorkspace } from "ee/selectors/selectedWorkspaceSelectors";
import { useActiveActionBaseId } from "ee/pages/Editor/Explorer/hooks";
import { INTEGRATION_TABS } from "constants/routes";
import { QUERY_EDITOR_FORM_NAME } from "ee/constants/forms";
import MenuField from "components/editorComponents/form/fields/MenuField";
import type { InjectedFormProps } from "redux-form";
import { reduxForm } from "redux-form";
import type { Action } from "entities/Action";
import { CurrentDataSourceLink } from "./CurrentDataSourceLink";
import { CurrentDataSource } from "./CurrentDataSource";
import { type Action } from "entities/Action";
import { CurrentDataSourceLink } from "../CurrentDataSourceLink";
import { CurrentDataSource } from "../CurrentDataSource";
import { useCreateDatasource } from "ee/PluginActionEditor/hooks/useCreateDatasource";
interface CustomProps {
export interface CustomProps {
datasourceId: string;
datasourceName: string;
formName: string;
}
type Props = InjectedFormProps<Action, CustomProps> & CustomProps;
@ -44,7 +43,11 @@ interface DATASOURCES_OPTIONS_TYPE {
onSelect?: (value: string) => void;
}
const DatasourceSelector = ({ datasourceId, datasourceName }: Props) => {
export const PluginDatasourceSelector = ({
datasourceId,
datasourceName,
formName,
}: Props) => {
const activeActionBaseId = useActiveActionBaseId();
const currentActionConfig = useSelector((state) =>
activeActionBaseId
@ -118,7 +121,7 @@ const DatasourceSelector = ({ datasourceId, datasourceName }: Props) => {
<Flex>
<MenuField
className={"t--switch-datasource"}
formName={QUERY_EDITOR_FORM_NAME}
formName={formName}
name="datasource.id"
options={DATASOURCES_OPTIONS}
>
@ -130,9 +133,3 @@ const DatasourceSelector = ({ datasourceId, datasourceName }: Props) => {
</Flex>
);
};
export default reduxForm<Action, CustomProps>({
form: QUERY_EDITOR_FORM_NAME,
destroyOnUnmount: false,
enableReinitialize: true,
})(DatasourceSelector);

View File

@ -0,0 +1,13 @@
import { QUERY_EDITOR_FORM_NAME } from "ee/constants/forms";
import { type Action } from "entities/Action";
import { reduxForm } from "redux-form";
import {
PluginDatasourceSelector,
type CustomProps,
} from "./PluginDatasourceSelector";
export default reduxForm<Action, CustomProps>({
form: QUERY_EDITOR_FORM_NAME,
destroyOnUnmount: false,
enableReinitialize: true,
})(PluginDatasourceSelector);

View File

@ -0,0 +1,31 @@
import React from "react";
import { UIComponentTypes } from "api/PluginApi";
import { usePluginActionContext } from "PluginActionEditor/PluginActionContext";
import ApiDatasourceSelector from "./ApiDatasourceSelector";
import QueryDatasourceSelector from "./QueryDatasourceSelector";
import {
API_EDITOR_FORM_NAME,
QUERY_EDITOR_FORM_NAME,
} from "ee/constants/forms";
const API_FORM_COMPONENTS = [
UIComponentTypes.ApiEditorForm,
UIComponentTypes.GraphQLEditorForm,
];
export interface DatasourceProps {
datasourceId: string;
datasourceName: string;
}
const DatasourceSelector = (props: DatasourceProps) => {
const { plugin } = usePluginActionContext();
return API_FORM_COMPONENTS.includes(plugin.uiComponent) ? (
<ApiDatasourceSelector {...props} formName={API_EDITOR_FORM_NAME} />
) : (
<QueryDatasourceSelector {...props} formName={QUERY_EDITOR_FORM_NAME} />
);
};
export default DatasourceSelector;

View File

@ -5,10 +5,10 @@ import {
} from "entities/Datasource";
import { DatasourceStructureContainer as DatasourceStructureList } from "pages/Editor/DatasourceInfo/DatasourceStructureContainer";
import React, { useCallback } from "react";
import DatasourceSelector from "./DatasourceSelector";
import { refreshDatasourceStructure } from "actions/datasourceActions";
import { useDispatch } from "react-redux";
import { SchemaTableContainer } from "./styles";
import DatasourceInfo from "./DatasourceInfo";
interface Props {
datasourceId: string;
@ -19,7 +19,7 @@ interface Props {
selectedTable: string | undefined;
}
const SchemaTables = ({
const DatasourceTables = ({
currentActionId,
datasourceId,
datasourceName,
@ -53,9 +53,10 @@ const SchemaTables = ({
gap="spaces-2"
justifyContent={"space-between"}
>
<DatasourceSelector
<DatasourceInfo
datasourceId={datasourceId}
datasourceName={datasourceName}
showEditButton
/>
<Button
className="datasourceStructure-refresh"
@ -80,4 +81,4 @@ const SchemaTables = ({
);
};
export { SchemaTables };
export { DatasourceTables };

View File

@ -16,6 +16,8 @@ import {
EDIT_DATASOURCE,
LOADING_RECORDS_TITLE_TEXT,
CANT_SHOW_SCHEMA,
NO_ACCESS_TITLE_TEXT,
NO_ACCESS_MESSAGE_TEXT,
} from "ee/constants/messages";
import { getAssetUrl } from "ee/utils/airgapHelpers";
import { ASSETS_CDN_URL } from "constants/ThirdPartyConstants";
@ -28,6 +30,7 @@ enum SchemaDisplayStatus {
FAILED = "FAILED",
NOCOLUMNS = "NOCOLUMNS",
CANTSHOW = "CANTSHOW",
NOACCESS = "NOACCESS",
}
interface Props {
@ -74,6 +77,11 @@ const StateData: Record<
message: createMessage(CANT_SHOW_SCHEMA),
image: getAssetUrl(`${ASSETS_CDN_URL}/empty-state.svg`),
},
NOACCESS: {
title: createMessage(NO_ACCESS_TITLE_TEXT),
message: createMessage(NO_ACCESS_MESSAGE_TEXT),
image: getAssetUrl(`${ASSETS_CDN_URL}/locked-state.svg`),
},
};
const StatusDisplay = ({ editDatasource, errorMessage, state }: Props) => {

View File

@ -0,0 +1 @@
export * from "./Datasource";

View File

@ -19,5 +19,9 @@ export const SchemaTableContainer = styled(Flex)`
.entity-icon > .ads-v2-icon {
display: none;
}
.t--entity-name {
padding-left: 0;
}
}
`;

View File

@ -30,9 +30,10 @@ export const StatusBar = styled.div`
display: flex;
justify-content: space-between;
height: ${TAB_BAR_HEIGHT}px;
padding: 8px;
padding: 8px 8px 8px 12px;
border-bottom: 1px solid var(--ads-v2-color-border);
z-index: var(--ads-v2-z-index-1);
background: var(--ads-v2-color-bg);
`;
export const StatusBarInfo = styled.div`

View File

@ -25,7 +25,7 @@ import {
} from "PluginActionEditor/store";
import { doesPluginRequireDatasource } from "ee/entities/Engine/actionHelpers";
import useShowSchema from "PluginActionEditor/components/PluginActionResponse/hooks/useShowSchema";
import { Schema } from "PluginActionEditor/components/PluginActionResponse/components/Schema";
import { Datasource } from "PluginActionEditor/components/PluginActionResponse/components/DatasourceTab";
import QueryResponseTab from "PluginActionEditor/components/PluginActionResponse/components/QueryResponseTab";
import type { SourceEntity } from "entities/AppsmithConsole";
import { ENTITY_TYPE as SOURCE_ENTITY_TYPE } from "ee/entities/AppsmithConsole/utils";
@ -62,6 +62,20 @@ function usePluginActionResponseTabs() {
};
if (plugin.type === PluginType.API) {
if (datasource && "id" in datasource) {
tabs.push({
key: DEBUGGER_TAB_KEYS.DATASOURCE_TAB,
title: "Datasource",
panelComponent: (
<Datasource
currentActionId={action.id}
datasourceId={datasource?.id || ""}
datasourceName={datasource?.name || ""}
/>
),
});
}
tabs.push(
{
key: DEBUGGER_TAB_KEYS.RESPONSE_TAB,
@ -111,10 +125,10 @@ function usePluginActionResponseTabs() {
if (showSchema) {
tabs.push({
key: DEBUGGER_TAB_KEYS.SCHEMA_TAB,
title: "Schema",
key: DEBUGGER_TAB_KEYS.DATASOURCE_TAB,
title: "Datasource",
panelComponent: (
<Schema
<Datasource
currentActionId={action.id}
datasourceId={datasource?.id || ""}
datasourceName={datasource?.name || ""}

View File

@ -393,6 +393,7 @@ export const CREATE_NEW_DATASOURCE_DATABASE_HEADER = () => "Databases";
export const CREATE_NEW_DATASOURCE_MOST_POPULAR_HEADER = () => "Most popular";
export const CREATE_NEW_DATASOURCE_REST_API = () => "REST API";
export const SAMPLE_DATASOURCES = () => "Sample datasources";
export const EDIT_DS_CONFIG = () => "Edit datasource configuration";
export const ERROR_EVAL_ERROR_GENERIC = () =>
`Unexpected error occurred while evaluating the application`;
@ -2277,18 +2278,22 @@ export const EMPTY_TABLE_MESSAGE_TEXT = () =>
export const EMPTY_SCHEMA_MESSAGE_TEXT = () =>
"There are no schema records to show";
export const NO_COLUMNS_MESSAGE_TEXT = () => "There are no columns to show";
export const LOADING_RECORDS_TITLE_TEXT = () => "Loading records";
export const LOADING_RECORDS_TITLE_TEXT = () => "Loading columns";
export const LOADING_SCHEMA_TITLE_TEXT = () => "Loading schema";
export const LOADING_RECORDS_MESSAGE_TEXT = () => "This may take a few seconds";
export const FAILED_RECORDS_TITLE_TEXT = () => "Failed to load";
export const FAILED_RECORDS_TITLE_TEXT = () => "Failed to load datasource";
export const FAILED_RECORDS_MESSAGE_TEXT = () =>
"There was an error connecting to the datasource. Please check the datasource configuration and retry.";
"Please check the datasource configuration and retry.";
export const DATASOURCE_SWITCHER_MENU_GROUP_NAME = () => "Select a datasource";
export const CANT_SHOW_SCHEMA = () =>
"We cant show the schema for this datasource";
export const COLUMNS_TITLE = () => "Columns";
export const COLUMNS_SEARCH_PLACEHOLDER = (tableName: string) =>
`Search columns in ${tableName}`;
export const NO_ACCESS_TITLE_TEXT = () =>
"You do not have access to this datasource";
export const NO_ACCESS_MESSAGE_TEXT = () =>
"Please contact your workspace administrator to gain access";
export const DATA_PANE_TITLE = () => "Datasources in your workspace";
export const DATASOURCE_LIST_BLANK_DESCRIPTION = () =>

View File

@ -70,7 +70,7 @@ function DebuggerTabs() {
const shouldRender = !(
selectedTab === DEBUGGER_TAB_KEYS.RESPONSE_TAB ||
selectedTab === DEBUGGER_TAB_KEYS.HEADER_TAB ||
selectedTab === DEBUGGER_TAB_KEYS.SCHEMA_TAB
selectedTab === DEBUGGER_TAB_KEYS.DATASOURCE_TAB
);
return (

View File

@ -1,5 +1,5 @@
export enum DEBUGGER_TAB_KEYS {
SCHEMA_TAB = "SCHEMA_TAB",
DATASOURCE_TAB = "DATASOURCE_TAB",
RESPONSE_TAB = "RESPONSE_TAB",
HEADER_TAB = "HEADERS_TAB",
ERROR_TAB = "ERROR_TAB",

View File

@ -125,7 +125,7 @@ export default function Debugger() {
const shouldRender = !(
selectedResponseTab === DEBUGGER_TAB_KEYS.RESPONSE_TAB ||
selectedResponseTab === DEBUGGER_TAB_KEYS.HEADER_TAB ||
selectedResponseTab === DEBUGGER_TAB_KEYS.SCHEMA_TAB
selectedResponseTab === DEBUGGER_TAB_KEYS.DATASOURCE_TAB
);
return (

View File

@ -14,6 +14,9 @@ import { getIDETestState } from "test/factories/AppIDEFactoryUtils";
import { PageFactory } from "test/factories/PageFactory";
import { screen, waitFor } from "@testing-library/react";
import { GoogleSheetFactory } from "test/factories/Actions/GoogleSheetFactory";
import { PluginActionContextProvider } from "PluginActionEditor";
import { PluginPackageName, PluginType } from "entities/Action";
import { DatasourceComponentTypes, UIComponentTypes } from "api/PluginApi";
const FeatureFlags = {
rollout_side_by_side_enabled: true,
@ -326,6 +329,17 @@ describe("IDE URL rendering of Queries", () => {
});
describe("Postgres Routes", () => {
const mockPlugin = {
id: "plugin_id",
name: "Postgres",
packageName: PluginPackageName.POSTGRES,
type: PluginType.DB,
uiComponent: UIComponentTypes.UQIDbEditorForm,
datasourceComponent: DatasourceComponentTypes.AutoForm,
templates: {},
requiresDatasource: true,
};
it("Renders Postgres routes in Full Screen", async () => {
const page = PageFactory.build();
const anQuery = PostgresFactory.build({
@ -344,7 +358,9 @@ describe("IDE URL rendering of Queries", () => {
const { getAllByText, getByRole, getByTestId } = render(
<Route path={BUILDER_PATH}>
<IDE />
<PluginActionContextProvider action={anQuery} plugin={mockPlugin}>
<IDE />
</PluginActionContextProvider>
</Route>,
{
url: `/app/applicationSlug/pageSlug-${page.basePageId}/edit/queries/${anQuery.baseId}`,
@ -402,7 +418,9 @@ describe("IDE URL rendering of Queries", () => {
const { getAllByText, getByRole, getByTestId } = render(
<Route path={BUILDER_PATH}>
<IDE />
<PluginActionContextProvider action={anQuery} plugin={mockPlugin}>
<IDE />
</PluginActionContextProvider>
</Route>,
{
url: `/app/applicationSlug/pageSlug-${page.basePageId}/edit/queries/${anQuery.baseId}`,
@ -533,6 +551,17 @@ describe("IDE URL rendering of Queries", () => {
});
describe("Google Sheets Routes", () => {
const mockPlugin = {
id: "plugin_id",
name: "Google Sheets",
packageName: PluginPackageName.GOOGLE_SHEETS,
type: PluginType.DB,
uiComponent: UIComponentTypes.GraphQLEditorForm,
datasourceComponent: DatasourceComponentTypes.RestAPIDatasourceForm,
templates: {},
requiresDatasource: false,
};
it("Renders Google Sheets routes in Full Screen", async () => {
const page = PageFactory.build();
const anQuery = GoogleSheetFactory.build({
@ -552,7 +581,9 @@ describe("IDE URL rendering of Queries", () => {
const { getAllByText, getByRole, getByTestId } = render(
<Route path={BUILDER_PATH}>
<IDE />
<PluginActionContextProvider action={anQuery} plugin={mockPlugin}>
<IDE />
</PluginActionContextProvider>
</Route>,
{
url: `/app/applicationSlug/pageSlug-${page.basePageId}/edit/saas/google-sheets-plugin/api/${anQuery.baseId}`,
@ -603,7 +634,9 @@ describe("IDE URL rendering of Queries", () => {
const { container, getAllByText, getByRole, getByTestId } = render(
<Route path={BUILDER_PATH}>
<IDE />
<PluginActionContextProvider action={anQuery} plugin={mockPlugin}>
<IDE />
</PluginActionContextProvider>
</Route>,
{
url: `/app/applicationSlug/pageSlug-${page.basePageId}/edit/saas/google-sheets-plugin/api/${anQuery.baseId}`,

View File

@ -12,7 +12,7 @@ import {
} from "ee/constants/messages";
import DebuggerLogs from "components/editorComponents/Debugger/DebuggerLogs";
import ErrorLogs from "components/editorComponents/Debugger/Errors";
import { Schema } from "PluginActionEditor/components/PluginActionResponse/components/Schema";
import { Datasource } from "PluginActionEditor/components/PluginActionResponse/components/DatasourceTab";
import type { ActionResponse } from "api/ActionAPI";
import type { SourceEntity } from "entities/AppsmithConsole";
import type { Action } from "entities/Action";
@ -141,7 +141,7 @@ function QueryDebuggerTabs({
dispatch(
setPluginActionEditorDebuggerState({
open: true,
selectedTab: DEBUGGER_TAB_KEYS.SCHEMA_TAB,
selectedTab: DEBUGGER_TAB_KEYS.DATASOURCE_TAB,
}),
);
}
@ -217,10 +217,10 @@ function QueryDebuggerTabs({
if (showSchema && currentActionConfig && currentActionConfig.datasource) {
responseTabs.unshift({
key: DEBUGGER_TAB_KEYS.SCHEMA_TAB,
title: "Schema",
key: DEBUGGER_TAB_KEYS.DATASOURCE_TAB,
title: "Datasource",
panelComponent: (
<Schema
<Datasource
currentActionId={currentActionConfig.id}
datasourceId={currentActionConfig.datasource.id || ""}
datasourceName={datasource?.name || ""}

View File

@ -0,0 +1,33 @@
package com.appsmith.server.migrations.db.ce;
import com.appsmith.server.domains.Plugin;
import io.mongock.api.annotations.ChangeUnit;
import io.mongock.api.annotations.Execution;
import io.mongock.api.annotations.RollbackExecution;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
@Slf4j
@ChangeUnit(order = "064", id = "add_plugin_doc_url_to_rest_api_plugin")
public class Migration064AddPluginDocUrlToRestApiPlugin {
private final MongoTemplate mongoTemplate;
public Migration064AddPluginDocUrlToRestApiPlugin(MongoTemplate mongoTemplate) {
this.mongoTemplate = mongoTemplate;
}
@RollbackExecution
public void rollbackExecution() {}
@Execution
public void execute() {
Query query = new Query().addCriteria(Criteria.where("packageName").is("restapi-plugin"));
Update update =
new Update().set("documentationLink", "https://docs.appsmith.com/connect-data/reference/rest-api");
mongoTemplate.updateMulti(query, update, Plugin.class);
}
}