chore: Introduce action isDirty map (#39872)

## Description

The server now adds a isDirty map in the action object to signify if any
aspect of the action is not saved (is dirty)

This is needed for the EE change
https://github.com/appsmithorg/appsmith-ee/pull/6713


https://www.notion.so/appsmith/Implement-save-button-for-AI-Query-1b9fe271b0e2808285dcc797ad281141?pvs=4

## Automation

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

### 🔍 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/14029254723>
> Commit: 4321d95d427a1dfd07aedecd3731390ed0a4688e
> <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=14029254723&attempt=1"
target="_blank">Cypress dashboard</a>.
> Tags: `@tag.Datasource`
> Spec:
> <hr>Mon, 24 Mar 2025 07:51:29 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

## Summary by CodeRabbit

- **New Features**
- Added a capability that improves how the app retrieves a specific
action from a collection based on unique identifiers, ensuring smoother
interaction.
- Enhanced state management in actions by introducing a new property to
track the update status of schema generation, supporting more robust
workflow handling.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Hetu Nandu 2025-03-24 14:08:43 +05:30 committed by GitHub
parent 5c0562478c
commit 97b374c1ef
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 48 additions and 0 deletions

View File

@ -40,6 +40,9 @@ const BASE_ACTION: ApiAction = {
}, },
timeoutInMillisecond: 5000, timeoutInMillisecond: 5000,
}, },
isDirtyMap: {
SCHEMA_GENERATION: false,
},
jsonPathKeys: [], jsonPathKeys: [],
messages: [], messages: [],
}; };

View File

@ -834,6 +834,20 @@ export const getJsCollectionByBaseId = (
return jsaction && jsaction.config; return jsaction && jsaction.config;
}; };
export const getJSCollectionAction = (
state: AppState,
collectionId: string,
actionId: string,
) => {
const jsCollection = getJSCollection(state, collectionId);
if (jsCollection) {
return jsCollection.actions.find((action) => action.id === actionId);
}
return null;
};
/** /**
* *
* getJSCollectionFromAllEntities is used to get the js collection from all jsAction entities (including module instance entities) ) * getJSCollectionFromAllEntities is used to get the js collection from all jsAction entities (including module instance entities) )

View File

@ -47,6 +47,9 @@ const TEST_JS_FUNCTION = {
userPermissions: ["read:actions", "execute:actions", "manage:actions"], userPermissions: ["read:actions", "execute:actions", "manage:actions"],
validName: "JSObject1.myFun234y", validName: "JSObject1.myFun234y",
cacheResponse: "", cacheResponse: "",
isDirtyMap: {
SCHEMA_GENERATION: false,
},
}; };
describe("GetJSResponseViewState", () => { describe("GetJSResponseViewState", () => {

View File

@ -23,6 +23,9 @@ const DEFAULT_ACTION: Action = {
pluginId: "", pluginId: "",
messages: [], messages: [],
pluginType: PluginType.DB, pluginType: PluginType.DB,
isDirtyMap: {
SCHEMA_GENERATION: false,
},
}; };
describe("getReactivePathsOfAction", () => { describe("getReactivePathsOfAction", () => {

View File

@ -166,6 +166,9 @@ export interface BaseAction {
visualization?: { visualization?: {
result: VisualizationElements; result: VisualizationElements;
}; };
isDirtyMap: {
SCHEMA_GENERATION: boolean;
};
} }
interface BaseApiAction extends BaseAction { interface BaseApiAction extends BaseAction {

View File

@ -61,6 +61,9 @@ const BASE_JS_ACTION = (useLiterals = false) => {
timeoutInMillisecond: 1000, timeoutInMillisecond: 1000,
jsArguments: [], jsArguments: [],
}, },
isDirtyMap: {
SCHEMA_GENERATION: false,
},
}; };
}; };

View File

@ -152,5 +152,8 @@ export const newlyCreatedActions: Action[] = [
"execute:actions", "execute:actions",
"manage:actions", "manage:actions",
], ],
isDirtyMap: {
SCHEMA_GENERATION: false,
},
}, },
]; ];

View File

@ -75,4 +75,7 @@ export const APIFactory = Factory.Sync.makeFactory<ApiAction>({
"manage:actions", "manage:actions",
], ],
confirmBeforeExecute: false, confirmBeforeExecute: false,
isDirtyMap: {
SCHEMA_GENERATION: false,
},
}); });

View File

@ -4,8 +4,12 @@ import { PluginPackageName, PluginType } from "entities/Plugin";
import { PluginIDs } from "test/factories/MockPluginsState"; import { PluginIDs } from "test/factories/MockPluginsState";
const pageId = "0123456789abcdef00000000"; const pageId = "0123456789abcdef00000000";
export const GoogleSheetFactory = Factory.Sync.makeFactory<SaaSAction>({ export const GoogleSheetFactory = Factory.Sync.makeFactory<SaaSAction>({
dynamicBindingPathList: [], dynamicBindingPathList: [],
isDirtyMap: {
SCHEMA_GENERATION: false,
},
id: "api_id", id: "api_id",
baseId: "api_base_id", baseId: "api_base_id",
workspaceId: "workspaceID", workspaceId: "workspaceID",

View File

@ -51,6 +51,9 @@ export const JSObjectFactory = Factory.Sync.makeFactory<JSCollection>({
"manage:actions", "manage:actions",
], ],
cacheResponse: "", cacheResponse: "",
isDirtyMap: {
SCHEMA_GENERATION: false,
},
}, },
{ {
id: "myFunc2_id", id: "myFunc2_id",
@ -88,6 +91,9 @@ export const JSObjectFactory = Factory.Sync.makeFactory<JSCollection>({
"manage:actions", "manage:actions",
], ],
cacheResponse: "", cacheResponse: "",
isDirtyMap: {
SCHEMA_GENERATION: false,
},
}, },
], ],
body: "export default {\n\tmyVar1: [],\n\tmyVar2: {},\n\tmyFun1 () {\n\t\t//\twrite code here\n\t\t//\tthis.myVar1 = [1,2,3]\n\t},\n\tasync myFun2 () {\n\t\t//\tuse async-await or promises\n\t\t//\tawait storeValue('varName', 'hello world')\n\t}\n}", body: "export default {\n\tmyVar1: [],\n\tmyVar2: {},\n\tmyFun1 () {\n\t\t//\twrite code here\n\t\t//\tthis.myVar1 = [1,2,3]\n\t},\n\tasync myFun2 () {\n\t\t//\tuse async-await or promises\n\t\t//\tawait storeValue('varName', 'hello world')\n\t}\n}",

View File

@ -44,4 +44,7 @@ export const PostgresFactory = Factory.Sync.makeFactory<QueryAction>({
"execute:actions", "execute:actions",
"manage:actions", "manage:actions",
], ],
isDirtyMap: {
SCHEMA_GENERATION: false,
},
}); });