Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions app/client/src/git/ce/constants/messages.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export const OPS_MODAL = {
TAB_RELEASE: "RELEASE",
};

export const TAB_RELEASE = {
TITLE: "Release version",
RELEASE_BTN: "Release",
};

export const RELEASE_VERSION_RADIO_GROUP = {
TITLE: "Version",
LAST_RELEASED: "Last released",
};

export const RELEASE_NOTES_INPUT = {
TITLE: "Release notes",
PLACEHOLDER: "Your release notes here",
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Flex, Icon, Text } from "@appsmith/ads";
import React from "react";
import styled from "styled-components";

const Container = styled(Flex)`
border-radius: 4px;
background-color: var(--ads-v2-color-gray-0);
`;

interface LatestCommitInfoViewProps {
authorName: string | null;
committedAt: string | null;
hash: string | null;
message: string | null;
}

function LatestCommitInfoView({
authorName = null,
committedAt = null,
hash = null,
message = null,
}: LatestCommitInfoViewProps) {
return (
<Container marginBottom="spaces-4" padding="spaces-3">
<Flex flex={1} flexDirection="column" gap="spaces-3">
<Text renderAs="p">{message}</Text>
<Text kind="body-s" renderAs="p">
{authorName ?? "-"} committed {committedAt ?? "-"}
</Text>
Comment thread
brayn003 marked this conversation as resolved.
</Flex>
<Flex alignItems="center" justifyContent="center">
<Flex gap="spaces-2">
<Icon name="git-commit" size="md" />
<Text renderAs="p">{hash ?? "-"}</Text>
</Flex>
</Flex>
Comment thread
brayn003 marked this conversation as resolved.
</Container>
);
}

export default LatestCommitInfoView;
18 changes: 18 additions & 0 deletions app/client/src/git/components/LatestCommitInfo/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from "react";
import LatestCommitInfoView from "./LatestCommitInfoView";
import useLatestCommit from "git/hooks/useLatestCommit";

function LatestCommitInfo() {
const { latestCommit } = useLatestCommit();

return (
<LatestCommitInfoView
authorName={latestCommit?.authorName ?? null}
committedAt={latestCommit?.committedAt ?? null}
hash={latestCommit?.hash ?? null}
message={latestCommit?.message ?? null}
/>
);
}
Comment thread
brayn003 marked this conversation as resolved.

export default LatestCommitInfo;
60 changes: 60 additions & 0 deletions app/client/src/git/components/OpsModal/TabRelease.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { Button, ModalBody, ModalFooter, Text } from "@appsmith/ads";
import LatestCommitInfo from "git/components/LatestCommitInfo";
import ReleaseNotesInput from "git/components/ReleaseNotesInput";
import ReleaseVersionRadioGroup from "git/components/ReleaseVersionRadioGroup";
import { TAB_RELEASE } from "git/ee/constants/messages";
Comment thread
brayn003 marked this conversation as resolved.
import React, { useCallback, useState } from "react";
import styled from "styled-components";

const Container = styled.div`
min-height: 360px;
overflow: unset;
padding-bottom: 4px;
`;

const TabTitle = styled(Text)`
margin-bottom: 12px;
color: var(--ads-v2-color-fg-emphasis);
`;

const StyledModalFooter = styled(ModalFooter)`
min-height: 52px;
`;

function TabRelease() {
const [releaseVersion, setReleaseVersion] = useState<string | null>(null);
const [releaseNotes, setReleaseNotes] = useState<string | null>(null);

const isReleaseDisabled = !releaseVersion || !releaseNotes;

const handleClickOnRelease = useCallback(() => {}, []);

return (
<>
<ModalBody>
<Container>
<TabTitle kind="heading-s" renderAs="p">
{TAB_RELEASE.TITLE}
</TabTitle>
<LatestCommitInfo />
<ReleaseVersionRadioGroup onVersionChange={setReleaseVersion} />
<ReleaseNotesInput
onTextChange={setReleaseNotes}
text={releaseNotes}
/>
</Container>
</ModalBody>
<StyledModalFooter>
<Button
isDisabled={isReleaseDisabled}
onClick={handleClickOnRelease}
size="md"
>
{TAB_RELEASE.RELEASE_BTN}
</Button>
</StyledModalFooter>
</>
);
}

