Merge pull request #31796 from appsmithorg/release
14th March, 2024 - Daily Promotion
This commit is contained in:
commit
35de20bac9
|
|
@ -1,5 +1,4 @@
|
|||
import React from "react";
|
||||
import type { Plugin } from "api/PluginApi";
|
||||
import type { LogItemProps } from "components/editorComponents/Debugger/ErrorLogs/ErrorLogItem";
|
||||
import { PluginType } from "entities/Action";
|
||||
import WidgetIcon from "pages/Editor/Explorer/Widgets/WidgetIcon";
|
||||
|
|
@ -13,7 +12,7 @@ import { ENTITY_TYPE } from "entities/DataTree/dataTreeFactory";
|
|||
|
||||
export const getIconForEntity: Record<
|
||||
string,
|
||||
(props: LogItemProps, pluginGroups: Record<string, Plugin>) => any
|
||||
(props: LogItemProps, pluginImages: Record<string, string>) => any
|
||||
> = {
|
||||
[ENTITY_TYPE.WIDGET]: (props) => {
|
||||
if (props.source?.pluginType) {
|
||||
|
|
@ -25,19 +24,16 @@ export const getIconForEntity: Record<
|
|||
[ENTITY_TYPE.JSACTION]: () => {
|
||||
return JsFileIconV2(16, 16, true, true);
|
||||
},
|
||||
[ENTITY_TYPE.ACTION]: (props, pluginGroups) => {
|
||||
[ENTITY_TYPE.ACTION]: (props, pluginImages) => {
|
||||
const { iconId, source } = props;
|
||||
if (source?.pluginType === PluginType.API && source.httpMethod) {
|
||||
// If the source is an API action.
|
||||
return ApiMethodIcon(source.httpMethod, "16px", "32px", 50);
|
||||
} else if (iconId && pluginGroups[iconId]) {
|
||||
} else if (iconId && pluginImages[iconId]) {
|
||||
// If the source is a Datasource action.
|
||||
return (
|
||||
<EntityIcon height={"16px"} noBackground noBorder width={"16px"}>
|
||||
<img
|
||||
alt="entityIcon"
|
||||
src={getAssetUrl(pluginGroups[iconId].iconLocation)}
|
||||
/>
|
||||
<img alt="entityIcon" src={getAssetUrl(pluginImages[iconId])} />
|
||||
</EntityIcon>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ import { BlankStateContainer } from "pages/Editor/IDE/EditorPane/JS/BlankStateCo
|
|||
import { useCurrentEditorState } from "pages/Editor/IDE/hooks";
|
||||
import history from "utils/history";
|
||||
import { FocusEntity, identifyEntityFromPath } from "navigation/FocusEntity";
|
||||
import { getJSUrl } from "./utils";
|
||||
import { useModuleOptions } from "@appsmith/utils/moduleInstanceHelpers";
|
||||
import { getJSUrl } from "@appsmith/pages/Editor/IDE/EditorPane/JS/utils";
|
||||
|
||||
export const useJSAdd = () => {
|
||||
const pageId = useSelector(getCurrentPageId);
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ import type { JSAction, Variable } from "entities/JSCollection";
|
|||
import keyBy from "lodash/keyBy";
|
||||
import { getActionConfig } from "pages/Editor/Explorer/Actions/helpers";
|
||||
import { JsFileIconV2 } from "pages/Editor/Explorer/ExplorerIcons";
|
||||
import { useMemo } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import type {
|
||||
ActionData,
|
||||
|
|
@ -69,9 +68,10 @@ import { setShowCreateNewModal } from "actions/propertyPaneActions";
|
|||
import { setIdeEditorViewMode } from "actions/ideActions";
|
||||
import { EditorViewMode } from "@appsmith/entities/IDE/constants";
|
||||
import { getIsSideBySideEnabled } from "selectors/ideSelectors";
|
||||
import { resolveIcon } from "pages/Editor/utils";
|
||||
import { getModuleIcon, getPluginImagesFromPlugins } from "pages/Editor/utils";
|
||||
import { getAllModules } from "@appsmith/selectors/modulesSelector";
|
||||
import type { Module } from "@appsmith/constants/ModuleConstants";
|
||||
import type { Plugin } from "api/PluginApi";
|
||||
|
||||
const actionList: {
|
||||
label: string;
|
||||
|
|
@ -396,7 +396,7 @@ export function useModalDropdownList(handleClose: () => void) {
|
|||
|
||||
export function getApiQueriesAndJSActionOptionsWithChildren(
|
||||
pageId: string,
|
||||
plugins: any,
|
||||
plugins: Plugin[],
|
||||
actions: ActionDataState,
|
||||
jsActions: Array<JSCollectionData>,
|
||||
dispatch: any,
|
||||
|
|
@ -422,7 +422,7 @@ export function getApiQueriesAndJSActionOptionsWithChildren(
|
|||
}
|
||||
|
||||
function getApiAndQueryOptions(
|
||||
plugins: any,
|
||||
plugins: Plugin[],
|
||||
actions: ActionDataState,
|
||||
dispatch: any,
|
||||
handleClose: () => void,
|
||||
|
|
@ -431,6 +431,8 @@ function getApiAndQueryOptions(
|
|||
) {
|
||||
const state = store.getState();
|
||||
const isSideBySideEnabled = getIsSideBySideEnabled(state);
|
||||
const pluginImages = getPluginImagesFromPlugins(plugins);
|
||||
const pluginGroups: any = keyBy(plugins, "id");
|
||||
|
||||
const createQueryObject: TreeDropdownOption = {
|
||||
label: "New query",
|
||||
|
|
@ -474,7 +476,7 @@ function getApiAndQueryOptions(
|
|||
type: queryOptions.value,
|
||||
icon: getActionConfig(api.config.pluginType)?.getIcon(
|
||||
api.config,
|
||||
plugins[(api as any).config.datasource.pluginId],
|
||||
pluginGroups[(api as any).config.datasource.pluginId],
|
||||
api.config.pluginType === PluginType.API,
|
||||
),
|
||||
} as TreeDropdownOption);
|
||||
|
|
@ -488,7 +490,7 @@ function getApiAndQueryOptions(
|
|||
type: queryOptions.value,
|
||||
icon: getActionConfig(query.config.pluginType)?.getIcon(
|
||||
query.config,
|
||||
plugins[(query as any).config.datasource.pluginId],
|
||||
pluginGroups[(query as any).config.datasource.pluginId],
|
||||
),
|
||||
} as TreeDropdownOption);
|
||||
});
|
||||
|
|
@ -499,11 +501,7 @@ function getApiAndQueryOptions(
|
|||
id: instance.config.id,
|
||||
value: instance.config.name,
|
||||
type: queryOptions.value,
|
||||
icon: resolveIcon({
|
||||
iconLocation: plugins[module.pluginId]?.iconLocation || "",
|
||||
pluginType: module.pluginType,
|
||||
moduleType: module.type,
|
||||
}),
|
||||
icon: getModuleIcon(module, pluginImages),
|
||||
} as TreeDropdownOption);
|
||||
});
|
||||
}
|
||||
|
|
@ -629,7 +627,6 @@ export function useApisQueriesAndJsActionOptions(handleClose: () => void) {
|
|||
const plugins = useSelector((state: AppState) => {
|
||||
return state.entities.plugins.list;
|
||||
});
|
||||
const pluginGroups: any = useMemo(() => keyBy(plugins, "id"), [plugins]);
|
||||
const actions = useSelector(getCurrentActions);
|
||||
const jsActions = useSelector(getCurrentJSCollections);
|
||||
const queryModuleInstances = useSelector(
|
||||
|
|
@ -641,7 +638,7 @@ export function useApisQueriesAndJsActionOptions(handleClose: () => void) {
|
|||
// this function gets all the Queries/API's/JS Objects and attaches it to actionList
|
||||
return getApiQueriesAndJSActionOptionsWithChildren(
|
||||
pageId,
|
||||
pluginGroups,
|
||||
plugins,
|
||||
actions,
|
||||
jsActions,
|
||||
dispatch,
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { getPlugins } from "@appsmith/selectors/entitiesSelector";
|
|||
import EntityLink from "../../EntityLink";
|
||||
import { DebuggerLinkUI } from "components/editorComponents/Debugger/DebuggerEntityLink";
|
||||
import { getIconForEntity } from "@appsmith/components/editorComponents/Debugger/ErrorLogs/getLogIconForEntity";
|
||||
import type { Plugin } from "api/PluginApi";
|
||||
import { getPluginImagesFromPlugins } from "pages/Editor/utils";
|
||||
|
||||
const EntityLinkWrapper = styled.div`
|
||||
display: flex;
|
||||
|
|
@ -30,11 +30,11 @@ const IconWrapper = styled.span`
|
|||
`;
|
||||
|
||||
// This function is used to fetch the icon component for the entity link.
|
||||
const getIcon = (props: LogItemProps, pluginGroups: Record<string, Plugin>) => {
|
||||
const getIcon = (props: LogItemProps, pluginImages: Record<string, string>) => {
|
||||
const entityType = props.source?.type;
|
||||
let icon = null;
|
||||
if (entityType) {
|
||||
icon = getIconForEntity[entityType](props, pluginGroups);
|
||||
icon = getIconForEntity[entityType](props, pluginImages);
|
||||
}
|
||||
return icon || <img alt="icon" src={undefined} />;
|
||||
};
|
||||
|
|
@ -43,6 +43,7 @@ const getIcon = (props: LogItemProps, pluginGroups: Record<string, Plugin>) => {
|
|||
export default function LogEntityLink(props: LogItemProps) {
|
||||
const plugins = useSelector(getPlugins);
|
||||
const pluginGroups = useMemo(() => keyBy(plugins, "id"), [plugins]);
|
||||
const pluginImages = getPluginImagesFromPlugins(plugins);
|
||||
|
||||
const plugin = props.iconId ? pluginGroups[props.iconId] : undefined;
|
||||
return (
|
||||
|
|
@ -55,7 +56,7 @@ export default function LogEntityLink(props: LogItemProps) {
|
|||
lineHeight: "14px",
|
||||
}}
|
||||
>
|
||||
<IconWrapper>{getIcon(props, pluginGroups)}</IconWrapper>
|
||||
<IconWrapper>{getIcon(props, pluginImages)}</IconWrapper>
|
||||
<EntityLink
|
||||
appsmithErrorCode={props.pluginErrorDetails?.appsmithErrorCode}
|
||||
errorSubType={props.messages && props.messages[0].message.name}
|
||||
|
|
|
|||
|
|
@ -27,9 +27,7 @@ import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag";
|
|||
import type { AppState } from "@appsmith/reducers";
|
||||
import type { Module } from "@appsmith/constants/ModuleConstants";
|
||||
import { getAllModules } from "@appsmith/selectors/modulesSelector";
|
||||
import { resolveIcon } from "pages/Editor/utils";
|
||||
import { Icon } from "design-system";
|
||||
import { EntityIcon } from "pages/Editor/Explorer/ExplorerIcons";
|
||||
import { getModuleIcon } from "pages/Editor/utils";
|
||||
|
||||
enum SortingWeights {
|
||||
alphabetical = 1,
|
||||
|
|
@ -105,19 +103,8 @@ export const getQueryIcon = (
|
|||
if (query.config.hasOwnProperty("type")) {
|
||||
const q = query as ModuleInstanceData;
|
||||
const module = modules[q.config.sourceModuleId];
|
||||
const icon = resolveIcon({
|
||||
iconLocation: pluginImages[module.pluginId] || "",
|
||||
pluginType: module.pluginType,
|
||||
moduleType: module.type,
|
||||
});
|
||||
|
||||
return (
|
||||
icon || (
|
||||
<EntityIcon>
|
||||
<Icon name="module" />
|
||||
</EntityIcon>
|
||||
)
|
||||
);
|
||||
return getModuleIcon(module, pluginImages);
|
||||
} else {
|
||||
const action = query as ActionData;
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ const SortingDropdownContainer = styled.div<{ size: string }>`
|
|||
gap: 5px;
|
||||
align-items: center;
|
||||
> div {
|
||||
width: 270px;
|
||||
width: 250px;
|
||||
}
|
||||
${(props) =>
|
||||
props.size === "small" &&
|
||||
|
|
@ -168,6 +168,9 @@ function SortingComponent(props: any) {
|
|||
<FormControl
|
||||
config={{
|
||||
...columnFieldConfig,
|
||||
customStyles: {
|
||||
width: "250px",
|
||||
},
|
||||
configProperty: `${columnPath}`,
|
||||
nestedFormControl: true,
|
||||
}}
|
||||
|
|
@ -180,9 +183,9 @@ function SortingComponent(props: any) {
|
|||
configProperty: `${OrderPath}`,
|
||||
nestedFormControl: true,
|
||||
customStyles: {
|
||||
width: isBreakpointSmall ? "65px" : "270px",
|
||||
width: isBreakpointSmall ? "65px" : "250px",
|
||||
},
|
||||
optionWidth: isBreakpointSmall ? "270px" : undefined,
|
||||
optionWidth: isBreakpointSmall ? "250px" : undefined,
|
||||
}}
|
||||
formName={props.formName}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ import {
|
|||
getPlugins,
|
||||
} from "@appsmith/selectors/entitiesSelector";
|
||||
import store from "store";
|
||||
import keyBy from "lodash/keyBy";
|
||||
import { getCurrentPageId } from "selectors/editorSelectors";
|
||||
import { getApiQueriesAndJSActionOptionsWithChildren } from "components/editorComponents/ActionCreator/helpers";
|
||||
import { selectEvaluationVersion } from "@appsmith/selectors/applicationSelectors";
|
||||
|
|
@ -152,12 +151,11 @@ class ActionSelectorControl extends BaseControl<ControlProps> {
|
|||
|
||||
const pageId = getCurrentPageId(state);
|
||||
const plugins = getPlugins(state);
|
||||
const pluginGroups: any = keyBy(plugins, "id");
|
||||
|
||||
// this function gets all the Queries/API's/JS Objects and attaches it to actionList
|
||||
const fieldOptions = getApiQueriesAndJSActionOptionsWithChildren(
|
||||
pageId,
|
||||
pluginGroups,
|
||||
plugins,
|
||||
actions,
|
||||
jsCollections,
|
||||
() => {
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ import ConvertEntityNotification from "@appsmith/pages/common/ConvertEntityNotif
|
|||
import { useIsEditorPaneSegmentsEnabled } from "../IDE/hooks";
|
||||
import { Icon } from "design-system";
|
||||
import { resolveIcon } from "../utils";
|
||||
import { ENTITY_ICON_SIZE, EntityIcon } from "../Explorer/ExplorerIcons";
|
||||
|
||||
type ApiEditorWrapperProps = RouteComponentProps<APIEditorRouteParams>;
|
||||
|
||||
|
|
@ -72,7 +73,14 @@ function ApiEditorWrapper(props: ApiEditorWrapperProps) {
|
|||
iconLocation: pluginGroups[pluginId]?.iconLocation || "",
|
||||
pluginType: action?.pluginType || "",
|
||||
moduleType: action?.actionConfiguration?.body?.moduleType,
|
||||
}) || <Icon name="module" />;
|
||||
}) || (
|
||||
<EntityIcon
|
||||
height={`${ENTITY_ICON_SIZE}px`}
|
||||
width={`${ENTITY_ICON_SIZE}px`}
|
||||
>
|
||||
<Icon name="module" />
|
||||
</EntityIcon>
|
||||
);
|
||||
|
||||
const isChangePermitted = getHasManageActionPermission(
|
||||
isFeatureEnabled,
|
||||
|
|
|
|||
|
|
@ -337,3 +337,11 @@ export function AppsmithAIIcon() {
|
|||
export function ActionUrlIcon(url: string) {
|
||||
return <img src={url} />;
|
||||
}
|
||||
|
||||
export function DefaultModuleIcon() {
|
||||
return (
|
||||
<EntityIcon>
|
||||
<Icon name="module" size="sm" />
|
||||
</EntityIcon>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ interface SettingsHeadingProps {
|
|||
hasInfo?: boolean;
|
||||
info?: string;
|
||||
grow: boolean;
|
||||
headingCount: number;
|
||||
}
|
||||
|
||||
export interface OnUpdateSettingsProps {
|
||||
|
|
@ -24,10 +25,14 @@ export interface OnUpdateSettingsProps {
|
|||
}
|
||||
|
||||
interface SettingsItemProps {
|
||||
headingCount: number;
|
||||
action: JSAction;
|
||||
disabled?: boolean;
|
||||
onUpdateSettings?: (props: OnUpdateSettingsProps) => void;
|
||||
renderAdditionalColumns?: (action: JSAction) => React.ReactNode;
|
||||
renderAdditionalColumns?: (
|
||||
action: JSAction,
|
||||
headingCount: number,
|
||||
) => React.ReactNode;
|
||||
}
|
||||
|
||||
export interface JSFunctionSettingsProps {
|
||||
|
|
@ -61,6 +66,7 @@ const StyledIcon = styled(Icon)`
|
|||
`;
|
||||
|
||||
export const SettingColumn = styled.div<{
|
||||
headingCount: number;
|
||||
grow?: boolean;
|
||||
isHeading?: boolean;
|
||||
}>`
|
||||
|
|
@ -68,13 +74,13 @@ export const SettingColumn = styled.div<{
|
|||
align-items: center;
|
||||
flex-grow: ${(props) => (props.grow ? 1 : 0)};
|
||||
padding: 5px 12px;
|
||||
min-width: 250px;
|
||||
width: ${({ headingCount }) => `calc(100% / ${headingCount})`};
|
||||
|
||||
${(props) =>
|
||||
props.isHeading &&
|
||||
`
|
||||
font-weight: ${props.theme.fontWeights[2]};
|
||||
font-size: ${props.theme.fontSizes[2]}px
|
||||
font-size: ${props.theme.fontSizes[2]}px;
|
||||
margin-right: 9px;
|
||||
`}
|
||||
|
||||
|
|
@ -91,8 +97,7 @@ const JSFunctionSettingsWrapper = styled.div`
|
|||
const SettingsContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: max-content;
|
||||
min-width: 700px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
& > h3 {
|
||||
margin: 20px 0;
|
||||
|
|
@ -116,9 +121,15 @@ const SettingsBodyWrapper = styled.div`
|
|||
const SwitchWrapper = styled.div`
|
||||
margin-left: 6ch;
|
||||
`;
|
||||
function SettingsHeading({ grow, hasInfo, info, text }: SettingsHeadingProps) {
|
||||
function SettingsHeading({
|
||||
grow,
|
||||
hasInfo,
|
||||
headingCount,
|
||||
info,
|
||||
text,
|
||||
}: SettingsHeadingProps) {
|
||||
return (
|
||||
<SettingColumn grow={grow} isHeading>
|
||||
<SettingColumn grow={grow} headingCount={headingCount} isHeading>
|
||||
<span>{text}</span>
|
||||
{hasInfo && info && (
|
||||
<Tooltip content={createMessage(() => info)}>
|
||||
|
|
@ -132,6 +143,7 @@ function SettingsHeading({ grow, hasInfo, info, text }: SettingsHeadingProps) {
|
|||
function SettingsItem({
|
||||
action,
|
||||
disabled,
|
||||
headingCount,
|
||||
onUpdateSettings,
|
||||
renderAdditionalColumns,
|
||||
}: SettingsItemProps) {
|
||||
|
|
@ -174,10 +186,13 @@ function SettingsItem({
|
|||
className="t--async-js-function-settings"
|
||||
id={`${action.name}-settings`}
|
||||
>
|
||||
<SettingColumn grow>
|
||||
<SettingColumn grow headingCount={headingCount}>
|
||||
<span>{action.name}</span>
|
||||
</SettingColumn>
|
||||
<SettingColumn className={`${action.name}-on-page-load-setting`}>
|
||||
<SettingColumn
|
||||
className={`${action.name}-on-page-load-setting`}
|
||||
headingCount={headingCount}
|
||||
>
|
||||
{RADIO_OPTIONS.length > 2 ? (
|
||||
<RadioGroup
|
||||
defaultValue={executeOnPageLoad}
|
||||
|
|
@ -207,7 +222,10 @@ function SettingsItem({
|
|||
</SwitchWrapper>
|
||||
)}
|
||||
</SettingColumn>
|
||||
<SettingColumn className={`${action.name}-confirm-before-execute`}>
|
||||
<SettingColumn
|
||||
className={`${action.name}-confirm-before-execute`}
|
||||
headingCount={headingCount}
|
||||
>
|
||||
{RADIO_OPTIONS.length > 2 ? (
|
||||
<RadioGroup
|
||||
defaultValue={confirmBeforeExecute}
|
||||
|
|
@ -238,7 +256,7 @@ function SettingsItem({
|
|||
</SwitchWrapper>
|
||||
)}
|
||||
</SettingColumn>
|
||||
{renderAdditionalColumns?.(action)}
|
||||
{renderAdditionalColumns?.(action, headingCount)}
|
||||
</SettingRow>
|
||||
);
|
||||
}
|
||||
|
|
@ -250,6 +268,7 @@ function JSFunctionSettingsView({
|
|||
onUpdateSettings,
|
||||
renderAdditionalColumns,
|
||||
}: JSFunctionSettingsProps) {
|
||||
const headings = [...SETTINGS_HEADINGS, ...additionalHeadings];
|
||||
return (
|
||||
<JSFunctionSettingsWrapper>
|
||||
<SettingsContainer>
|
||||
|
|
@ -257,17 +276,16 @@ function JSFunctionSettingsView({
|
|||
<SettingsRowWrapper>
|
||||
<SettingsHeaderWrapper>
|
||||
<SettingRow isHeading>
|
||||
{[...SETTINGS_HEADINGS, ...additionalHeadings].map(
|
||||
(setting, index) => (
|
||||
<SettingsHeading
|
||||
grow={index === 0}
|
||||
hasInfo={setting.hasInfo}
|
||||
info={setting.info}
|
||||
key={setting.key}
|
||||
text={setting.text}
|
||||
/>
|
||||
),
|
||||
)}
|
||||
{headings.map((setting, index) => (
|
||||
<SettingsHeading
|
||||
grow={index === 0}
|
||||
hasInfo={setting.hasInfo}
|
||||
headingCount={headings.length}
|
||||
info={setting.info}
|
||||
key={setting.key}
|
||||
text={setting.text}
|
||||
/>
|
||||
))}
|
||||
</SettingRow>
|
||||
</SettingsHeaderWrapper>
|
||||
<SettingsBodyWrapper>
|
||||
|
|
@ -276,6 +294,7 @@ function JSFunctionSettingsView({
|
|||
<SettingsItem
|
||||
action={action}
|
||||
disabled={disabled}
|
||||
headingCount={headings.length}
|
||||
key={action.id}
|
||||
onUpdateSettings={onUpdateSettings}
|
||||
renderAdditionalColumns={renderAdditionalColumns}
|
||||
|
|
@ -283,7 +302,9 @@ function JSFunctionSettingsView({
|
|||
))
|
||||
) : (
|
||||
<SettingRow noBorder>
|
||||
<SettingColumn>{createMessage(NO_JS_FUNCTIONS)}</SettingColumn>
|
||||
<SettingColumn headingCount={0}>
|
||||
{createMessage(NO_JS_FUNCTIONS)}
|
||||
</SettingColumn>
|
||||
</SettingRow>
|
||||
)}
|
||||
</SettingsBodyWrapper>
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ import { PluginType } from "entities/Action";
|
|||
import { useIsEditorPaneSegmentsEnabled } from "../IDE/hooks";
|
||||
import { Icon } from "design-system";
|
||||
import { resolveIcon } from "../utils";
|
||||
import { ENTITY_ICON_SIZE, EntityIcon } from "../Explorer/ExplorerIcons";
|
||||
|
||||
type QueryEditorProps = RouteComponentProps<QueryEditorRouteParams>;
|
||||
|
||||
|
|
@ -66,7 +67,14 @@ function QueryEditor(props: QueryEditorProps) {
|
|||
iconLocation: pluginImages[pluginId] || "",
|
||||
pluginType: action?.pluginType || "",
|
||||
moduleType: action?.actionConfiguration?.body?.moduleType,
|
||||
}) || <Icon name="module" />;
|
||||
}) || (
|
||||
<EntityIcon
|
||||
height={`${ENTITY_ICON_SIZE}px`}
|
||||
width={`${ENTITY_ICON_SIZE}px`}
|
||||
>
|
||||
<Icon name="module" />
|
||||
</EntityIcon>
|
||||
);
|
||||
|
||||
const isDeletePermitted = getHasDeleteActionPermission(
|
||||
isFeatureEnabled,
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import { useSelector } from "react-redux";
|
|||
import { getCurrentPageId } from "selectors/editorSelectors";
|
||||
import type { WidgetCardProps } from "widgets/BaseWidget";
|
||||
import type { ActionResponse } from "api/ActionAPI";
|
||||
import type { Module } from "@appsmith/constants/ModuleConstants";
|
||||
import { MODULE_TYPE } from "@appsmith/constants/ModuleConstants";
|
||||
import {
|
||||
ENTITY_ICON_SIZE,
|
||||
|
|
@ -29,6 +30,9 @@ import {
|
|||
} from "pages/Editor/Explorer/ExplorerIcons";
|
||||
import { PluginType } from "entities/Action";
|
||||
import { getAssetUrl } from "@appsmith/utils/airgapHelpers";
|
||||
import type { Plugin } from "api/PluginApi";
|
||||
import ImageAlt from "assets/images/placeholder-image.svg";
|
||||
import { Icon } from "design-system";
|
||||
|
||||
export const draggableElement = (
|
||||
id: string,
|
||||
|
|
@ -381,3 +385,33 @@ export function resolveIcon({
|
|||
return resolveQueryModuleIcon(iconLocation, pluginType, isLargeIcon);
|
||||
}
|
||||
}
|
||||
|
||||
export function getModuleIcon(
|
||||
module: Module | undefined,
|
||||
pluginImages: Record<string, string>,
|
||||
isLargeIcon = false,
|
||||
) {
|
||||
return module ? (
|
||||
resolveIcon({
|
||||
iconLocation: pluginImages[module.pluginId] || "",
|
||||
pluginType: module.pluginType,
|
||||
moduleType: module.type,
|
||||
isLargeIcon,
|
||||
})
|
||||
) : (
|
||||
<EntityIcon
|
||||
height={`${isLargeIcon ? ENTITY_ICON_SIZE * 2 : ENTITY_ICON_SIZE}px`}
|
||||
width={`${isLargeIcon ? ENTITY_ICON_SIZE * 2 : ENTITY_ICON_SIZE}px`}
|
||||
>
|
||||
<Icon name="module" />
|
||||
</EntityIcon>
|
||||
);
|
||||
}
|
||||
|
||||
export function getPluginImagesFromPlugins(plugins: Plugin[]) {
|
||||
const pluginImages: Record<string, string> = {};
|
||||
plugins.forEach((plugin) => {
|
||||
pluginImages[plugin.id] = plugin?.iconLocation ?? ImageAlt;
|
||||
});
|
||||
return pluginImages;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,9 +16,9 @@ import com.appsmith.external.models.Executable;
|
|||
import com.appsmith.external.models.PluginType;
|
||||
import com.appsmith.external.models.Policy;
|
||||
import com.appsmith.external.models.Property;
|
||||
import com.appsmith.external.views.ResponseOnly;
|
||||
import com.appsmith.external.views.Views;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonView;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
|
@ -88,8 +88,9 @@ public class ActionCE_DTO implements Identifiable, Executable {
|
|||
ActionConfiguration actionConfiguration;
|
||||
|
||||
// this attribute carries error messages while processing the actionCollection
|
||||
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
|
||||
@Transient
|
||||
@JsonView(ResponseOnly.class)
|
||||
@JsonView(Views.Public.class)
|
||||
List<ErrorDTO> errorReports;
|
||||
|
||||
@JsonView(Views.Public.class)
|
||||
|
|
@ -105,19 +106,23 @@ public class ActionCE_DTO implements Identifiable, Executable {
|
|||
@JsonView(Views.Public.class)
|
||||
List<Property> dynamicBindingPathList;
|
||||
|
||||
@JsonView(ResponseOnly.class)
|
||||
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
|
||||
@JsonView(Views.Public.class)
|
||||
Boolean isValid;
|
||||
|
||||
@JsonView(ResponseOnly.class)
|
||||
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
|
||||
@JsonView(Views.Public.class)
|
||||
Set<String> invalids;
|
||||
|
||||
@Transient
|
||||
@JsonView(ResponseOnly.class)
|
||||
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
|
||||
@JsonView(Views.Public.class)
|
||||
Set<String> messages = new HashSet<>();
|
||||
|
||||
// This is a list of keys that the client whose values the client needs to send during action execution.
|
||||
// These are the Mustache keys that the server will replace before invoking the API
|
||||
@JsonView(ResponseOnly.class)
|
||||
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
|
||||
@JsonView(Views.Public.class)
|
||||
Set<String> jsonPathKeys;
|
||||
|
||||
@JsonView(Views.Internal.class)
|
||||
|
|
|
|||
|
|
@ -1,7 +0,0 @@
|
|||
package com.appsmith.external.views;
|
||||
|
||||
/**
|
||||
* Intended to annotate fields that can be set by HTTP request payloads, but should NOT be included
|
||||
* in HTTP responses sent back to the client.
|
||||
*/
|
||||
public interface RequestOnly extends Views.Public {}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
package com.appsmith.external.views;
|
||||
|
||||
/**
|
||||
* Intended to mark entity/DTO fields that should be included as part of HTTP responses, but should
|
||||
* be ignored as part of HTTP requests. For example, if a field is marked with this annotation, in
|
||||
* a class used with {@code @RequestBody}, it's value will NOT be deserialized.
|
||||
*/
|
||||
public interface ResponseOnly extends Views.Public {}
|
||||
|
|
@ -92,11 +92,7 @@
|
|||
"isRequired": false,
|
||||
"initialValue": "Appsmith",
|
||||
"placeholderText": "Appsmith",
|
||||
"hidden": {
|
||||
"path": "datasourceConfiguration.properties[0].value",
|
||||
"comparison": "NOT_EQUALS",
|
||||
"value": "FORM_PROPERTIES_CONFIGURATION"
|
||||
}
|
||||
"hidden": true
|
||||
},
|
||||
{
|
||||
"label": "JDBC URL",
|
||||
|
|
|
|||
|
|
@ -45,6 +45,11 @@ public interface ActionCollectionServiceCE extends CrudService<ActionCollection,
|
|||
|
||||
Mono<ActionCollectionDTO> deleteUnpublishedActionCollection(String id);
|
||||
|
||||
Mono<ActionCollectionDTO> deleteUnpublishedActionCollectionWithOptionalPermission(
|
||||
String id,
|
||||
Optional<AclPermission> deleteCollectionPermission,
|
||||
Optional<AclPermission> deleteActionPermission);
|
||||
|
||||
Mono<ActionCollectionDTO> deleteWithoutPermissionUnpublishedActionCollection(String id);
|
||||
|
||||
Mono<ActionCollectionDTO> deleteUnpublishedActionCollection(String id, String branchName);
|
||||
|
|
|
|||
|
|
@ -356,16 +356,28 @@ public class ActionCollectionServiceCEImpl extends BaseService<ActionCollectionR
|
|||
|
||||
@Override
|
||||
public Mono<ActionCollectionDTO> deleteWithoutPermissionUnpublishedActionCollection(String id) {
|
||||
return deleteUnpublishedActionCollectionEx(id, Optional.empty());
|
||||
return deleteUnpublishedActionCollectionEx(
|
||||
id, Optional.empty(), Optional.of(actionPermission.getDeletePermission()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<ActionCollectionDTO> deleteUnpublishedActionCollection(String id) {
|
||||
return deleteUnpublishedActionCollectionEx(id, Optional.of(actionPermission.getDeletePermission()));
|
||||
return deleteUnpublishedActionCollectionEx(
|
||||
id,
|
||||
Optional.of(actionPermission.getDeletePermission()),
|
||||
Optional.of(actionPermission.getDeletePermission()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<ActionCollectionDTO> deleteUnpublishedActionCollectionWithOptionalPermission(
|
||||
String id,
|
||||
Optional<AclPermission> deleteCollectionPermission,
|
||||
Optional<AclPermission> deleteActionPermission) {
|
||||
return deleteUnpublishedActionCollectionEx(id, deleteCollectionPermission, deleteActionPermission);
|
||||
}
|
||||
|
||||
public Mono<ActionCollectionDTO> deleteUnpublishedActionCollectionEx(
|
||||
String id, Optional<AclPermission> permission) {
|
||||
String id, Optional<AclPermission> permission, Optional<AclPermission> deleteActionPermission) {
|
||||
Mono<ActionCollection> actionCollectionMono = repository
|
||||
.findById(id, permission)
|
||||
.switchIfEmpty(Mono.error(
|
||||
|
|
@ -381,7 +393,7 @@ public class ActionCollectionServiceCEImpl extends BaseService<ActionCollectionR
|
|||
.getDefaultToBranchedActionIdsMap()
|
||||
.values())
|
||||
.flatMap(actionId -> newActionService
|
||||
.deleteUnpublishedAction(actionId)
|
||||
.deleteUnpublishedActionWithOptionalPermission(actionId, deleteActionPermission)
|
||||
// return an empty action so that the filter can remove it from the list
|
||||
.onErrorResume(throwable -> {
|
||||
log.debug(
|
||||
|
|
|
|||
|
|
@ -6,19 +6,23 @@ import com.appsmith.server.newactions.base.NewActionService;
|
|||
import com.appsmith.server.refactors.applications.RefactoringService;
|
||||
import com.appsmith.server.services.LayoutActionService;
|
||||
import com.appsmith.server.solutions.ActionExecutionSolution;
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping(Url.ACTION_URL)
|
||||
@Slf4j
|
||||
public class ActionController extends ActionControllerCE {
|
||||
|
||||
public ActionController(
|
||||
LayoutActionService layoutActionService,
|
||||
NewActionService newActionService,
|
||||
RefactoringService refactoringService,
|
||||
ActionExecutionSolution actionExecutionSolution) {
|
||||
ActionExecutionSolution actionExecutionSolution,
|
||||
ObservationRegistry observationRegistry) {
|
||||
|
||||
super(layoutActionService, newActionService, refactoringService, actionExecutionSolution);
|
||||
super(layoutActionService, newActionService, refactoringService, actionExecutionSolution, observationRegistry);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package com.appsmith.server.controllers.ce;
|
|||
|
||||
import com.appsmith.external.models.ActionDTO;
|
||||
import com.appsmith.external.models.ActionExecutionResult;
|
||||
import com.appsmith.external.views.RequestOnly;
|
||||
import com.appsmith.external.views.Views;
|
||||
import com.appsmith.server.constants.FieldName;
|
||||
import com.appsmith.server.constants.Url;
|
||||
|
|
@ -17,6 +16,7 @@ import com.appsmith.server.refactors.applications.RefactoringService;
|
|||
import com.appsmith.server.services.LayoutActionService;
|
||||
import com.appsmith.server.solutions.ActionExecutionSolution;
|
||||
import com.fasterxml.jackson.annotation.JsonView;
|
||||
import io.micrometer.observation.ObservationRegistry;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
|
@ -48,25 +48,30 @@ public class ActionControllerCE {
|
|||
private final NewActionService newActionService;
|
||||
private final RefactoringService refactoringService;
|
||||
private final ActionExecutionSolution actionExecutionSolution;
|
||||
private final ObservationRegistry observationRegistry;
|
||||
|
||||
@Autowired
|
||||
public ActionControllerCE(
|
||||
LayoutActionService layoutActionService,
|
||||
NewActionService newActionService,
|
||||
RefactoringService refactoringService,
|
||||
ActionExecutionSolution actionExecutionSolution) {
|
||||
ActionExecutionSolution actionExecutionSolution,
|
||||
ObservationRegistry observationRegistry) {
|
||||
this.layoutActionService = layoutActionService;
|
||||
this.newActionService = newActionService;
|
||||
this.refactoringService = refactoringService;
|
||||
this.actionExecutionSolution = actionExecutionSolution;
|
||||
this.observationRegistry = observationRegistry;
|
||||
}
|
||||
|
||||
@JsonView(Views.Public.class)
|
||||
@PostMapping
|
||||
@ResponseStatus(HttpStatus.CREATED)
|
||||
public Mono<ResponseDTO<ActionDTO>> createAction(
|
||||
@Valid @RequestBody @JsonView(RequestOnly.class) ActionDTO resource,
|
||||
@RequestHeader(name = FieldName.BRANCH_NAME, required = false) String branchName) {
|
||||
@Valid @RequestBody ActionDTO resource,
|
||||
@RequestHeader(name = FieldName.BRANCH_NAME, required = false) String branchName,
|
||||
@RequestHeader(name = "Origin", required = false) String originHeader,
|
||||
ServerWebExchange exchange) {
|
||||
log.debug("Going to create resource {}", resource.getClass().getName());
|
||||
return layoutActionService
|
||||
.createSingleActionWithBranch(resource, branchName)
|
||||
|
|
@ -77,7 +82,7 @@ public class ActionControllerCE {
|
|||
@PutMapping("/{defaultActionId}")
|
||||
public Mono<ResponseDTO<ActionDTO>> updateAction(
|
||||
@PathVariable String defaultActionId,
|
||||
@Valid @RequestBody @JsonView(RequestOnly.class) ActionDTO resource,
|
||||
@Valid @RequestBody ActionDTO resource,
|
||||
@RequestHeader(name = FieldName.BRANCH_NAME, required = false) String branchName) {
|
||||
log.debug("Going to update resource with defaultActionId: {}, branch: {}", defaultActionId, branchName);
|
||||
return layoutActionService
|
||||
|
|
@ -173,6 +178,9 @@ public class ActionControllerCE {
|
|||
* <p>
|
||||
* The controller function is primarily used with param applicationId by the client to fetch the actions in edit
|
||||
* mode.
|
||||
*
|
||||
* @param params
|
||||
* @return
|
||||
*/
|
||||
@JsonView(Views.Public.class)
|
||||
@GetMapping("")
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import java.util.Set;
|
|||
import static com.appsmith.server.constants.ResourceModes.EDIT;
|
||||
import static com.appsmith.server.constants.ResourceModes.VIEW;
|
||||
import static com.appsmith.server.helpers.DateUtils.ISO_FORMATTER;
|
||||
import static com.appsmith.server.helpers.StringUtils.dotted;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
|
|
@ -484,14 +485,14 @@ public class Application extends BaseDomain implements Artifact {
|
|||
|
||||
public static class Fields extends BaseDomain.Fields {
|
||||
public static final String gitApplicationMetadata_gitAuth =
|
||||
gitApplicationMetadata + "." + GitArtifactMetadata.Fields.gitAuth;
|
||||
dotted(gitApplicationMetadata, GitArtifactMetadata.Fields.gitAuth);
|
||||
public static final String gitApplicationMetadata_defaultApplicationId =
|
||||
gitApplicationMetadata + "." + GitArtifactMetadata.Fields.defaultApplicationId;
|
||||
dotted(gitApplicationMetadata, GitArtifactMetadata.Fields.defaultApplicationId);
|
||||
public static final String gitApplicationMetadata_branchName =
|
||||
gitApplicationMetadata + "." + GitArtifactMetadata.Fields.branchName;
|
||||
dotted(gitApplicationMetadata, GitArtifactMetadata.Fields.branchName);
|
||||
public static final String gitApplicationMetadata_isRepoPrivate =
|
||||
gitApplicationMetadata + "." + GitArtifactMetadata.Fields.isRepoPrivate;
|
||||
dotted(gitApplicationMetadata, GitArtifactMetadata.Fields.isRepoPrivate);
|
||||
public static final String gitApplicationMetadata_isProtectedBranch =
|
||||
gitApplicationMetadata + "." + GitArtifactMetadata.Fields.isProtectedBranch;
|
||||
dotted(gitApplicationMetadata, GitArtifactMetadata.Fields.isProtectedBranch);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ import lombok.Setter;
|
|||
import lombok.ToString;
|
||||
import lombok.experimental.FieldNameConstants;
|
||||
|
||||
import static com.appsmith.server.helpers.StringUtils.dotted;
|
||||
|
||||
/**
|
||||
* This class represents a collection of actions that may or may not belong to the same plugin.
|
||||
* The logic for grouping is agnostic of the handling of this collection
|
||||
|
|
@ -52,21 +54,21 @@ public class ActionCollectionCE extends BranchAwareDomain {
|
|||
|
||||
public static class Fields extends BranchAwareDomain.Fields {
|
||||
public static final String publishedCollection_name =
|
||||
publishedCollection + "." + ActionCollectionDTO.Fields.name;
|
||||
dotted(publishedCollection, ActionCollectionDTO.Fields.name);
|
||||
public static final String unpublishedCollection_name =
|
||||
unpublishedCollection + "." + ActionCollectionDTO.Fields.name;
|
||||
dotted(unpublishedCollection, ActionCollectionDTO.Fields.name);
|
||||
|
||||
public static final String publishedCollection_pageId =
|
||||
publishedCollection + "." + ActionCollectionDTO.Fields.pageId;
|
||||
dotted(publishedCollection, ActionCollectionDTO.Fields.pageId);
|
||||
public static final String unpublishedCollection_pageId =
|
||||
unpublishedCollection + "." + ActionCollectionDTO.Fields.pageId;
|
||||
dotted(unpublishedCollection, ActionCollectionDTO.Fields.pageId);
|
||||
|
||||
public static final String publishedCollection_contextType =
|
||||
publishedCollection + "." + ActionCollectionDTO.Fields.contextType;
|
||||
dotted(publishedCollection, ActionCollectionDTO.Fields.contextType);
|
||||
public static final String unpublishedCollection_contextType =
|
||||
unpublishedCollection + "." + ActionCollectionDTO.Fields.contextType;
|
||||
dotted(unpublishedCollection, ActionCollectionDTO.Fields.contextType);
|
||||
|
||||
public static final String unpublishedCollection_deletedAt =
|
||||
unpublishedCollection + "." + ActionCollectionDTO.Fields.deletedAt;
|
||||
dotted(unpublishedCollection, ActionCollectionDTO.Fields.deletedAt);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ import lombok.Setter;
|
|||
import lombok.ToString;
|
||||
import lombok.experimental.FieldNameConstants;
|
||||
|
||||
import static com.appsmith.server.helpers.StringUtils.dotted;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
|
|
@ -60,27 +62,23 @@ public class NewActionCE extends BranchAwareDomain {
|
|||
|
||||
public static class Fields extends BranchAwareDomain.Fields {
|
||||
public static final String unpublishedAction_datasource_id =
|
||||
String.join(".", unpublishedAction, ActionDTO.Fields.datasource, Datasource.Fields.id);
|
||||
public static final String unpublishedAction_name = String.join(".", unpublishedAction, ActionDTO.Fields.name);
|
||||
public static final String unpublishedAction_pageId =
|
||||
String.join(".", unpublishedAction, ActionDTO.Fields.pageId);
|
||||
public static final String unpublishedAction_deletedAt =
|
||||
String.join(".", unpublishedAction, ActionDTO.Fields.deletedAt);
|
||||
dotted(unpublishedAction, ActionDTO.Fields.datasource, Datasource.Fields.id);
|
||||
public static final String unpublishedAction_name = dotted(unpublishedAction, ActionDTO.Fields.name);
|
||||
public static final String unpublishedAction_pageId = dotted(unpublishedAction, ActionDTO.Fields.pageId);
|
||||
public static final String unpublishedAction_deletedAt = dotted(unpublishedAction, ActionDTO.Fields.deletedAt);
|
||||
public static final String unpublishedAction_contextType =
|
||||
String.join(".", unpublishedAction, ActionDTO.Fields.contextType);
|
||||
dotted(unpublishedAction, ActionDTO.Fields.contextType);
|
||||
public static final String unpublishedAction_userSetOnLoad =
|
||||
String.join(".", unpublishedAction, ActionDTO.Fields.userSetOnLoad);
|
||||
dotted(unpublishedAction, ActionDTO.Fields.userSetOnLoad);
|
||||
public static final String unpublishedAction_executeOnLoad =
|
||||
String.join(".", unpublishedAction, ActionDTO.Fields.executeOnLoad);
|
||||
dotted(unpublishedAction, ActionDTO.Fields.executeOnLoad);
|
||||
public static final String unpublishedAction_fullyQualifiedName =
|
||||
String.join(".", unpublishedAction, ActionDTO.Fields.fullyQualifiedName);
|
||||
public static final String unpublishedAction_actionConfiguration_httpMethod = String.join(
|
||||
".", unpublishedAction, ActionDTO.Fields.actionConfiguration, ActionConfiguration.Fields.httpMethod);
|
||||
dotted(unpublishedAction, ActionDTO.Fields.fullyQualifiedName);
|
||||
public static final String unpublishedAction_actionConfiguration_httpMethod =
|
||||
dotted(unpublishedAction, ActionDTO.Fields.actionConfiguration, ActionConfiguration.Fields.httpMethod);
|
||||
|
||||
public static final String publishedAction_name = String.join(".", unpublishedAction, ActionDTO.Fields.name);
|
||||
public static final String publishedAction_pageId =
|
||||
String.join(".", unpublishedAction, ActionDTO.Fields.pageId);
|
||||
public static final String publishedAction_contextType =
|
||||
String.join(".", unpublishedAction, ActionDTO.Fields.contextType);
|
||||
public static final String publishedAction_name = dotted(publishedAction, ActionDTO.Fields.name);
|
||||
public static final String publishedAction_pageId = dotted(publishedAction, ActionDTO.Fields.pageId);
|
||||
public static final String publishedAction_contextType = dotted(publishedAction, ActionDTO.Fields.contextType);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
package com.appsmith.server.helpers;
|
||||
|
||||
public class StringUtils {
|
||||
private StringUtils() {}
|
||||
|
||||
public static String dotted(String... parts) {
|
||||
return String.join(".", parts);
|
||||
}
|
||||
}
|
||||
|
|
@ -82,6 +82,9 @@ public interface NewActionServiceCE extends CrudService<NewAction, String> {
|
|||
|
||||
Mono<ActionDTO> deleteUnpublishedAction(String id);
|
||||
|
||||
Mono<ActionDTO> deleteUnpublishedActionWithOptionalPermission(
|
||||
String id, Optional<AclPermission> newActionDeletePermission);
|
||||
|
||||
Flux<ActionDTO> getUnpublishedActions(MultiValueMap<String, String> params, Boolean includeJsActions);
|
||||
|
||||
Flux<ActionDTO> getUnpublishedActions(
|
||||
|
|
|
|||
|
|
@ -842,8 +842,14 @@ public class NewActionServiceCEImpl extends BaseService<NewActionRepository, New
|
|||
|
||||
@Override
|
||||
public Mono<ActionDTO> deleteUnpublishedAction(String id) {
|
||||
return deleteUnpublishedActionWithOptionalPermission(id, Optional.of(actionPermission.getDeletePermission()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<ActionDTO> deleteUnpublishedActionWithOptionalPermission(
|
||||
String id, Optional<AclPermission> newActionDeletePermission) {
|
||||
Mono<NewAction> actionMono = repository
|
||||
.findById(id, actionPermission.getDeletePermission())
|
||||
.findById(id, newActionDeletePermission)
|
||||
.switchIfEmpty(
|
||||
Mono.error(new AppsmithException(AppsmithError.NO_RESOURCE_FOUND, FieldName.ACTION, id)));
|
||||
return actionMono
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ import java.util.HashMap;
|
|||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.appsmith.external.helpers.AppsmithBeanUtils.copyNestedNonNullProperties;
|
||||
|
|
@ -98,7 +99,7 @@ public class NewActionImportableServiceCEImpl implements ImportableServiceCE<New
|
|||
log.info("Deleting {} actions which are no more used", invalidActionIds.size());
|
||||
return Flux.fromIterable(invalidActionIds)
|
||||
.flatMap(actionId -> newActionService
|
||||
.deleteUnpublishedAction(actionId)
|
||||
.deleteUnpublishedActionWithOptionalPermission(actionId, Optional.empty())
|
||||
// return an empty action so that the filter can remove it from the list
|
||||
.onErrorResume(throwable -> {
|
||||
log.debug("Failed to delete action with id {} during import", actionId);
|
||||
|
|
|
|||
|
|
@ -358,7 +358,14 @@ public class NewPageImportableServiceCEImpl implements ImportableServiceCE<NewPa
|
|||
// Delete the pages which were removed during git merge operation
|
||||
// This does not apply to the traditional import via file approach
|
||||
return Flux.fromIterable(invalidPageIds)
|
||||
.flatMap(applicationPageService::deleteWithoutPermissionUnpublishedPage)
|
||||
.flatMap(pageId -> {
|
||||
return applicationPageService.deleteUnpublishedPageWithOptionalPermission(
|
||||
pageId,
|
||||
Optional.empty(),
|
||||
Optional.empty(),
|
||||
Optional.empty(),
|
||||
Optional.empty());
|
||||
})
|
||||
.flatMap(page -> newPageService
|
||||
.archiveWithoutPermissionById(page.getId())
|
||||
.onErrorResume(e -> {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.appsmith.server.services.ce;
|
||||
|
||||
import com.appsmith.server.acl.AclPermission;
|
||||
import com.appsmith.server.domains.Application;
|
||||
import com.appsmith.server.domains.NewPage;
|
||||
import com.appsmith.server.domains.User;
|
||||
|
|
@ -8,6 +9,8 @@ import com.appsmith.server.dtos.ClonePageMetaDTO;
|
|||
import com.appsmith.server.dtos.PageDTO;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface ApplicationPageServiceCE {
|
||||
|
||||
Mono<PageDTO> createPage(PageDTO page);
|
||||
|
|
@ -47,9 +50,14 @@ public interface ApplicationPageServiceCE {
|
|||
|
||||
Mono<PageDTO> deleteUnpublishedPageByBranchAndDefaultPageId(String defaultPageId, String branchName);
|
||||
|
||||
Mono<PageDTO> deleteUnpublishedPage(String id);
|
||||
Mono<PageDTO> deleteUnpublishedPageWithOptionalPermission(
|
||||
String id,
|
||||
Optional<AclPermission> deletePagePermission,
|
||||
Optional<AclPermission> readApplicationPermission,
|
||||
Optional<AclPermission> deleteCollectionPermission,
|
||||
Optional<AclPermission> deleteActionPermission);
|
||||
|
||||
Mono<PageDTO> deleteWithoutPermissionUnpublishedPage(String id);
|
||||
Mono<PageDTO> deleteUnpublishedPage(String id);
|
||||
|
||||
Mono<Application> publish(String applicationId, boolean isPublishedManually);
|
||||
|
||||
|
|
|
|||
|
|
@ -640,6 +640,10 @@ public class ApplicationPageServiceCEImpl implements ApplicationPageServiceCE {
|
|||
return page;
|
||||
}));
|
||||
|
||||
final Flux<ActionCollection> sourceActionCollectionsFlux = getCloneableActionCollections(pageId);
|
||||
|
||||
Flux<NewAction> sourceActionFlux = getCloneableActions(pageId);
|
||||
|
||||
return sourcePageMono
|
||||
.flatMap(page -> {
|
||||
clonePageMetaDTO.setBranchedSourcePageId(page.getId());
|
||||
|
|
@ -738,6 +742,26 @@ public class ApplicationPageServiceCEImpl implements ApplicationPageServiceCE {
|
|||
}));
|
||||
}
|
||||
|
||||
protected Flux<ActionCollection> getCloneableActionCollections(String pageId) {
|
||||
final Flux<ActionCollection> sourceActionCollectionsFlux = actionCollectionService.findByPageId(pageId);
|
||||
return sourceActionCollectionsFlux;
|
||||
}
|
||||
|
||||
protected Flux<NewAction> getCloneableActions(String pageId) {
|
||||
Flux<NewAction> sourceActionFlux = newActionService
|
||||
.findByPageId(pageId, actionPermission.getEditPermission())
|
||||
// Set collection reference in actions to null to reset to the new application's collections later
|
||||
.map(newAction -> {
|
||||
if (newAction.getUnpublishedAction() != null) {
|
||||
newAction.getUnpublishedAction().setCollectionId(null);
|
||||
}
|
||||
return newAction;
|
||||
})
|
||||
// In case there are no actions in the page being cloned, return empty
|
||||
.switchIfEmpty(Flux.empty());
|
||||
return sourceActionFlux;
|
||||
}
|
||||
|
||||
private Mono<PageDTO> clonePageGivenApplicationId(String pageId, String applicationId) {
|
||||
final ClonePageMetaDTO clonePageMetaDTO = new ClonePageMetaDTO();
|
||||
return clonePageGivenApplicationId(pageId, applicationId, null, clonePageMetaDTO);
|
||||
|
|
@ -901,17 +925,38 @@ public class ApplicationPageServiceCEImpl implements ApplicationPageServiceCE {
|
|||
* In this scenario, if we were to delete all actions associated with the page, we would end up deleting an action
|
||||
* which is currently in published state and is being used.
|
||||
*
|
||||
* @param id The pageId which needs to be archived.
|
||||
* @param id The pageId which needs to be archived.
|
||||
* @param deletePagePermission
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Mono<PageDTO> deleteWithoutPermissionUnpublishedPage(String id) {
|
||||
return deleteUnpublishedPageEx(id, Optional.empty());
|
||||
public Mono<PageDTO> deleteUnpublishedPageWithOptionalPermission(
|
||||
String id,
|
||||
Optional<AclPermission> deletePagePermission,
|
||||
Optional<AclPermission> readApplicationPermission,
|
||||
Optional<AclPermission> deleteCollectionPermission,
|
||||
Optional<AclPermission> deleteActionPermission) {
|
||||
return deleteUnpublishedPageEx(
|
||||
id,
|
||||
deletePagePermission,
|
||||
readApplicationPermission,
|
||||
deleteCollectionPermission,
|
||||
deleteActionPermission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<PageDTO> deleteUnpublishedPage(String id) {
|
||||
return deleteUnpublishedPageEx(id, Optional.of(pagePermission.getDeletePermission()));
|
||||
|
||||
Optional<AclPermission> deletePagePermission = Optional.of(pagePermission.getDeletePermission());
|
||||
Optional<AclPermission> readApplicationPermission = Optional.of(applicationPermission.getReadPermission());
|
||||
Optional<AclPermission> deleteCollectionPermission = Optional.of(actionPermission.getDeletePermission());
|
||||
Optional<AclPermission> deleteActionPermission = Optional.of(actionPermission.getDeletePermission());
|
||||
return deleteUnpublishedPageEx(
|
||||
id,
|
||||
deletePagePermission,
|
||||
readApplicationPermission,
|
||||
deleteCollectionPermission,
|
||||
deleteActionPermission);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -923,23 +968,36 @@ public class ApplicationPageServiceCEImpl implements ApplicationPageServiceCE {
|
|||
* In this scenario, if we were to delete all actions associated with the page, we would end up deleting an action
|
||||
* which is currently in published state and is being used.
|
||||
*
|
||||
* @param id The pageId which needs to be archived.
|
||||
* @param id The pageId which needs to be archived.
|
||||
* @param readApplicationPermission
|
||||
* @param deleteCollectionPermission
|
||||
* @param deleteActionPermission
|
||||
* @return
|
||||
*/
|
||||
private Mono<PageDTO> deleteUnpublishedPageEx(String id, Optional<AclPermission> permission) {
|
||||
private Mono<PageDTO> deleteUnpublishedPageEx(
|
||||
String id,
|
||||
Optional<AclPermission> deletePagePermission,
|
||||
Optional<AclPermission> readApplicationPermission,
|
||||
Optional<AclPermission> deleteCollectionPermission,
|
||||
Optional<AclPermission> deleteActionPermission) {
|
||||
|
||||
return newPageService
|
||||
.findById(id, permission)
|
||||
.findById(id, deletePagePermission)
|
||||
.switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.NO_RESOURCE_FOUND, FieldName.PAGE, id)))
|
||||
.flatMap(page -> {
|
||||
log.debug(
|
||||
"Going to archive pageId: {} for applicationId: {}", page.getId(), page.getApplicationId());
|
||||
// Application is accessed without any application permission over here.
|
||||
// previously it was getting accessed only with read permission.
|
||||
Mono<Application> applicationMono = applicationService
|
||||
.getById(page.getApplicationId())
|
||||
.findById(page.getApplicationId(), readApplicationPermission)
|
||||
.switchIfEmpty(Mono.error(
|
||||
new AppsmithException(AppsmithError.NO_RESOURCE_FOUND, FieldName.APPLICATION, id)))
|
||||
.flatMap(application -> {
|
||||
application.getPages().removeIf(p -> p.getId().equals(page.getId()));
|
||||
return applicationService.save(application);
|
||||
});
|
||||
|
||||
Mono<NewPage> newPageMono;
|
||||
if (page.getPublishedPage() != null) {
|
||||
PageDTO unpublishedPage = page.getUnpublishedPage();
|
||||
|
|
@ -966,12 +1024,13 @@ public class ApplicationPageServiceCEImpl implements ApplicationPageServiceCE {
|
|||
* condition for delete action
|
||||
*/
|
||||
Mono<List<ActionDTO>> archivedActionsMono = newActionService
|
||||
.findByPageId(page.getId(), actionPermission.getDeletePermission())
|
||||
.findByPageId(page.getId(), deleteActionPermission)
|
||||
.filter(newAction -> !StringUtils.hasLength(
|
||||
newAction.getUnpublishedAction().getCollectionId()))
|
||||
.flatMap(action -> {
|
||||
log.debug("Going to archive actionId: {} for applicationId: {}", action.getId(), id);
|
||||
return newActionService.deleteUnpublishedAction(action.getId());
|
||||
return newActionService.deleteUnpublishedActionWithOptionalPermission(
|
||||
action.getId(), deleteActionPermission);
|
||||
})
|
||||
.collectList();
|
||||
|
||||
|
|
@ -985,8 +1044,8 @@ public class ApplicationPageServiceCEImpl implements ApplicationPageServiceCE {
|
|||
"Going to archive actionCollectionId: {} for applicationId: {}",
|
||||
actionCollection.getId(),
|
||||
id);
|
||||
return actionCollectionService.deleteUnpublishedActionCollection(
|
||||
actionCollection.getId());
|
||||
return actionCollectionService.deleteUnpublishedActionCollectionWithOptionalPermission(
|
||||
actionCollection.getId(), deleteCollectionPermission, deleteActionPermission);
|
||||
})
|
||||
.collectList();
|
||||
|
||||
|
|
|
|||
|
|
@ -683,7 +683,7 @@ public class ActionCollectionServiceImplTest {
|
|||
Mockito.when(actionCollectionRepository.findById(Mockito.any(), Mockito.<Optional<AclPermission>>any()))
|
||||
.thenReturn(Mono.just(actionCollection));
|
||||
|
||||
Mockito.when(newActionService.deleteUnpublishedAction(Mockito.any()))
|
||||
Mockito.when(newActionService.deleteUnpublishedActionWithOptionalPermission(Mockito.any(), Mockito.any()))
|
||||
.thenReturn(Mono.just(
|
||||
actionCollection.getUnpublishedCollection().getActions().get(0)));
|
||||
|
||||
|
|
|
|||
65
app/server/scripts/check-field-constants.mjs
Normal file
65
app/server/scripts/check-field-constants.mjs
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
import {promises as fs} from "fs";
|
||||
import path from "path";
|
||||
|
||||
async function findInnerClassDefinitions(directory) {
|
||||
try {
|
||||
const files = await fs.readdir(directory);
|
||||
|
||||
for (const file of files) {
|
||||
const filePath = path.join(directory, file);
|
||||
const stats = await fs.stat(filePath);
|
||||
|
||||
if (stats.isDirectory()) {
|
||||
await findInnerClassDefinitions(filePath);
|
||||
} else if (path.extname(filePath) === '.java') {
|
||||
await processJavaFile(filePath);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
async function processJavaFile(filePath) {
|
||||
try {
|
||||
const contents = await fs.readFile(filePath, 'utf8');
|
||||
|
||||
const innerClassRegex = /^ {4}([\w ]+?)\s+class\s+Fields\s+(extends (\w+)\.Fields)?\s*{(.+?\n {4})?}$/gsm;
|
||||
|
||||
for (const innerClassMatch of contents.matchAll(innerClassRegex)) {
|
||||
const classQualifiers = innerClassMatch[1]; // we don't care much about this
|
||||
const expectedParentClass = innerClassMatch[3];
|
||||
console.log(filePath, classQualifiers, expectedParentClass);
|
||||
|
||||
for (const match of innerClassMatch[0].matchAll(/\bpublic\s+static\s+final\s+String\s+(\w+)\s+=\s+(.+?);/gs)) {
|
||||
const key = match[1]
|
||||
const valMatcherParts = [`^dotted\\(`];
|
||||
for (const [i, field] of key.split("_").entries()) {
|
||||
if (i > 0) {
|
||||
valMatcherParts.push(`\\s*,\\s+`);
|
||||
}
|
||||
valMatcherParts.push(`(\\w+\\.\\w+\\.)?${field}`);
|
||||
}
|
||||
valMatcherParts.push(`\\s*\\)$`);
|
||||
const valMatcher = new RegExp(valMatcherParts.join(''));
|
||||
if (!valMatcher.test(match[2])) {
|
||||
console.log("key is", key);
|
||||
console.log("val is", match[2]);
|
||||
console.log("pattern", valMatcher);
|
||||
console.error(`Field ${key} in ${filePath} is not looking right.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if (finds.length > 1) {
|
||||
// console.error(`Found multiple inner class definitions in file: ${filePath}`);
|
||||
// return;
|
||||
// }
|
||||
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
const directoryPath = '.';
|
||||
findInnerClassDefinitions(directoryPath);
|
||||
Loading…
Reference in New Issue
Block a user