feat: git mod - package details and redux slice (#36989)

## Description
Introduces a new yarn package for git. Includes the yarn package files,
redux slice and relevant redux actions

Fixes #36808 
Fixes #36809 
Fixes #36810 

This is not integrated into the monolith. So, this doesn't directly
impact the product yet

## Automation
/ok-to-test tags="@tag.Git"

### 🔍 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/11478975801>
> Commit: 02c38bff6be96f3572100f348f12c15ea94ae971
> <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=11478975801&attempt=2"
target="_blank">Cypress dashboard</a>.
> Tags: `@tag.Git`
> Spec:
> <hr>Wed, 23 Oct 2024 19:42:30 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 the `@appsmith/git` package for Git-related functionality.
	- Added a new `GitTest` component for testing purposes.
- Implemented multiple actions for managing Git operations, including
commit, connection, branch fetching, metadata fetching, status fetching,
and pull actions.
	- Created a Redux slice for managing Git artifact state.

- **Documentation**
- Added TypeScript types and interfaces for better state management
within the Git context.
- Introduced ESLint configuration for consistent code quality across the
package.

These updates enhance the application's Git capabilities and improve
state management, providing a more robust user experience.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Rudraprasad Das 2024-11-21 16:03:05 +07:00 committed by GitHub
parent d99789c401
commit 2099fceffa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 448 additions and 3 deletions

View File

@ -0,0 +1,3 @@
{
"extends": ["../../.eslintrc.base.json"]
}

View File

@ -0,0 +1,15 @@
{
"name": "@appsmith/git",
"description": "This package contains all the git related functionality for Appsmith UI",
"private": true,
"version": "1.0.0",
"main": "src/index.ts",
"scripts": {
"lint": "yarn g:lint",
"prettier": "yarn g:prettier",
"test:unit": "yarn g:jest --passWithNoTests"
},
"dependencies": {
"@reduxjs/toolkit": "^2.3.0"
}
}

View File

@ -0,0 +1,26 @@
import { createSingleArtifactAction } from "./helpers/createSingleArtifactAction";
import type { GitArtifactPayloadAction } from "../types";
export const commitInitAction = createSingleArtifactAction((state) => {
state.commit.loading = true;
state.commit.error = null;
return state;
});
export const commitSuccessAction = createSingleArtifactAction((state) => {
state.commit.loading = false;
return state;
});
export const commitErrorAction = createSingleArtifactAction(
(state, action: GitArtifactPayloadAction<{ error: string }>) => {
const { error } = action.payload;
state.commit.loading = false;
state.commit.error = error;
return state;
},
);

View File

@ -0,0 +1,26 @@
import { createSingleArtifactAction } from "./helpers/createSingleArtifactAction";
import type { GitArtifactPayloadAction } from "../types";
export const connectInitAction = createSingleArtifactAction((state) => {
state.connect.loading = true;
state.connect.error = null;
return state;
});
export const connectSuccessAction = createSingleArtifactAction((state) => {
state.connect.loading = false;
return state;
});
export const connectErrorAction = createSingleArtifactAction(
(state, action: GitArtifactPayloadAction<{ error: string }>) => {
const { error } = action.payload;
state.connect.loading = false;
state.connect.error = error;
return state;
},
);

View File

@ -0,0 +1,29 @@
import type { GitArtifactPayloadAction, GitBranches } from "../types";
import { createSingleArtifactAction } from "./helpers/createSingleArtifactAction";
export const fetchBranchesInitAction = createSingleArtifactAction((state) => {
state.branches.loading = true;
state.branches.error = null;
return state;
});
export const fetchBranchesSuccessAction = createSingleArtifactAction(
(state, action: GitArtifactPayloadAction<{ branches: GitBranches }>) => {
state.branches.loading = false;
state.branches.value = action.payload.branches;
return state;
},
);
export const fetchBranchesErrorAction = createSingleArtifactAction(
(state, action: GitArtifactPayloadAction<{ error: string }>) => {
const { error } = action.payload;
state.branches.loading = false;
state.branches.error = error;
return state;
},
);

View File

@ -0,0 +1,29 @@
import type { GitArtifactPayloadAction, GitMetadata } from "../types";
import { createSingleArtifactAction } from "./helpers/createSingleArtifactAction";
export const fetchMetadataInitAction = createSingleArtifactAction((state) => {
state.metadata.loading = true;
state.metadata.error = null;
return state;
});
export const fetchMetadataSuccessAction = createSingleArtifactAction(
(state, action: GitArtifactPayloadAction<{ metadata: GitMetadata }>) => {
state.metadata.loading = false;
state.metadata.value = action.payload.metadata;
return state;
},
);
export const fetchMetadataErrorAction = createSingleArtifactAction(
(state, action: GitArtifactPayloadAction<{ error: string }>) => {
const { error } = action.payload;
state.metadata.loading = false;
state.metadata.error = error;
return state;
},
);

View File

@ -0,0 +1,29 @@
import type { GitArtifactPayloadAction, GitStatus } from "../types";
import { createSingleArtifactAction } from "./helpers/createSingleArtifactAction";
export const fetchStatusInitAction = createSingleArtifactAction((state) => {
state.status.loading = true;
state.status.error = null;
return state;
});
export const fetchStatusSuccessAction = createSingleArtifactAction(
(state, action: GitArtifactPayloadAction<{ status: GitStatus }>) => {
state.status.loading = false;
state.status.value = action.payload.status;
return state;
},
);
export const fetchStatusErrorAction = createSingleArtifactAction(
(state, action: GitArtifactPayloadAction<{ error: string }>) => {
const { error } = action.payload;
state.status.loading = false;
state.status.error = error;
return state;
},
);

View File

@ -0,0 +1,63 @@
import type {
GitArtifactPayloadAction,
GitArtifactReduxState,
GitSingleArtifactReduxState,
} from "../../types";
type SingleArtifactStateCb<T> = (
singleArtifactState: GitSingleArtifactReduxState,
action: GitArtifactPayloadAction<T>,
) => GitSingleArtifactReduxState;
export const gitSingleArtifactInitialState: GitSingleArtifactReduxState = {
metadata: {
value: null,
loading: false,
error: null,
},
connect: {
loading: false,
error: null,
},
branches: {
value: null,
loading: false,
error: null,
},
status: {
value: null,
loading: false,
error: null,
},
commit: {
loading: false,
error: null,
},
pull: {
loading: false,
error: null,
},
};
export const createSingleArtifactAction = <T>(
singleArtifactStateCb: SingleArtifactStateCb<T>,
) => {
return (
state: GitArtifactReduxState,
action: GitArtifactPayloadAction<T>,
) => {
const { artifactType, baseArtifactId } = action.payload;
state[artifactType] ??= {};
state[artifactType][baseArtifactId] ??= gitSingleArtifactInitialState;
const singleArtifactState = state[artifactType][baseArtifactId];
state[artifactType][baseArtifactId] = singleArtifactStateCb(
singleArtifactState,
action,
);
return state;
};
};

View File

@ -0,0 +1,28 @@
import type { PayloadAction } from "@reduxjs/toolkit";
import type { GitArtifactBasePayload, GitArtifactReduxState } from "../types";
import { gitSingleArtifactInitialState } from "./helpers/createSingleArtifactAction";
// ! This might be removed later
export const mountAction = (
state: GitArtifactReduxState,
action: PayloadAction<GitArtifactBasePayload>,
) => {
const { artifactType, baseArtifactId } = action.payload;
state[artifactType] ??= {};
state[artifactType][baseArtifactId] ??= gitSingleArtifactInitialState;
return state;
};
export const unmountAction = (
state: GitArtifactReduxState,
action: PayloadAction<GitArtifactBasePayload>,
) => {
const { artifactType, baseArtifactId } = action.payload;
delete state?.[artifactType]?.[baseArtifactId];
return state;
};

View File

@ -0,0 +1,26 @@
import { createSingleArtifactAction } from "./helpers/createSingleArtifactAction";
import type { GitArtifactPayloadAction } from "../types";
export const pullInitAction = createSingleArtifactAction((state) => {
state.pull.loading = true;
state.pull.error = null;
return state;
});
export const pullSuccessAction = createSingleArtifactAction((state) => {
state.pull.loading = false;
return state;
});
export const pullErrorAction = createSingleArtifactAction(
(state, action: GitArtifactPayloadAction<{ error: string }>) => {
const { error } = action.payload;
state.pull.loading = false;
state.pull.error = error;
return state;
},
);

View File

@ -0,0 +1,7 @@
import React from "react";
function GitTest() {
return <div>GitTest</div>;
}
export default GitTest;

View File

@ -0,0 +1,67 @@
/* eslint-disable padding-line-between-statements */
import { createSlice } from "@reduxjs/toolkit";
import type { GitArtifactReduxState } from "../types";
import { mountAction, unmountAction } from "../actions/mountActions";
import {
connectErrorAction,
connectInitAction,
connectSuccessAction,
} from "../actions/connectActions";
import {
fetchMetadataErrorAction,
fetchMetadataInitAction,
fetchMetadataSuccessAction,
} from "../actions/fetchMetadataActions";
import {
fetchBranchesErrorAction,
fetchBranchesInitAction,
fetchBranchesSuccessAction,
} from "../actions/fetchBranchesActions";
import {
fetchStatusErrorAction,
fetchStatusInitAction,
fetchStatusSuccessAction,
} from "../actions/fetchStatusActions";
import {
commitErrorAction,
commitInitAction,
commitSuccessAction,
} from "../actions/commitActions";
import {
pullErrorAction,
pullInitAction,
pullSuccessAction,
} from "../actions/pullActions";
const initialState: GitArtifactReduxState = {};
export const gitArtifactSlice = createSlice({
name: "gitArtifact",
initialState,
reducers: {
mount: mountAction,
unmount: unmountAction,
connectInit: connectInitAction,
connectSuccess: connectSuccessAction,
connectError: connectErrorAction,
fetchMetadataInit: fetchMetadataInitAction,
fetchMetadataSuccess: fetchMetadataSuccessAction,
fetchMetadataError: fetchMetadataErrorAction,
fetchBranchesInit: fetchBranchesInitAction,
fetchBranchesSuccess: fetchBranchesSuccessAction,
fetchBranchesError: fetchBranchesErrorAction,
fetchStatusInit: fetchStatusInitAction,
fetchStatusSuccess: fetchStatusSuccessAction,
fetchStatusError: fetchStatusErrorAction,
commitInit: commitInitAction,
commitSuccess: commitSuccessAction,
commitError: commitErrorAction,
pullInit: pullInitAction,
pullSuccess: pullSuccessAction,
pullError: pullErrorAction,
},
});
export const gitArtifactActions = gitArtifactSlice.actions;
export default gitArtifactSlice.reducer;

View File

@ -0,0 +1,35 @@
import type { PayloadAction } from "@reduxjs/toolkit";
// These will be updated when contracts are finalized
export type GitMetadata = Record<string, unknown>;
export type GitBranches = Record<string, unknown>;
export type GitStatus = Record<string, unknown>;
interface AsyncState<T = unknown> {
value: T | null;
loading: boolean;
error: string | null;
}
export interface GitSingleArtifactReduxState {
metadata: AsyncState<GitMetadata>;
connect: Omit<AsyncState, "value">;
branches: AsyncState<GitBranches>;
status: AsyncState<GitStatus>;
commit: Omit<AsyncState, "value">;
pull: Omit<AsyncState, "value">;
}
export interface GitArtifactReduxState {
[key: string]: Record<string, GitSingleArtifactReduxState>;
}
export interface GitArtifactBasePayload {
artifactType: string;
baseArtifactId: string;
}
export type GitArtifactPayloadAction<T = Record<string, unknown>> =
PayloadAction<GitArtifactBasePayload & T>;

View File

@ -0,0 +1,4 @@
{
"extends": "../../tsconfig.json",
"include": ["./src/**/*"]
}

View File

@ -192,6 +192,14 @@ __metadata:
languageName: unknown
linkType: soft
"@appsmith/git@workspace:packages/git":
version: 0.0.0-use.local
resolution: "@appsmith/git@workspace:packages/git"
dependencies:
"@reduxjs/toolkit": ^2.3.0
languageName: unknown
linkType: soft
"@appsmith/utils@workspace:^, @appsmith/utils@workspace:packages/utils":
version: 0.0.0-use.local
resolution: "@appsmith/utils@workspace:packages/utils"
@ -8011,6 +8019,26 @@ __metadata:
languageName: node
linkType: hard
"@reduxjs/toolkit@npm:^2.3.0":
version: 2.3.0
resolution: "@reduxjs/toolkit@npm:2.3.0"
dependencies:
immer: ^10.0.3
redux: ^5.0.1
redux-thunk: ^3.1.0
reselect: ^5.1.0
peerDependencies:
react: ^16.9.0 || ^17.0.0 || ^18
react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0
peerDependenciesMeta:
react:
optional: true
react-redux:
optional: true
checksum: 1a0d85978f99a44f7ceabec8623f46cdd2a2dc25d809dfb0d5c9cd13e2aa12cf116cffe34a4ed949169804dc6125ef9cf68143225e9527f861b597ea701e8bb5
languageName: node
linkType: hard
"@rollup/plugin-babel@npm:^5.2.0":
version: 5.3.1
resolution: "@rollup/plugin-babel@npm:5.3.1"
@ -20770,10 +20798,17 @@ __metadata:
languageName: node
linkType: hard
"immer@npm:^10.0.3":
version: 10.1.1
resolution: "immer@npm:10.1.1"
checksum: 07c67970b7d22aded73607193d84861bf786f07d47f7d7c98bb10016c7a88f6654ad78ae1e220b3c623695b133aabbf24f5eb8d9e8060cff11e89ccd81c9c10b
languageName: node
linkType: hard
"immer@npm:^9.0.6, immer@npm:^9.0.7":
version: 9.0.14
resolution: "immer@npm:9.0.14"
checksum: 17f1365c06d653e672a4f609f08e7203e9ab4b4284818332d6ca9b3f3577a0e3c0066ca7933b636fbae560df79a4b3fde70ed717ce3c6e95c39bf3d5861d5be9
version: 9.0.21
resolution: "immer@npm:9.0.21"
checksum: 70e3c274165995352f6936695f0ef4723c52c92c92dd0e9afdfe008175af39fa28e76aafb3a2ca9d57d1fb8f796efc4dd1e1cc36f18d33fa5b74f3dfb0375432
languageName: node
linkType: hard
@ -29630,6 +29665,15 @@ __metadata:
languageName: node
linkType: hard
"redux-thunk@npm:^3.1.0":
version: 3.1.0
resolution: "redux-thunk@npm:3.1.0"
peerDependencies:
redux: ^5.0.0
checksum: bea96f8233975aad4c9f24ca1ffd08ac7ec91eaefc26e7ba9935544dc55d7f09ba2aa726676dab53dc79d0c91e8071f9729cddfea927f4c41839757d2ade0f50
languageName: node
linkType: hard
"redux@npm:^3.6.0 || ^4.0.0, redux@npm:^4.0.0, redux@npm:^4.0.1, redux@npm:^4.0.4, redux@npm:^4.0.5":
version: 4.0.5
resolution: "redux@npm:4.0.5"
@ -29640,6 +29684,13 @@ __metadata:
languageName: node
linkType: hard
"redux@npm:^5.0.1":
version: 5.0.1
resolution: "redux@npm:5.0.1"
checksum: e74affa9009dd5d994878b9a1ce30d6569d986117175056edb003de2651c05b10fe7819d6fa94aea1a94de9a82f252f986547f007a2fbeb35c317a2e5f5ecf2c
languageName: node
linkType: hard
"reflect.getprototypeof@npm:^1.0.4":
version: 1.0.4
resolution: "reflect.getprototypeof@npm:1.0.4"
@ -29931,6 +29982,13 @@ __metadata:
languageName: node
linkType: hard
"reselect@npm:^5.1.0":
version: 5.1.1
resolution: "reselect@npm:5.1.1"
checksum: 5d32d48be29071ddda21a775945c2210cf4ca3fccde1c4a0e1582ac3bf99c431c6c2330ef7ca34eae4c06feea617e7cb2c275c4b33ccf9a930836dfc98b49b13
languageName: node
linkType: hard
"resize-observer-polyfill@npm:^1.5.0, resize-observer-polyfill@npm:^1.5.1":
version: 1.5.1
resolution: "resize-observer-polyfill@npm:1.5.1"