export default TabRelease;
31 changes: 31 additions & 0 deletions app/client/src/git/components/ReleaseNotesInput/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from "react";
import { Flex, Input } from "@appsmith/ads";
import { RELEASE_NOTES_INPUT } from "git/ee/constants/messages";
Comment thread
brayn003 marked this conversation as resolved.
import { noop } from "lodash";

interface ReleaseNotesInputProps {
onTextChange: (text: string | null) => void;
text: string | null;
}

function ReleaseNotesInput({
onTextChange = noop,
text = null,
}: ReleaseNotesInputProps) {
return (
<Flex flexDirection={"column"}>
<Input
autoFocus
label={RELEASE_NOTES_INPUT.TITLE}
onChange={onTextChange}
Comment thread
brayn003 marked this conversation as resolved.
placeholder={RELEASE_NOTES_INPUT.PLACEHOLDER}
renderAs="textarea"
size="md"
type="text"
value={text ?? undefined}
/>
</Flex>
);
}

export default ReleaseNotesInput;
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { Flex, Radio, RadioGroup, Tag, Text } from "@appsmith/ads";
import { RELEASE_VERSION_RADIO_GROUP } from "git/ee/constants/messages";
Comment thread
brayn003 marked this conversation as resolved.
import { inc } from "semver";
import noop from "lodash/noop";

type ReleaseType = "major" | "minor" | "patch" | null;

interface ReleaseVersionRadioGroupViewProps {
currentVersion: string | null;
onVersionChange: (value: string | null) => void;
releasedAt: string | null;
}

function ReleaseVersionRadioGroupView({
currentVersion = null,
onVersionChange = noop,
releasedAt = null,
}: ReleaseVersionRadioGroupViewProps) {
const [releaseType, setReleaseType] = useState<ReleaseType>("patch");

const nextVersion = useMemo(() => {
if (!currentVersion || !releaseType) return null;

return inc(currentVersion, releaseType);
}, [currentVersion, releaseType]);

useEffect(
function releaseVersionChangeEffect() {
onVersionChange(nextVersion);
},
[nextVersion, onVersionChange],
);

const handleRadioChange = useCallback((value: string) => {
setReleaseType(value as ReleaseType);
}, []);

return (
<Flex flexDirection="column" gap="spaces-2" marginBottom="spaces-4">
<Text renderAs="p">{RELEASE_VERSION_RADIO_GROUP.TITLE}</Text>
<Flex alignItems="center" gap="spaces-4">
<Flex minWidth="40px">
<Tag isClosable={false} kind="neutral">
{nextVersion ?? "-"}
</Tag>
</Flex>
<RadioGroup
UNSAFE_gap="var(--ads-v2-spaces-4)"
onChange={handleRadioChange}
orientation="horizontal"
value={releaseType ?? undefined}
>
<Radio value="major">Major</Radio>
<Radio value="minor">Minor</Radio>
<Radio value="patch">Patch</Radio>
</RadioGroup>
</Flex>
<Text kind="body-s" renderAs="p">
{RELEASE_VERSION_RADIO_GROUP.LAST_RELEASED}: {currentVersion ?? "-"} (
{releasedAt ?? "-"})
</Text>
</Flex>
);
}

export default ReleaseVersionRadioGroupView;
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from "react";
import ReleaseVersionRadioGroupView from "./ReleaseVersionRadioGroupView";
import noop from "lodash/noop";
import useLatestCommit from "git/hooks/useLatestCommit";

interface ReleaseVersionRadioGroupProps {
onVersionChange: (version: string | null) => void;
}
Comment thread
brayn003 marked this conversation as resolved.

function ReleaseVersionRadioGroup({
onVersionChange = noop,
}: ReleaseVersionRadioGroupProps) {
const { latestCommit } = useLatestCommit();

return (
<ReleaseVersionRadioGroupView
currentVersion={latestCommit?.releaseTagName ?? null}
onVersionChange={onVersionChange}
releasedAt={latestCommit?.releasedAt ?? null}
/>
);
}

