diff --git a/app/client/src/assets/images/no-js-min.svg b/app/client/src/assets/images/no-js-min.svg new file mode 100644 index 0000000000..4a209d3f4e --- /dev/null +++ b/app/client/src/assets/images/no-js-min.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/client/src/assets/images/no-query-min.svg b/app/client/src/assets/images/no-query-min.svg new file mode 100644 index 0000000000..1a472b5ef6 --- /dev/null +++ b/app/client/src/assets/images/no-query-min.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/client/src/ce/constants/messages.ts b/app/client/src/ce/constants/messages.ts index 3240551f4f..0c9631b4d0 100644 --- a/app/client/src/ce/constants/messages.ts +++ b/app/client/src/ce/constants/messages.ts @@ -2274,6 +2274,10 @@ export const PAGES_PANE_TEXTS = { queries_tab: () => "Queries", js_tab: () => "JS", ui_tab: () => "UI", + query_blank_state: () => "Write your first query or API to access data", + js_blank_state: () => "Use JS to transform your data or write business logic", + query_blank_button: () => "New Query/API", + js_blank_button: () => "New JS Object", }; export const PARTIAL_IMPORT_EXPORT = { diff --git a/app/client/src/ce/pages/Editor/IDE/MainPane/useRoutes.ts b/app/client/src/ce/pages/Editor/IDE/MainPane/useRoutes.ts index 0f44c62708..e0b6b1cfee 100644 --- a/app/client/src/ce/pages/Editor/IDE/MainPane/useRoutes.ts +++ b/app/client/src/ce/pages/Editor/IDE/MainPane/useRoutes.ts @@ -15,6 +15,7 @@ import { JS_COLLECTION_EDITOR_PATH, JS_COLLECTION_ID_PATH, PROVIDER_TEMPLATE_PATH, + QUERIES_EDITOR_BASE_PATH, QUERIES_EDITOR_ID_PATH, WIDGETS_EDITOR_BASE_PATH, WIDGETS_EDITOR_ID_PATH, @@ -39,6 +40,8 @@ import ProviderTemplates from "pages/Editor/APIEditor/ProviderTemplates"; import GeneratePage from "pages/Editor/GeneratePage"; import type { RouteProps } from "react-router"; import { useIsAppSidebarEnabled } from "navigation/featureFlagHooks"; +import { JSBlankState } from "../../../../../pages/Editor/JSEditor/JSBlankState"; +import { QueriesBlankState } from "../../../../../pages/Editor/QueryEditor/QueriesBlankState"; export interface RouteReturnType extends RouteProps { key: string; @@ -87,6 +90,12 @@ function useRoutes(path: string): RouteReturnType[] { exact: true, path: `${path}${API_EDITOR_ID_PATH}`, }, + { + key: "QueryEditorList", + component: QueriesBlankState, + exact: true, + path: `${path}${QUERIES_EDITOR_BASE_PATH}`, + }, { key: "QueryEditor", component: QueryEditor, @@ -94,8 +103,8 @@ function useRoutes(path: string): RouteReturnType[] { path: `${path}${QUERIES_EDITOR_ID_PATH}`, }, { - key: "JSEditor Collection", - component: JSEditor, + key: "JSEditorList", + component: JSBlankState, exact: true, path: `${path}${JS_COLLECTION_EDITOR_PATH}`, }, diff --git a/app/client/src/ce/pages/Editor/routes.tsx b/app/client/src/ce/pages/Editor/routes.tsx index d2176c98f8..1da9e0f617 100644 --- a/app/client/src/ce/pages/Editor/routes.tsx +++ b/app/client/src/ce/pages/Editor/routes.tsx @@ -13,7 +13,6 @@ import { CURL_IMPORT_PAGE_PATH, GENERATE_TEMPLATE_FORM_PATH, INTEGRATION_EDITOR_PATH, - JS_COLLECTION_EDITOR_PATH, JS_COLLECTION_ID_PATH, PROVIDER_TEMPLATE_PATH, QUERIES_EDITOR_ID_PATH, @@ -69,11 +68,6 @@ function EditorRoutes() { exact path={`${path}${QUERIES_EDITOR_ID_PATH}`} /> - = { setter: setQueryPaneConfigSelectedTabIndex, defaultValue: 0, }, - ], - [FocusEntity.PROPERTY_PANE]: [ - { - type: ConfigType.Redux, - name: FocusElement.PropertyTabs, - selector: getWidgetSelectedPropertyTabIndex, - setter: setWidgetSelectedPropertyTabIndex, - defaultValue: 0, - }, - { - type: ConfigType.Redux, - name: FocusElement.PropertyField, - selector: getFocusablePropertyPaneField, - setter: setFocusablePropertyPaneField, - defaultValue: "", - }, - ], - [FocusEntity.API]: [ { type: ConfigType.Redux, name: FocusElement.ApiPaneConfigTabs, @@ -319,6 +317,23 @@ export const FocusElementsConfig: Record = { setter: setApiRightPaneSelectedTab, }, ], + [FocusEntity.PROPERTY_PANE]: [ + { + type: ConfigType.Redux, + name: FocusElement.PropertyTabs, + selector: getWidgetSelectedPropertyTabIndex, + setter: setWidgetSelectedPropertyTabIndex, + defaultValue: 0, + }, + { + type: ConfigType.Redux, + name: FocusElement.PropertyField, + selector: getFocusablePropertyPaneField, + setter: setFocusablePropertyPaneField, + defaultValue: "", + }, + ], + [FocusEntity.API]: [], [FocusEntity.DEBUGGER]: [ { type: ConfigType.Redux, @@ -330,4 +345,22 @@ export const FocusElementsConfig: Record = { ], [FocusEntity.LIBRARY]: [], [FocusEntity.SETTINGS]: [], + [FocusEntity.QUERY_LIST]: [ + { + type: ConfigType.URL, + name: FocusElement.SelectedQuery, + selector: getSelectedQueryId, + setter: setSelectedQuery, + defaultValue: getFirstQueryId, + }, + ], + [FocusEntity.JS_OBJECT_LIST]: [ + { + type: ConfigType.URL, + name: FocusElement.SelectedJSObject, + selector: getSelectedJSObjectId, + setter: setSelectedJSObject, + defaultValue: getFirstJSObjectId, + }, + ], }; diff --git a/app/client/src/navigation/FocusEntity.test.ts b/app/client/src/navigation/FocusEntity.test.ts index cfbc87f79c..f8b8802525 100644 --- a/app/client/src/navigation/FocusEntity.test.ts +++ b/app/client/src/navigation/FocusEntity.test.ts @@ -21,10 +21,19 @@ describe("identifyEntityFromPath", () => { appState: AppState.PAGES, }, }, + { + path: "/applications/myAppId/pages/myPageId/edit/queries", + expected: { + entity: FocusEntity.QUERY_LIST, + id: "", + pageId: "myPageId", + appState: AppState.PAGES, + }, + }, { path: "/applications/myAppId/pages/myPageId/edit/api/myApiId", expected: { - entity: FocusEntity.API, + entity: FocusEntity.QUERY, id: "myApiId", pageId: "myPageId", appState: AppState.PAGES, @@ -39,6 +48,42 @@ describe("identifyEntityFromPath", () => { appState: AppState.PAGES, }, }, + { + path: "/applications/myAppId/pages/myPageId/edit/jsObjects", + expected: { + entity: FocusEntity.JS_OBJECT_LIST, + id: "", + pageId: "myPageId", + appState: AppState.PAGES, + }, + }, + { + path: "/applications/myAppId/pages/myPageId/edit/jsObjects/myJSId", + expected: { + entity: FocusEntity.JS_OBJECT, + id: "myJSId", + pageId: "myPageId", + appState: AppState.PAGES, + }, + }, + { + path: "/applications/myAppId/pages/myPageId/edit/datasource", + expected: { + entity: FocusEntity.DATASOURCE_LIST, + id: "", + pageId: "myPageId", + appState: AppState.DATA, + }, + }, + { + path: "/applications/myAppId/pages/myPageId/edit/datasources/myDatasourceId", + expected: { + entity: FocusEntity.DATASOURCE, + id: "myDatasourceId", + pageId: "myPageId", + appState: AppState.DATA, + }, + }, ]; const pageSlugCases = [ { @@ -59,10 +104,19 @@ describe("identifyEntityFromPath", () => { appState: AppState.PAGES, }, }, + { + path: "/app/eval/page1-myPageId/edit/queries", + expected: { + entity: FocusEntity.QUERY_LIST, + id: "", + pageId: "myPageId", + appState: AppState.PAGES, + }, + }, { path: "/app/eval/page1-myPageId/edit/api/myApiId", expected: { - entity: FocusEntity.API, + entity: FocusEntity.QUERY, id: "myApiId", pageId: "myPageId", appState: AppState.PAGES, @@ -77,6 +131,42 @@ describe("identifyEntityFromPath", () => { appState: AppState.PAGES, }, }, + { + path: "/app/eval/page1-myPageId/edit/jsObjects", + expected: { + entity: FocusEntity.JS_OBJECT_LIST, + id: "", + pageId: "myPageId", + appState: AppState.PAGES, + }, + }, + { + path: "/app/eval/page1-myPageId/edit/jsObjects/myJSId", + expected: { + entity: FocusEntity.JS_OBJECT, + id: "myJSId", + pageId: "myPageId", + appState: AppState.PAGES, + }, + }, + { + path: "/app/eval/page1-myPageId/edit/datasource", + expected: { + entity: FocusEntity.DATASOURCE_LIST, + id: "", + pageId: "myPageId", + appState: AppState.DATA, + }, + }, + { + path: "/app/eval/page1-myPageId/edit/datasources/myDatasourceId", + expected: { + entity: FocusEntity.DATASOURCE, + id: "myDatasourceId", + pageId: "myPageId", + appState: AppState.DATA, + }, + }, ]; const customSlugCases = [ { @@ -97,10 +187,19 @@ describe("identifyEntityFromPath", () => { appState: AppState.PAGES, }, }, + { + path: "/app/myCustomSlug-myPageId/edit/queries", + expected: { + entity: FocusEntity.QUERY_LIST, + id: "", + pageId: "myPageId", + appState: AppState.PAGES, + }, + }, { path: "/app/myCustomSlug-myPageId/edit/api/myApiId", expected: { - entity: FocusEntity.API, + entity: FocusEntity.QUERY, id: "myApiId", pageId: "myPageId", appState: AppState.PAGES, @@ -115,6 +214,42 @@ describe("identifyEntityFromPath", () => { appState: AppState.PAGES, }, }, + { + path: "/app/myCustomSlug-myPageId/edit/jsObjects", + expected: { + entity: FocusEntity.JS_OBJECT_LIST, + id: "", + pageId: "myPageId", + appState: AppState.PAGES, + }, + }, + { + path: "/app/myCustomSlug-myPageId/edit/jsObjects/myJSId", + expected: { + entity: FocusEntity.JS_OBJECT, + id: "myJSId", + pageId: "myPageId", + appState: AppState.PAGES, + }, + }, + { + path: "/app/myCustomSlug-myPageId/edit/datasource", + expected: { + entity: FocusEntity.DATASOURCE_LIST, + id: "", + pageId: "myPageId", + appState: AppState.DATA, + }, + }, + { + path: "/app/myCustomSlug-myPageId/edit/datasources/myDatasourceId", + expected: { + entity: FocusEntity.DATASOURCE, + id: "myDatasourceId", + pageId: "myPageId", + appState: AppState.DATA, + }, + }, ]; const cases = oldUrlCases.concat(pageSlugCases.concat(customSlugCases)); diff --git a/app/client/src/navigation/FocusEntity.ts b/app/client/src/navigation/FocusEntity.ts index a7cd686251..eb7b8a8c9d 100644 --- a/app/client/src/navigation/FocusEntity.ts +++ b/app/client/src/navigation/FocusEntity.ts @@ -25,7 +25,9 @@ export enum FocusEntity { DATASOURCE = "DATASOURCE", DEBUGGER = "DEBUGGER", QUERY = "QUERY", + QUERY_LIST = "QUERY_LIST", JS_OBJECT = "JS_OBJECT", + JS_OBJECT_LIST = "JS_OBJECT_LIST", PROPERTY_PANE = "PROPERTY_PANE", NONE = "NONE", APP_STATE = "APP_STATE", @@ -36,6 +38,8 @@ export enum FocusEntity { export const FocusStoreHierarchy: Partial> = { [FocusEntity.PROPERTY_PANE]: FocusEntity.CANVAS, [FocusEntity.DATASOURCE]: FocusEntity.DATASOURCE_LIST, + [FocusEntity.JS_OBJECT]: FocusEntity.JS_OBJECT_LIST, + [FocusEntity.QUERY]: FocusEntity.QUERY_LIST, }; export interface FocusEntityInfo { @@ -109,7 +113,7 @@ export function identifyEntityFromPath(path: string): FocusEntityInfo { }; } return { - entity: FocusEntity.API, + entity: FocusEntity.QUERY, id: match.params.apiId, pageId: match.params.pageId, appState: AppState.PAGES, @@ -172,6 +176,22 @@ export function identifyEntityFromPath(path: string): FocusEntityInfo { appState: AppState.PAGES, }; } + if (match.params.entity === "queries") { + return { + entity: FocusEntity.QUERY_LIST, + id: "", + pageId: match.params.pageId, + appState: AppState.PAGES, + }; + } + if (match.params.entity === "jsObjects") { + return { + entity: FocusEntity.JS_OBJECT_LIST, + id: "", + pageId: match.params.pageId, + appState: AppState.PAGES, + }; + } if (match.params.entity) { if (match.params.entity === "libraries") { return { diff --git a/app/client/src/navigation/FocusSelectors.ts b/app/client/src/navigation/FocusSelectors.ts index 77646c5953..73ac8979a1 100644 --- a/app/client/src/navigation/FocusSelectors.ts +++ b/app/client/src/navigation/FocusSelectors.ts @@ -1,13 +1,18 @@ import { matchPath } from "react-router"; import { + API_EDITOR_ID_PATH, BUILDER_CUSTOM_PATH, BUILDER_PATH, BUILDER_PATH_DEPRECATED, DATA_SOURCES_EDITOR_ID_PATH, + JS_COLLECTION_ID_PATH, + QUERIES_EDITOR_ID_PATH, SAAS_GSHEET_EDITOR_ID_PATH, } from "../constants/routes"; import { shouldStorePageURLForFocus } from "./FocusUtils"; import { FocusEntity, identifyEntityFromPath } from "./FocusEntity"; +import { SAAS_EDITOR_API_ID_PATH } from "../pages/Editor/SaaSEditor/constants"; +import { PluginType } from "../entities/Action"; export const getSelectedDatasourceId = (path: string): string | undefined => { const match = matchPath<{ datasourceId?: string }>(path, [ @@ -34,3 +39,54 @@ export const getCurrentAppUrl = (path: string): string | undefined => { return path; } }; + +export type QueryListState = + | { id: string; type: PluginType; pluginPackageName?: string } + | undefined; + +export const getSelectedQueryId = (path: string): QueryListState => { + const match = matchPath<{ + queryId?: string; + apiId?: string; + pluginPackageName?: string; + }>(path, [ + // Queries + BUILDER_PATH_DEPRECATED + QUERIES_EDITOR_ID_PATH, + BUILDER_PATH + QUERIES_EDITOR_ID_PATH, + BUILDER_CUSTOM_PATH + QUERIES_EDITOR_ID_PATH, + // SASS + BUILDER_PATH_DEPRECATED + SAAS_EDITOR_API_ID_PATH, + BUILDER_PATH + SAAS_EDITOR_API_ID_PATH, + BUILDER_CUSTOM_PATH + SAAS_EDITOR_API_ID_PATH, + // API + BUILDER_PATH_DEPRECATED + API_EDITOR_ID_PATH, + BUILDER_PATH + API_EDITOR_ID_PATH, + BUILDER_CUSTOM_PATH + API_EDITOR_ID_PATH, + ]); + if (!match) return undefined; + const { apiId, pluginPackageName, queryId } = match.params; + if (!queryId || !apiId) { + return undefined; + } + let type: PluginType = PluginType.API; + if (pluginPackageName) { + type = PluginType.SAAS; + } else if (queryId) { + type = PluginType.DB; + } + return { + type, + id: apiId || queryId, + pluginPackageName, + }; +}; + +export const getSelectedJSObjectId = (path: string): string | undefined => { + const match = matchPath<{ collectionId?: string }>(path, [ + BUILDER_PATH_DEPRECATED + JS_COLLECTION_ID_PATH, + BUILDER_PATH + JS_COLLECTION_ID_PATH, + BUILDER_CUSTOM_PATH + JS_COLLECTION_ID_PATH, + ]); + if (!match) return undefined; + return match.params.collectionId; +}; diff --git a/app/client/src/navigation/FocusSetters.ts b/app/client/src/navigation/FocusSetters.ts index 1d8607c3c1..9e35bd2445 100644 --- a/app/client/src/navigation/FocusSetters.ts +++ b/app/client/src/navigation/FocusSetters.ts @@ -1,9 +1,17 @@ import history from "utils/history"; -import { datasourcesEditorIdURL } from "@appsmith/RouteBuilder"; +import { + apiEditorIdURL, + datasourcesEditorIdURL, + jsCollectionIdURL, + queryEditorIdURL, + saasEditorApiIdURL, +} from "@appsmith/RouteBuilder"; +import { PluginType } from "../entities/Action"; +import type { QueryListState } from "./FocusSelectors"; export function setSelectedDatasource(id: string | undefined) { if (id) { - history.push( + history.replace( datasourcesEditorIdURL({ datasourceId: id, }), @@ -14,13 +22,56 @@ export function setSelectedDatasource(id: string | undefined) { export function setPageUrl(path: string | undefined) { if (path) { const params = history.location.search; - history.push(`${path}${params}`); + history.replace(`${path}${params}`); } } export function setAppUrl(path: string | undefined) { if (path) { const params = history.location.search; - history.push(`${path}${params}`); + history.replace(`${path}${params}`); + } +} + +export function setSelectedQuery(state: QueryListState) { + if (state) { + switch (state.type) { + case PluginType.SAAS: + if (state.pluginPackageName) { + history.replace( + saasEditorApiIdURL({ + apiId: state.id, + pluginPackageName: state.pluginPackageName, + }), + ); + } + break; + case PluginType.DB: + history.replace( + queryEditorIdURL({ + queryId: state.id, + }), + ); + break; + case PluginType.API: + history.replace( + apiEditorIdURL({ + apiId: state.id, + }), + ); + break; + default: + break; + } + } +} + +export function setSelectedJSObject(id: string | undefined) { + if (id) { + history.replace( + jsCollectionIdURL({ + collectionId: id, + }), + ); } } diff --git a/app/client/src/navigation/FocusUtils.ts b/app/client/src/navigation/FocusUtils.ts index 85d018e827..5840869df0 100644 --- a/app/client/src/navigation/FocusUtils.ts +++ b/app/client/src/navigation/FocusUtils.ts @@ -1,6 +1,11 @@ import type { FocusEntityInfo } from "./FocusEntity"; import { FocusEntity, identifyEntityFromPath } from "./FocusEntity"; -import { builderURL, datasourcesEditorURL } from "@appsmith/RouteBuilder"; +import { + builderURL, + datasourcesEditorURL, + jsCollectionListURL, + queryListURL, +} from "@appsmith/RouteBuilder"; export const getEntityParentUrl = ( entityInfo: FocusEntityInfo, @@ -13,6 +18,12 @@ export const getEntityParentUrl = ( if (parentEntity === FocusEntity.DATASOURCE_LIST) { return datasourcesEditorURL({ pageId: entityInfo.pageId }); } + if (parentEntity === FocusEntity.JS_OBJECT_LIST) { + return jsCollectionListURL({ pageId: entityInfo.pageId }); + } + if (parentEntity === FocusEntity.QUERY_LIST) { + return queryListURL({ pageId: entityInfo.pageId }); + } return ""; }; export const isPageChange = (prevPath: string, currentPath: string) => { diff --git a/app/client/src/pages/Editor/IDE/PagesPane/JS_Section.tsx b/app/client/src/pages/Editor/IDE/PagesPane/JS_Section.tsx new file mode 100644 index 0000000000..b3f54ff168 --- /dev/null +++ b/app/client/src/pages/Editor/IDE/PagesPane/JS_Section.tsx @@ -0,0 +1,48 @@ +import React from "react"; +import { useSelector } from "react-redux"; +import { Flex } from "design-system"; +import styled from "styled-components"; + +import { selectFilesForExplorer } from "@appsmith/selectors/entitiesSelector"; +import { useActiveAction } from "@appsmith/pages/Editor/Explorer/hooks"; +import ExplorerJSCollectionEntity from "pages/Editor/Explorer/JSActions/JSActionEntity"; + +const JSContainer = styled(Flex)` + & .t--entity-item { + grid-template-columns: 4px auto 1fr auto auto auto auto auto; + + & .t--entity-name { + padding-left: var(--ads-v2-spaces-3); + } + } +`; + +const JSSection = () => { + const files = useSelector(selectFilesForExplorer); + const activeActionId = useActiveAction(); + + return ( + + {files.map(({ entity, type }: any) => { + if (type === "JS" && entity.id) { + return ( + + ); + } + })} + + ); +}; + +export { JSSection }; diff --git a/app/client/src/pages/Editor/IDE/PagesPane/Queries_JS.tsx b/app/client/src/pages/Editor/IDE/PagesPane/Queries_JS.tsx deleted file mode 100644 index 6d6cf22631..0000000000 --- a/app/client/src/pages/Editor/IDE/PagesPane/Queries_JS.tsx +++ /dev/null @@ -1,108 +0,0 @@ -import React, { useMemo } from "react"; -import { useSelector } from "react-redux"; -import { Flex, Text } from "design-system"; -import styled from "styled-components"; - -import { getPagePermissions } from "selectors/editorSelectors"; -import { selectFilesForExplorer } from "@appsmith/selectors/entitiesSelector"; -import { useActiveAction } from "@appsmith/pages/Editor/Explorer/hooks"; -import ExplorerActionEntity from "pages/Editor/Explorer/Actions/ActionEntity"; -import { EmptyComponent } from "pages/Editor/Explorer/common"; -import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; -import { - createMessage, - EMPTY_QUERY_JS_BUTTON_TEXT, - EMPTY_QUERY_JS_MAIN_TEXT, -} from "@appsmith/constants/messages"; -import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; -import { getHasCreateActionPermission } from "@appsmith/utils/BusinessFeatures/permissionPageHelpers"; -import ExplorerJSCollectionEntity from "pages/Editor/Explorer/JSActions/JSActionEntity"; - -const QueriesContainer = styled(Flex)` - & .t--entity-item { - grid-template-columns: 4px auto 1fr auto auto auto auto auto; - - & .t--entity-name { - padding-left: var(--ads-v2-spaces-3); - } - } -`; - -const QueriesJS = ({ paneType }: { paneType: "queries" | "js" }) => { - const files = useSelector(selectFilesForExplorer); - const activeActionId = useActiveAction(); - const pagePermissions = useSelector(getPagePermissions); - const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); - - const canCreateActions = getHasCreateActionPermission( - isFeatureEnabled, - pagePermissions, - ); - - const fileEntities = useMemo( - () => - files.map(({ entity, type }: any) => { - if ( - paneType !== "js" && - type === "group" && - entity.name === "JS Objects" - ) { - return ( - - - {entity.name} - - - ); - } else if (type !== "JS" && paneType === "queries") { - return ( - - ); - } else if (type === "JS" && paneType === "js") { - return ( - - ); - } - }), - [files, activeActionId], - ); - - return ( - - {fileEntities.length ? ( - fileEntities - ) : ( - - )} - - ); -}; - -export { QueriesJS }; diff --git a/app/client/src/pages/Editor/IDE/PagesPane/Queries_Section.tsx b/app/client/src/pages/Editor/IDE/PagesPane/Queries_Section.tsx new file mode 100644 index 0000000000..0fd36d7105 --- /dev/null +++ b/app/client/src/pages/Editor/IDE/PagesPane/Queries_Section.tsx @@ -0,0 +1,70 @@ +import React from "react"; +import { useSelector } from "react-redux"; +import { Flex, Text } from "design-system"; +import styled from "styled-components"; + +import { selectFilesForExplorer } from "@appsmith/selectors/entitiesSelector"; +import { useActiveAction } from "@appsmith/pages/Editor/Explorer/hooks"; +import ExplorerActionEntity from "pages/Editor/Explorer/Actions/ActionEntity"; + +const QueriesContainer = styled(Flex)` + & .t--entity-item { + grid-template-columns: 4px auto 1fr auto auto auto auto auto; + + & .t--entity-name { + padding-left: var(--ads-v2-spaces-3); + } + } +`; + +const QueriesSection = () => { + const files = useSelector(selectFilesForExplorer); + const activeActionId = useActiveAction(); + + return ( + + {files.map(({ entity, type }: any) => { + if (type === "group" && entity.name !== "JS Objects") { + return ( + + + {entity.name} + + + ); + } else if (type !== "JS" && entity.id) { + return ( + + ); + } + })} + + {files.length === 0 && ( + + + No Queries/APIs found + + + )} + + ); +}; + +export { QueriesSection }; diff --git a/app/client/src/pages/Editor/IDE/PagesPane/index.tsx b/app/client/src/pages/Editor/IDE/PagesPane/index.tsx index f5d13028d7..a0e69b6898 100644 --- a/app/client/src/pages/Editor/IDE/PagesPane/index.tsx +++ b/app/client/src/pages/Editor/IDE/PagesPane/index.tsx @@ -1,13 +1,11 @@ import React, { useCallback, useEffect, useState } from "react"; import { withProfiler } from "@sentry/react"; -import { Divider, Flex, SegmentedControl } from "design-system"; +import { Flex, SegmentedControl } from "design-system"; import { useLocation } from "react-router"; import { useDispatch, useSelector } from "react-redux"; -import { FocusEntity } from "navigation/FocusEntity"; -import { identifyEntityFromPath } from "navigation/FocusEntity"; +import { FocusEntity, identifyEntityFromPath } from "navigation/FocusEntity"; import { createMessage, PAGES_PANE_TEXTS } from "@appsmith/constants/messages"; -import { QueriesJS } from "./Queries_JS"; import ExplorerWidgetGroup from "pages/Editor/Explorer/Widgets/WidgetGroup"; import { getCurrentPageId } from "@appsmith/selectors/entitiesSelector"; import AnalyticsUtil from "utils/AnalyticsUtil"; @@ -21,6 +19,8 @@ import { forceOpenWidgetPanel } from "actions/widgetSidebarActions"; import { getIsFirstTimeUserOnboardingEnabled } from "selectors/onboardingSelectors"; import { toggleInOnboardingWidgetSelection } from "actions/onboardingActions"; import Pages from "pages/Editor/Explorer/Pages"; +import { JSSection } from "./JS_Section"; +import { QueriesSection } from "./Queries_Section"; enum TabsType { QUERIES = "queries", @@ -47,10 +47,12 @@ const _pagesPane = () => { ).entity; switch (entity) { case FocusEntity.QUERY: + case FocusEntity.QUERY_LIST: case FocusEntity.API: setSelected(TabsType.QUERIES); break; case FocusEntity.JS_OBJECT: + case FocusEntity.JS_OBJECT_LIST: setSelected(TabsType.JS); break; case FocusEntity.CANVAS: @@ -92,7 +94,6 @@ const _pagesPane = () => { }; return ( { value={selected} /> - { overflow="hidden" width="100%" > - {(selected === TabsType.QUERIES || selected === TabsType.JS) && ( - - )} + {selected === TabsType.QUERIES && } + + {selected === TabsType.JS && } {selected === TabsType.UI && ( + {isAppSidebarAnnouncementEnabled && !isAppSidebarAnnouncementDismissed && ( diff --git a/app/client/src/pages/Editor/JSEditor/JSBlankState.tsx b/app/client/src/pages/Editor/JSEditor/JSBlankState.tsx new file mode 100644 index 0000000000..3b7e71c4d8 --- /dev/null +++ b/app/client/src/pages/Editor/JSEditor/JSBlankState.tsx @@ -0,0 +1,63 @@ +import React from "react"; +import { Flex, Text, Button } from "design-system"; +import { importSvg } from "design-system-old"; + +import { createMessage, PAGES_PANE_TEXTS } from "@appsmith/constants/messages"; +import { + getCurrentPageId, + getPagePermissions, +} from "selectors/editorSelectors"; +import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; +import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; +import { getHasCreateActionPermission } from "@appsmith/utils/BusinessFeatures/permissionPageHelpers"; +import { useDispatch, useSelector } from "react-redux"; +import { createNewJSCollection } from "../../../actions/jsPaneActions"; + +const JSBlankState = () => { + const pagePermissions = useSelector(getPagePermissions); + + const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); + + const canCreateActions = getHasCreateActionPermission( + isFeatureEnabled, + pagePermissions, + ); + + const BlankStateIllustration = importSvg( + async () => import("assets/images/no-js-min.svg"), + ); + const dispatch = useDispatch(); + + const pageId = useSelector(getCurrentPageId); + + return ( + + + + {createMessage(PAGES_PANE_TEXTS.js_blank_state)} + + {canCreateActions && ( + + )} + + ); +}; + +export { JSBlankState }; diff --git a/app/client/src/pages/Editor/QueryEditor/QueriesBlankState.tsx b/app/client/src/pages/Editor/QueryEditor/QueriesBlankState.tsx new file mode 100644 index 0000000000..74555f784b --- /dev/null +++ b/app/client/src/pages/Editor/QueryEditor/QueriesBlankState.tsx @@ -0,0 +1,48 @@ +import React from "react"; +import { Flex, Text, Button } from "design-system"; +import { importSvg } from "design-system-old"; +import { useSelector } from "react-redux"; + +import { createMessage, PAGES_PANE_TEXTS } from "@appsmith/constants/messages"; +import { getPagePermissions } from "selectors/editorSelectors"; +import { useFeatureFlag } from "utils/hooks/useFeatureFlag"; +import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; +import { getHasCreateActionPermission } from "@appsmith/utils/BusinessFeatures/permissionPageHelpers"; + +const QueriesBlankState = () => { + const pagePermissions = useSelector(getPagePermissions); + + const isFeatureEnabled = useFeatureFlag(FEATURE_FLAG.license_gac_enabled); + + const canCreateActions = getHasCreateActionPermission( + isFeatureEnabled, + pagePermissions, + ); + + const BlankStateIllustration = importSvg( + async () => import("assets/images/no-query-min.svg"), + ); + + return ( + + + + {createMessage(PAGES_PANE_TEXTS.query_blank_state)} + + {canCreateActions && ( + + )} + + ); +}; + +export { QueriesBlankState }; diff --git a/app/client/src/selectors/jsPaneSelectors.ts b/app/client/src/selectors/jsPaneSelectors.ts index 08588103a7..9e9a12e4e5 100644 --- a/app/client/src/selectors/jsPaneSelectors.ts +++ b/app/client/src/selectors/jsPaneSelectors.ts @@ -1,4 +1,12 @@ import type { AppState } from "@appsmith/reducers"; +import { getCurrentJSCollections } from "@appsmith/selectors/entitiesSelector"; export const getJSPaneConfigSelectedTab = (state: AppState) => state.ui.jsPane.selectedConfigTab; + +export const getFirstJSObjectId = (state: AppState) => { + const currentJSActions = getCurrentJSCollections(state); + if (currentJSActions.length) { + return currentJSActions[0].config.id; + } +}; diff --git a/app/client/src/selectors/queryPaneSelectors.ts b/app/client/src/selectors/queryPaneSelectors.ts index 935d990c89..994687c37b 100644 --- a/app/client/src/selectors/queryPaneSelectors.ts +++ b/app/client/src/selectors/queryPaneSelectors.ts @@ -1,4 +1,22 @@ import type { AppState } from "@appsmith/reducers"; +import type { QueryListState } from "../navigation/FocusSelectors"; +import { getPageActions } from "@appsmith/selectors/entitiesSelector"; +import { getCurrentPageId } from "./editorSelectors"; export const getQueryPaneConfigSelectedTabIndex = (state: AppState) => state.ui.queryPane.selectedConfigTabIndex; + +export const getFirstQueryId = (state: AppState): QueryListState => { + const { plugins } = state.entities; + const pageId = getCurrentPageId(state); + const currentPageActions = getPageActions(pageId)(state); + if (currentPageActions.length) { + const first = currentPageActions[0].config; + const plugin = plugins.list.find((p) => p.id === first.pluginId); + return { + id: first.id, + type: first.pluginType, + pluginPackageName: plugin?.packageName, + }; + } +};