Skip to content

Commit

Permalink
Titan v1.1.0 Changelog
Browse files Browse the repository at this point in the history
- Reset Source Branch, Issue Number and Commit Message on every time commit section is opened ✅
- Make the Commit Message element a creatable select like Issue Number, and store history of previous commit messages being used. ✅
- ISSUE: When you click on Diff button for local changes, it unselects the file ✅
- FR: SVN Log across selected branches ✅
- Remove the need to select files from the source branch even if they don't appear for added flexibility in commit messages ✅
- Sort revisions by branch version to make the clipboard text easier to paste ✅
- Remove tooltip for Diff buttons ✅
  • Loading branch information
ArrushC committed Jul 26, 2024
1 parent 5ef6231 commit 4f01bf3
Show file tree
Hide file tree
Showing 21 changed files with 763 additions and 445 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ node_modules
*.local

# Release directory
release
release/win-unpacked
release/*.yml
release/*.yaml
Expand Down
392 changes: 0 additions & 392 deletions dist/assets/index-6K0W5olM.js

This file was deleted.

392 changes: 392 additions & 0 deletions dist/assets/index-BAbK4Sd9.js

Large diffs are not rendered by default.

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions dist/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
<link rel="icon" type="image/png" href="/Titan.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Titan</title>
<script type="module" crossorigin src="/assets/index-6K0W5olM.js"></script>
<script type="module" crossorigin src="/assets/index-BAbK4Sd9.js"></script>
<link rel="modulepreload" crossorigin href="/assets/ag-grid-community-Cx90zoxL.js">
<link rel="modulepreload" crossorigin href="/assets/ag-grid-react-DXgOePOU.js">
<link rel="stylesheet" crossorigin href="/assets/index-Bc2YU8Yt.css">
<link rel="stylesheet" crossorigin href="/assets/index-D9YwCfQp.css">
</head>

<body>
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "titan",
"private": true,
"proxy": "http://localhost:5173",
"version": "1.0.1",
"version": "1.1.0",
"type": "module",
"main": "main.js",
"description": "A desktop application for managing your workflow in VCS and RCS environments.",
Expand Down
89 changes: 88 additions & 1 deletion server/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ async function writeTargetsFile(targets = []) {
************************************/
function executeSvnCommand(commands) {
if (!Array.isArray(commands)) {
commands = [commands]; // Wrap the single command object in an array for uniform processing
commands = [commands];
}

return Promise.all(
Expand Down Expand Up @@ -154,6 +154,45 @@ function executeSvnCommand(commands) {
);
}

function executeSvnCommandParallel(commands) {
if (!Array.isArray(commands)) {
commands = [commands];
}

// Dont return promise, just execute the commands in parallel
commands.forEach((cmd) => {
const args = Array.isArray(cmd.args) ? cmd.args : [cmd.args];
const options = cmd.options || {};

args.push(options);

const opCallback = (err, result) => {
if (err) {
logger.error(`Error executing SVN operation ${cmd.command} with args ${JSON.stringify(args, null, 2)}:`);
logger.error(JSON.stringify(err, null, 2));
}
cmd.postopCallback(err, result);
};

// Check whether to execute a utility command or a regular SVN command
if (cmd.isUtilityCmd) {
// Handle utility commands
if (typeof svnUltimate.util[cmd.command] !== "function") {
logger.error(`Invalid SVN utility command: ${cmd.command}`);
return;
}
svnUltimate.util[cmd.command](...args, opCallback);
} else {
// Handle regular SVN commands
if (typeof svnUltimate.commands[cmd.command] !== "function") {
logger.error(`Invalid SVN command: ${cmd.command}`);
return;
}
svnUltimate.commands[cmd.command](...args, opCallback);
}
});
}

const svnQueueSerial = async.queue(async (task) => {
debugTask("svnQueueSerial", task, false);
const { command, args, postopCallback, preopCallback } = task;
Expand Down Expand Up @@ -662,6 +701,54 @@ io.on("connection", (socket) => {
debugTask("svn-commit", data, true);
});

socket.on("svn-log-selected", async (data) => {
debugTask("svn-log-selected", data, false);

if (!data.selectedBranches || data.selectedBranches.length === 0) {
emitMessage(socket, "No branches selected", "error");
return;
}

const tasks = data.selectedBranches.map((branch) => {
return {
command: "log",
args: [branch["SVN Branch"]],
options: { revision: "1:HEAD" },
postopCallback: (err, result) => {
if (err) {
logger.error(`Failed to fetch logs for branch ${branch["SVN Branch"]}:`, err);
if (!isSVNConnectionError(socket, err)) emitMessage(socket, `Failed to fetch logs for branch ${branch["SVN Branch"]}`, "error");
} else {
const logs = result.logentry || [];
const logsArray = Array.isArray(logs) ? logs : [logs];
const formattedLogs = logsArray.map((entry) => {
return {
revision: entry["$"].revision,
branchFolder: branch["Branch Folder"],
branchVersion: branch["Branch Version"],
author: entry.author,
message: entry.msg,
date: (new Date(entry.date)).toLocaleString("en-GB"),
};
});

socket.emit("svn-log-result", { ...branch, logs: formattedLogs });
}
},
};
});

try {
// Execute SVN commands in parallel
executeSvnCommandParallel(tasks);
} catch (err) {
logger.error("Error fetching SVN logs:", err);
if (!isSVNConnectionError(socket, err)) emitMessage(socket, "Error fetching SVN logs", "error");
}

debugTask("svn-log-selected", data, true);
});

socket.on("client-log", (data) => {
let { logType, logMessage } = data;
logger.log(logType, `Client Message - ${logMessage}}`);
Expand Down
2 changes: 2 additions & 0 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import SectionBranches from "./components/SectionBranches";
import SectionCommit from "./components/SectionCommit";
import { useApp } from "./AppContext";
import useNotifications from "./hooks/useNotifications";
import SectionBranchLog from "./components/SectionBranchLog";

function App() {
const { isCommitMode, selectedBranches, configurableRowData, config } = useApp();
Expand Down Expand Up @@ -46,6 +47,7 @@ function App() {
</Box>
)}
</Flex>
<SectionBranchLog />
</Box>
);
}
Expand Down
5 changes: 5 additions & 0 deletions src/AppContext.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ const AppContext = createContext({
branchTableGridRef: null,
selectedBranches: [],
setSelectedBranches: (_) => {},
showSelectedBranchesLog: false,
setShowSelectedBranchesLog: (_) => {},
isCommitMode: false,
setIsCommitMode: (_) => {},
selectedBranchStatuses: [],
Expand Down Expand Up @@ -121,6 +123,7 @@ export const AppProvider = ({ children }) => {
const [branchInfos, setBranchInfos] = useState({});
const branchTableGridRef = useRef(null);
const [selectedBranches, setSelectedBranches] = useState([]);
const [showSelectedBranchesLog, setShowSelectedBranchesLog] = useState(false);

// Props used in SectionCommit
const [isCommitMode, setIsCommitMode] = useState(false);
Expand Down Expand Up @@ -189,6 +192,8 @@ export const AppProvider = ({ children }) => {
branchTableGridRef,
selectedBranches,
setSelectedBranches,
showSelectedBranchesLog,
setShowSelectedBranchesLog,
isCommitMode,
setIsCommitMode,
selectedBranchStatuses,
Expand Down
8 changes: 2 additions & 6 deletions src/components/DiffButton.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IconButton, Tooltip } from "@chakra-ui/react";
import { IconButton } from "@chakra-ui/react";
import React from "react";
import { VscDiffSingle } from "react-icons/vsc";

Expand All @@ -17,9 +17,5 @@ export default function DiffButton(props) {
}
};

return (
<Tooltip label="Diff">
<IconButton aria-label="Diff" size="sm" icon={<VscDiffSingle />} onClick={handleDiff} colorScheme="yellow"/>
</Tooltip>
);
return <IconButton aria-label="Diff" size="sm" icon={<VscDiffSingle />} onClick={handleDiff} colorScheme="yellow" />;
}
9 changes: 5 additions & 4 deletions src/components/FooterSectionCommit.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@ export default function FooterSectionCommit({ openModal }) {
return;
}

if (!selectedLocalChanges.map((file) => file.branchId).includes(sourceBranch.value)) {
RaiseClientNotificaiton("Please select at least 1 file from the source branch to proceed!", "error");
return;
}
// 16/07/2024 AC: Commented this validation logic to allow users to commit without selecting files from the source branch for added flexibility.
// if (!selectedLocalChanges.map((file) => file.branchId).includes(sourceBranch.value)) {
// RaiseClientNotificaiton("Please select at least 1 file from the source branch to proceed!", "error");
// return;
// }

setSocketPayload({ sourceBranch: selectedBranches.find((row) => row.id == sourceBranch.value), issueNumber: issueNumber.value, commitMessage, filesToProcess: selectedLocalChanges });
openModal();
Expand Down
98 changes: 75 additions & 23 deletions src/components/FormSVNMessage.jsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { Box, Flex, FormControl, FormLabel, Textarea } from "@chakra-ui/react";
import { Box, Flex, FormControl, FormLabel, IconButton, Textarea, Tooltip } from "@chakra-ui/react";
import { CreatableSelect, Select } from "chakra-react-select";
import React, { useCallback, useEffect, useMemo } from "react";
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { useApp } from "../AppContext";
import { branchString } from "../utils/CommonConfig";
import { CloseIcon } from "@chakra-ui/icons";

export default function FormSVNMessage() {
const {sourceBranch, setSourceBranch, issueNumber, setIssueNumber, commitMessage, setCommitMessage, issueOptions, setIssueOptions, selectedBranches} = useApp();
const { sourceBranch, setSourceBranch, issueNumber, setIssueNumber, commitMessage, setCommitMessage, issueOptions, setIssueOptions, selectedBranches, isCommitMode } = useApp();
const [commitMessageHistory, setCommitMessageHistory] = useState([]);

const sourceBranchOptions = useMemo(
() =>
Expand All @@ -16,9 +18,12 @@ export default function FormSVNMessage() {
[selectedBranches]
);

const handleSourceBranchChange = useCallback((selectedOption) => {
setSourceBranch(selectedOption);
}, [setSourceBranch]);
const handleSourceBranchChange = useCallback(
(selectedOption) => {
setSourceBranch(selectedOption);
},
[setSourceBranch]
);

const handleIssueNumberChange = (selectedOption) => {
setIssueNumber(selectedOption);
Expand All @@ -29,40 +34,87 @@ export default function FormSVNMessage() {
}
};

const handleCommitMessageChange = (e) => {
setCommitMessage(String(e.target.value).replace(/["`]/g, "'"));
const handleClearIssueOptions = () => {
setIssueOptions([]);
localStorage.removeItem("issueOptions");
};

// Load issue options from localStorage on component mount
useEffect(() => {
const savedOptions = localStorage.getItem("issueOptions");
if (savedOptions) {
setIssueOptions(JSON.parse(savedOptions));
const handleCommitMessageChange = (selectedMessage) => {
if (selectedMessage) {
setCommitMessage(selectedMessage.value.replace(/["`]/g, "'"));
if (!commitMessageHistory.some((option) => option.value === selectedMessage.value)) {
const newHistory = [selectedMessage, ...commitMessageHistory];
setCommitMessageHistory(newHistory);
localStorage.setItem("commitMessageHistory", JSON.stringify(newHistory));
}
} else {
setCommitMessage("");
}
};

const handleClearCommitMessageHistory = () => {
setCommitMessageHistory([]);
localStorage.removeItem("commitMessageHistory");
};

// Load options from localStorage on component mount
useEffect(() => {
const savedIssueOptions = localStorage.getItem("issueOptions");
if (savedIssueOptions) setIssueOptions(JSON.parse(savedIssueOptions));

const savedCommitMessageHistory = localStorage.getItem("commitMessageHistory");
if (savedCommitMessageHistory) setCommitMessageHistory(JSON.parse(savedCommitMessageHistory));
}, []);

useEffect(() => {
if (selectedBranches.length === 1) setSourceBranch(sourceBranchOptions[0]);
else setSourceBranch(null);
}, [selectedBranches, sourceBranchOptions]);

useEffect(() => {
if (!isCommitMode) return;
setSourceBranch(null);
setIssueNumber(null);
setCommitMessage("");
}, [isCommitMode]);

return (
<Box>
<Flex columnGap={2} mb={2}>
<FormControl width={"50%"} isRequired>
<FormLabel>Source Branch</FormLabel>
<Select value={sourceBranch} onChange={handleSourceBranchChange} options={sourceBranchOptions} placeholder="Select branch you would like to commit from" selectedOptionColorScheme="yellow" />
</FormControl>
<FormControl width={"50%"} isRequired>
<FormLabel>Issue Number</FormLabel>
<CreatableSelect value={issueNumber} onChange={handleIssueNumberChange} options={issueOptions} placeholder="Select or create an issue number" formatCreateLabel={(inputValue) => `Create issue "${inputValue}"`} selectedOptionColorScheme="yellow" />
</FormControl>
<Box width={"50%"}>
<FormControl isRequired>
<FormLabel>Source Branch</FormLabel>
<Select value={sourceBranch} onChange={handleSourceBranchChange} options={sourceBranchOptions} placeholder="Select branch you would like to commit from" selectedOptionStyle="check" selectedOptionColorScheme="yellow" isClearable />
</FormControl>
</Box>
<Flex width={"50%"} alignItems={"flex-end"} columnGap={2}>
<FormControl isRequired>
<FormLabel>Issue Number</FormLabel>
<CreatableSelect value={issueNumber} onChange={handleIssueNumberChange} options={issueOptions} placeholder="Select or create an issue number" formatCreateLabel={(inputValue) => `Create issue "${inputValue}"`} selectedOptionStyle="check" selectedOptionColorScheme="yellow" isClearable />
</FormControl>
<Tooltip label="Clear All Issue Number Options" hasArrow>
<IconButton colorScheme={"red"} aria-label="Clear Issue Number Options" size="md" onClick={handleClearIssueOptions} icon={<CloseIcon />} />
</Tooltip>
</Flex>
</Flex>
<Flex>
<Flex alignItems={"flex-end"} columnGap={2}>
<FormControl width={"100%"} isRequired>
<FormLabel>Commit Message</FormLabel>
<Textarea placeholder={"Enter Commit Message"} resize={"vertical"} onInput={handleCommitMessageChange} value={commitMessage} />
<CreatableSelect
size={"lg"}
value={commitMessage ? { value: commitMessage, label: commitMessage } : null}
onChange={handleCommitMessageChange}
options={commitMessageHistory}
placeholder="Enter or select a commit message"
formatCreateLabel={(inputValue) => `Create message "${inputValue}"`}
selectedOptionStyle="check"
selectedOptionColorScheme="yellow"
isClearable
/>
</FormControl>
<Tooltip label="Clear All Commit Message History" hasArrow>
<IconButton colorScheme={"red"} aria-label="Clear Commit Message History" size="lg" onClick={handleClearCommitMessageHistory} icon={<CloseIcon />} />
</Tooltip>
</Flex>
</Box>
);
Expand Down
8 changes: 4 additions & 4 deletions src/components/ModalCommit.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@ export default function ModalCommit({ isModalOpen, onModalClose }) {
(responses, options) => {
const zeroWidthSpace = "\u200B".repeat(7);
const newline = options.includes("MarkupSupport") ? `\r\n${zeroWidthSpace}` : "\r\n";

return responses
const sortedResponses = responses.sort((a, b) => a["Branch Version"].localeCompare(b["Branch Version"]));
return sortedResponses
.map((response) => {
const parts = [];
if (options.includes("BranchFolder")) parts.push(response["Branch Folder"]);
Expand Down Expand Up @@ -353,12 +353,12 @@ export default function ModalCommit({ isModalOpen, onModalClose }) {
</Box>
</ModalBody>
<ModalFooter>
<Tooltip label={"Cannot undo the commit currently"} isDisabled={activeStep < 2}>
<Tooltip hasArrow label={"Cannot undo the commit currently"} isDisabled={activeStep < 2}>
<Button onClick={handlePrevious} mr={3} isDisabled={activeStep >= 2}>
{activeStep == 1 ? "Cancel" : "Previous"}
</Button>
</Tooltip>
<Tooltip label={"Cannot undo the commit currently"} isDisabled={activeStep != 2}>
<Tooltip hasArrow label={"Cannot undo the commit currently"} isDisabled={activeStep != 2}>
<Button colorScheme="yellow" onClick={handleNext} isDisabled={activeStep == 2}>
{activeStep == steps.length ? "Complete" : "Next"}
</Button>
Expand Down
1 change: 1 addition & 0 deletions src/components/PanelLocalChanges.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ export default function PanelLocalChanges({ rowDataLocalChanges, setRowDataLocal
quickFilterText={quickFilterFileViewText}
domLayout="normal"
rowSelection={"multiple"}
suppressRowClickSelection={true}
rowMultiSelectWithClick={true}
animateRows={true}
columnMenu={"new"}
Expand Down
Loading

0 comments on commit 4f01bf3

Please sign in to comment.