export default ReleaseVersionRadioGroup;
1 change: 1 addition & 0 deletions app/client/src/git/constants/enums.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export enum GitArtifactType {
export enum GitOpsTab {
Deploy = "Deploy",
Merge = "Merge",
Release = "Release",
}

export enum GitSettingsTab {
Expand Down
1 change: 1 addition & 0 deletions app/client/src/git/ee/constants/messages.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "../../ce/constants/messages";
29 changes: 29 additions & 0 deletions app/client/src/git/hooks/useLatestCommit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { useGitContext } from "git/components/GitContextProvider";
import useArtifactSelector from "./useArtifactSelector";
import { selectLatestCommitState } from "git/store/selectors/gitArtifactSelectors";
import { useDispatch } from "react-redux";
import { gitArtifactActions } from "git/store/gitArtifactSlice";
import { useCallback } from "react";

export default function useLatestCommit() {
const dispatch = useDispatch();
const { artifact, artifactDef } = useGitContext();
const artifactId = artifact?.id;

const latestCommitState = useArtifactSelector(selectLatestCommitState);

const fetchLatestCommit = useCallback(() => {
if (artifactDef && artifactId) {
dispatch(
gitArtifactActions.fetchLatestCommitInit({ artifactDef, artifactId }),
);
}
}, [artifactDef, artifactId, dispatch]);

return {
latestCommit: latestCommitState?.value ?? null,
isLatestCommitLoading: latestCommitState?.loading ?? false,
latestCommitError: latestCommitState?.error ?? null,
fetchLatestCommit,
};
}
15 changes: 15 additions & 0 deletions app/client/src/git/requests/fetchLatestCommitRequest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import type { AxiosPromise } from "axios";
import type { GitArtifactType } from "git/constants/enums";
import type { FetchLatestCommitResponse } from "./fetchLatestCommitRequest.types";
import Api from "api/Api";
import { GIT_BASE_URL } from "./constants";

export default async function fetchLatestCommitRequest(
artifactType: GitArtifactType,
branchedArtifactId: string,
): AxiosPromise<FetchLatestCommitResponse> {
return Api.get(
`${GIT_BASE_URL}/${artifactType}/${branchedArtifactId}/commit/latest`,
);
}
13 changes: 13 additions & 0 deletions app/client/src/git/requests/fetchLatestCommitRequest.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { ApiResponse } from "api/types";

export interface FetchLatestCommitResponseData {
authorName: string;
committedAt: string;
hash: string;
message: string;
releaseTagName: string;
releasedAt: string;
}

export type FetchLatestCommitResponse =
ApiResponse<FetchLatestCommitResponseData>;
38 changes: 38 additions & 0 deletions app/client/src/git/store/actions/fetchLatestCommitActions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import type {
GitArtifactErrorPayloadAction,
GitAsyncSuccessPayload,
} from "../types";
import { createArtifactAction } from "../helpers/createArtifactAction";
import type { FetchLatestCommitResponseData } from "git/requests/fetchLatestCommitRequest.types";

export interface FetchLatestCommitInitPayload {
artifactId: string;
}

export const fetchLatestCommitInitAction =
createArtifactAction<FetchLatestCommitInitPayload>((state) => {
state.apiResponses.latestCommit.loading = true;
state.apiResponses.latestCommit.error = null;

return state;
});

export const fetchLatestCommitSuccessAction = createArtifactAction<
GitAsyncSuccessPayload<FetchLatestCommitResponseData>
>((state, action) => {
state.apiResponses.latestCommit.loading = false;
state.apiResponses.latestCommit.value = action.payload.responseData;

return state;
});

export const fetchLatestCommitErrorAction = createArtifactAction(
(state, action: GitArtifactErrorPayloadAction) => {
const { error } = action.payload;

state.apiResponses.latestCommit.loading = false;
state.apiResponses.latestCommit.error = error;

return state;
},
);
8 changes: 8 additions & 0 deletions app/client/src/git/store/gitArtifactSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,11 @@ import {
resetCurrentBranchAction,
updateCurrentBranchAction,
} from "./actions/currentBranchActions";
import {
fetchLatestCommitErrorAction,
fetchLatestCommitInitAction,
fetchLatestCommitSuccessAction,
} from "./actions/fetchLatestCommitActions";

const initialState: GitArtifactRootReduxState = {};

Expand Down Expand Up @@ -205,6 +210,9 @@ export const gitArtifactSlice = createSlice({
pullError: pullErrorAction,
toggleOpsModal: toggleOpsModalAction,
toggleConflictErrorModal: toggleConflictErrorModalAction,
fetchLatestCommitInit: fetchLatestCommitInitAction,
fetchLatestCommitSuccess: fetchLatestCommitSuccessAction,
fetchLatestCommitError: fetchLatestCommitErrorAction,

// branches
fetchBranchesInit: fetchBranchesInitAction,
Expand Down
Loading