From d22ebfa6ce9504a3e289fc86179ff042b762d5f6 Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Mon, 22 Jan 2024 11:45:11 +0100 Subject: [PATCH] Commit message input --- package.json | 8 ++ src/constants/GeneralCommands.ts | 3 +- src/constants/TelemetryEvent.ts | 3 +- src/constants/settings.ts | 1 + .../components/Header/Header.tsx | 2 +- src/helpers/PanelSettings.ts | 1 - src/listeners/general/GitListener.ts | 55 ++++---- src/models/GitSettings.ts | 1 + src/panelWebView/components/ActionButton.tsx | 2 +- .../components/Fields/TextField.tsx | 4 + src/panelWebView/components/Git/GitAction.tsx | 131 +++++++++++++----- .../components/Icons/BranchIcon.tsx | 15 ++ src/panelWebView/styles.css | 2 + 13 files changed, 163 insertions(+), 65 deletions(-) create mode 100644 src/panelWebView/components/Icons/BranchIcon.tsx diff --git a/package.json b/package.json index bb9cf3a5..9fc98088 100644 --- a/package.json +++ b/package.json @@ -871,6 +871,14 @@ "type": "string" } }, + "frontMatter.git.requiresCommitMessage": { + "type": "array", + "markdownDescription": "%setting.frontMatter.git.requiresCommitMessage.markdownDescription%", + "default": [], + "items": { + "type": "string" + } + }, "frontMatter.git.submodule.pull": { "type": "boolean", "markdownDescription": "%setting.frontMatter.git.submodule.pull.markdownDescription%", diff --git a/src/constants/GeneralCommands.ts b/src/constants/GeneralCommands.ts index 0087cccf..3deef171 100644 --- a/src/constants/GeneralCommands.ts +++ b/src/constants/GeneralCommands.ts @@ -4,7 +4,7 @@ export const GeneralCommands = { git: { syncingStart: 'gitSyncingStart', syncingEnd: 'gitSyncingEnd', - branchInfo: 'gitBranchInfo' + branchName: 'gitBranchName' }, setLocalization: 'setLocalization' }, @@ -12,6 +12,7 @@ export const GeneralCommands = { openLink: 'openLink', git: { sync: 'gitSync', + fetch: 'getFetch', getBranch: 'getBranch', selectBranch: 'gitSelectBranch' }, diff --git a/src/constants/TelemetryEvent.ts b/src/constants/TelemetryEvent.ts index e4a1dbc1..f717da6f 100644 --- a/src/constants/TelemetryEvent.ts +++ b/src/constants/TelemetryEvent.ts @@ -49,5 +49,6 @@ export const TelemetryEvent = { webviewTaxonomyDashboard: 'webviewTaxonomyDashboard', // Git - gitSync: 'gitSync' + gitSync: 'gitSync', + gitFetch: 'gitFetch' }; diff --git a/src/constants/settings.ts b/src/constants/settings.ts index 328c57b5..33d592cb 100644 --- a/src/constants/settings.ts +++ b/src/constants/settings.ts @@ -99,6 +99,7 @@ export const SETTING_SITE_BASEURL = 'site.baseURL'; export const SETTING_GIT_ENABLED = 'git.enabled'; export const SETTING_GIT_DISABLED_BRANCHES = 'git.disableOnBranches'; +export const SETTING_GIT_REQUIRES_COMMIT_MSG = 'git.requiresCommitMessage'; export const SETTING_GIT_COMMIT_MSG = 'git.commitMessage'; export const SETTING_GIT_SUBMODULE_PULL = 'git.submodule.pull'; export const SETTING_GIT_SUBMODULE_PUSH = 'git.submodule.push'; diff --git a/src/dashboardWebView/components/Header/Header.tsx b/src/dashboardWebView/components/Header/Header.tsx index bd606d42..38689280 100644 --- a/src/dashboardWebView/components/Header/Header.tsx +++ b/src/dashboardWebView/components/Header/Header.tsx @@ -173,7 +173,7 @@ export const Header: React.FunctionComponent = ({
- + {/* */} (SETTING_GIT_ENABLED); @@ -54,6 +56,9 @@ export class GitListener { actions: gitActions || false, disabledBranches: gitActions ? Settings.get(SETTING_GIT_DISABLED_BRANCHES) || [] + : [], + requiresCommitMessage: gitActions + ? Settings.get(SETTING_GIT_REQUIRES_COMMIT_MSG) || [] : [] }; } @@ -91,7 +96,10 @@ export class GitListener { public static process(msg: PostMessageData) { switch (msg.command) { case GeneralCommands.toVSCode.git.sync: - this.sync(); + this.sync(msg.payload); + break; + case GeneralCommands.toVSCode.git.fetch: + this.sync(undefined, false); break; case GeneralCommands.toVSCode.git.getBranch: this.getBranch(msg.command, msg.requestId); @@ -108,16 +116,19 @@ export class GitListener { } /** - * Run the sync + * Run the sync/fetch */ - public static async sync() { + public static async sync(commitMsg?: string, isSync: boolean = true) { try { - this.sendMsg(GeneralCommands.toWebview.git.syncingStart, {}); + this.sendMsg(GeneralCommands.toWebview.git.syncingStart, isSync ? 'syncing' : 'fetching'); - Telemetry.send(TelemetryEvent.gitSync); + Telemetry.send(isSync ? TelemetryEvent.gitSync : TelemetryEvent.gitFetch); await this.pull(); - await this.push(); + + if (isSync) { + await this.push(commitMsg); + } this.sendMsg(GeneralCommands.toWebview.git.syncingEnd, {}); } catch (e) { @@ -187,8 +198,9 @@ export class GitListener { * Push the changes to the remote * @returns */ - private static async push() { - let commitMsg = Settings.get(SETTING_GIT_COMMIT_MSG); + private static async push(commitMsg?: string) { + commitMsg = + commitMsg || Settings.get(SETTING_GIT_COMMIT_MSG) || 'Synced by Front Matter'; if (commitMsg) { const dateFormat = Settings.get(SETTING_DATE_FORMAT) as string; @@ -213,7 +225,7 @@ export class GitListener { // Check if anything changed if (status.files.length > 0) { await subGit.raw(['add', '.', '-A']); - await subGit.commit(commitMsg || 'Synced by Front Matter'); + await subGit.commit(commitMsg); } await subGit.push(); } catch (e) { @@ -235,13 +247,7 @@ export class GitListener { // First line is the submodule folder name if (lines.length > 1) { await git.subModule(['foreach', 'git', 'add', '.', '-A']); - await git.subModule([ - 'foreach', - 'git', - 'commit', - '-m', - commitMsg || 'Synced by Front Matter' - ]); + await git.subModule(['foreach', 'git', 'commit', '-m', commitMsg]); await git.subModule(['foreach', 'git', 'push']); } } catch (e) { @@ -260,7 +266,7 @@ export class GitListener { if (status.files.length > 0) { await git.raw(['add', '.', '-A']); - await git.commit(commitMsg || 'Synced by Front Matter'); + await git.commit(commitMsg); } await git.push(); @@ -365,20 +371,11 @@ export class GitListener { */ private static async triggerBranchChange(repo: GitRepository | null) { if (repo && repo.state) { - if (repo.state.HEAD.name !== GitListener.repository?.state?.HEAD.name) { + if (repo.state.HEAD.name !== GitListener.branchName) { + GitListener.branchName = repo.state.HEAD.name; GitListener.repository = repo; - let branches = []; - if (repo.repository.getBranches) { - const allBranches = await repo.repository.getBranches(); - if (allBranches && allBranches.length > 0) { - branches = allBranches.map((branch: any) => branch.name); - } - } - this.sendMsg(GeneralCommands.toWebview.git.branchInfo, { - crntBranch: GitListener.repository?.state?.HEAD.name, - branches - }); + this.sendMsg(GeneralCommands.toWebview.git.branchName, GitListener.branchName); repo.state.onDidChange(() => { GitListener.triggerBranchChange(repo); diff --git a/src/models/GitSettings.ts b/src/models/GitSettings.ts index e29a149b..f32c71d5 100644 --- a/src/models/GitSettings.ts +++ b/src/models/GitSettings.ts @@ -2,4 +2,5 @@ export interface GitSettings { isGitRepo: boolean; actions: boolean; disabledBranches: string[]; + requiresCommitMessage: string[]; } diff --git a/src/panelWebView/components/ActionButton.tsx b/src/panelWebView/components/ActionButton.tsx index 9acf2eef..71e7ee73 100644 --- a/src/panelWebView/components/ActionButton.tsx +++ b/src/panelWebView/components/ActionButton.tsx @@ -14,7 +14,7 @@ const ActionButton: React.FunctionComponent = ({ title }: React.PropsWithChildren) => { return ( -
+
diff --git a/src/panelWebView/components/Fields/TextField.tsx b/src/panelWebView/components/Fields/TextField.tsx index f55651f9..097228a4 100644 --- a/src/panelWebView/components/Fields/TextField.tsx +++ b/src/panelWebView/components/Fields/TextField.tsx @@ -20,6 +20,7 @@ export interface ITextFieldProps extends BaseFieldProps { limit: number | undefined; rows?: number; name: string; + placeholder?: string; settings: PanelSettings; onChange: (txtValue: string) => void; } @@ -27,6 +28,7 @@ export interface ITextFieldProps extends BaseFieldProps { const WysiwygField = React.lazy(() => import('./WysiwygField')); export const TextField: React.FunctionComponent = ({ + placeholder, singleLine, wysiwyg, limit, @@ -154,6 +156,7 @@ export const TextField: React.FunctionComponent = ({ className={`metadata_field__input`} value={text || ''} onChange={(e) => onTextChange(e.currentTarget.value)} + placeholder={placeholder} style={{ border }} @@ -164,6 +167,7 @@ export const TextField: React.FunctionComponent = ({ rows={rows || 2} value={text || ''} onChange={(e) => onTextChange(e.currentTarget.value)} + placeholder={placeholder} style={{ border }} diff --git a/src/panelWebView/components/Git/GitAction.tsx b/src/panelWebView/components/Git/GitAction.tsx index 53ba5164..1e3cefab 100644 --- a/src/panelWebView/components/Git/GitAction.tsx +++ b/src/panelWebView/components/Git/GitAction.tsx @@ -1,6 +1,6 @@ import { Messenger, messageHandler } from '@estruyf/vscode/dist/client'; import { EventData } from '@estruyf/vscode/dist/models'; -import { ArrowPathIcon } from '@heroicons/react/24/outline'; +import { ArrowDownTrayIcon, ArrowPathIcon } from '@heroicons/react/24/outline'; import * as React from 'react'; import { useEffect, useState } from 'react'; import { GeneralCommands } from '../../../constants'; @@ -8,6 +8,7 @@ import { PanelSettings } from '../../../models'; import { ActionButton } from '../ActionButton'; import * as l10n from '@vscode/l10n'; import { LocalizationKey } from '../../../localization'; +import { BranchIcon } from '../Icons/BranchIcon'; export interface IGitActionProps { settings: PanelSettings | undefined; @@ -16,12 +17,16 @@ export interface IGitActionProps { export const GitAction: React.FunctionComponent = ({ settings }: React.PropsWithChildren) => { + const [commitMessage, setCommitMessage] = useState(undefined); const [crntBanch, setCrntBranch] = useState(undefined); - const [branches, setBranches] = useState(undefined); - const [isSyncing, setIsSyncing] = useState(false); + const [isSyncing, setIsSyncing] = useState<"syncing" | "fetching" | "idle">("idle"); - const pull = () => { - Messenger.send(GeneralCommands.toVSCode.git.sync); + const sync = () => { + Messenger.send(GeneralCommands.toVSCode.git.sync, commitMessage); + }; + + const fetch = () => { + Messenger.send(GeneralCommands.toVSCode.git.fetch); }; const selectBranch = () => { @@ -32,26 +37,65 @@ export const GitAction: React.FunctionComponent = ({ const { command, payload } = message.data; if (command === GeneralCommands.toWebview.git.syncingStart) { - setIsSyncing(true); + setIsSyncing(payload || "syncing"); + } else if (command === GeneralCommands.toWebview.git.syncingStart) { + setIsSyncing("syncing"); } else if (command === GeneralCommands.toWebview.git.syncingEnd) { - setIsSyncing(false); - } else if (command === GeneralCommands.toWebview.git.branchInfo) { - setCrntBranch(payload.crntBranch || undefined); - setBranches(payload.branches || undefined); + setCommitMessage(undefined); + setIsSyncing("idle"); + } else if (command === GeneralCommands.toWebview.git.branchName) { + setCrntBranch(payload || undefined); } }; - const isSyncDisabled = React.useMemo(() => { - if (!settings?.git?.disabledBranches || settings.git.disabledBranches.length === 0) { - return false; + const isCommitRequired = React.useMemo(() => { + const requiresCommitMessage = settings?.git?.requiresCommitMessage || []; + + if (!crntBanch) { + return {}; } + if (requiresCommitMessage && requiresCommitMessage.includes(crntBanch) && !commitMessage) { + return { + border: '1px solid var(--vscode-inputValidation-errorBorder)' + }; + } + + return {}; + }, [settings?.git?.requiresCommitMessage, crntBanch, commitMessage]) + + const isCommitDisabed = React.useMemo(() => { + const disabledBranches = settings?.git?.disabledBranches || []; + if (!crntBanch) { return true; } - return settings.git.disabledBranches.includes(crntBanch); - }, [settings?.git?.disabledBranches, crntBanch]) + if (disabledBranches && disabledBranches.includes(crntBanch)) { + return true; + } + + return false; + }, [settings?.git?.disabledBranches, crntBanch, commitMessage]) + + const isSyncDisabled = React.useMemo(() => { + const disabledBranches = settings?.git?.disabledBranches || []; + const requiresCommitMessage = settings?.git?.requiresCommitMessage || []; + + if (!crntBanch) { + return true; + } + + if (disabledBranches && disabledBranches.includes(crntBanch)) { + return true; + } + + if (requiresCommitMessage && requiresCommitMessage.includes(crntBanch)) { + return !commitMessage; + } + + return false; + }, [settings?.git?.disabledBranches, settings?.git?.requiresCommitMessage, crntBanch, commitMessage]) useEffect(() => { Messenger.listen(messageListener); @@ -75,32 +119,57 @@ export const GitAction: React.FunctionComponent = ({

- Git Actions + Changes

- - - - {l10n.t(LocalizationKey.commonSync)} - -
- } - /> +
+ setCommitMessage(e.target.value)} + disabled={isCommitDisabed} + /> + + + + + {l10n.t(LocalizationKey.commonSync)} + +
+ } + /> + + + + + Fetch + +
+ } + /> +
); }; diff --git a/src/panelWebView/components/Icons/BranchIcon.tsx b/src/panelWebView/components/Icons/BranchIcon.tsx new file mode 100644 index 00000000..18a3c50e --- /dev/null +++ b/src/panelWebView/components/Icons/BranchIcon.tsx @@ -0,0 +1,15 @@ +import * as React from 'react'; + +export interface IBranchIconProps { + className?: string; +} + +export const BranchIcon: React.FunctionComponent = ({ + className +}: React.PropsWithChildren) => { + return ( + + + + ); +}; \ No newline at end of file diff --git a/src/panelWebView/styles.css b/src/panelWebView/styles.css index 163bec84..9d0a9a40 100644 --- a/src/panelWebView/styles.css +++ b/src/panelWebView/styles.css @@ -976,12 +976,14 @@ vscode-divider { } /* Git actions */ +.git_actions__fetch, .git_actions__sync { display: flex; align-items: center; justify-content: center; } +.git_actions__fetch svg, .git_actions__sync svg { height: 1.25rem; width: 1.25rem;