Skip to content

Commit

Permalink
#186 Added a new field to the "Add Tag" dialog that enables the exten…
Browse files Browse the repository at this point in the history
…sion to push the tag to a remote once it is added.
  • Loading branch information
mhutchie committed Sep 29, 2019
1 parent b9e0544 commit e862985
Show file tree
Hide file tree
Showing 8 changed files with 78 additions and 28 deletions.
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,11 @@
},
"description": "An object specifying the default visibility of the Date, Author & Commit columns. Example: {\"Date\": true, \"Author\": true, \"Commit\": true}"
},
"git-graph.dialog.addTag.pushToRemote": {
"type": "boolean",
"default": false,
"description": "Default state of the field indicating whether the tag should be pushed to a remote once it is added."
},
"git-graph.dialog.addTag.type": {
"type": "string",
"enum": [
Expand Down
1 change: 1 addition & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ class Config {

return {
addTag: {
pushToRemote: !!this.config.get('dialog.addTag.pushToRemote', false),
type: this.config.get<string>('dialog.addTag.type', 'Annotated') === 'Lightweight' ? 'lightweight' : 'annotated'
},
createBranch: {
Expand Down
16 changes: 10 additions & 6 deletions src/gitGraphView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { ExtensionState } from './extensionState';
import { Logger } from './logger';
import { RepoFileWatcher } from './repoFileWatcher';
import { RepoManager } from './repoManager';
import { GitGraphViewInitialState, GitRepoSet, RequestMessage, ResponseMessage } from './types';
import { ErrorInfo, GitGraphViewInitialState, GitRepoSet, RequestMessage, ResponseMessage } from './types';
import { copyFilePathToClipboard, copyToClipboard, getNonce, openFile, UNABLE_TO_FIND_GIT_MSG, UNCOMMITTED, viewDiff, viewScm } from './utils';

export class GitGraphView {
Expand Down Expand Up @@ -99,6 +99,8 @@ export class GitGraphView {
this.panel.webview.onDidReceiveMessage(async (msg: RequestMessage) => {
if (this.dataSource === null) return;
this.repoFileWatcher.mute();
let errorInfos: ErrorInfo[];

switch (msg.command) {
case 'addRemote':
this.sendMessage({
Expand All @@ -107,10 +109,11 @@ export class GitGraphView {
});
break;
case 'addTag':
this.sendMessage({
command: 'addTag',
error: await this.dataSource.addTag(msg.repo, msg.tagName, msg.commitHash, msg.lightweight, msg.message)
});
errorInfos = [await this.dataSource.addTag(msg.repo, msg.tagName, msg.commitHash, msg.lightweight, msg.message)];
if (errorInfos[0] === null && msg.pushToRemote !== null) {
errorInfos.push(await this.dataSource.pushTag(msg.repo, msg.tagName, msg.pushToRemote));
}
this.sendMessage({ command: 'addTag', errors: errorInfos });
break;
case 'applyStash':
this.sendMessage({
Expand Down Expand Up @@ -193,7 +196,7 @@ export class GitGraphView {
});
break;
case 'deleteBranch':
let errorInfos = [await this.dataSource.deleteBranch(msg.repo, msg.branchName, msg.forceDelete)];
errorInfos = [await this.dataSource.deleteBranch(msg.repo, msg.branchName, msg.forceDelete)];
for (let i = 0; i < msg.deleteOnRemotes.length; i++) {
errorInfos.push(await this.dataSource.deleteRemoteBranch(msg.repo, msg.branchName, msg.deleteOnRemotes[i]));
}
Expand Down Expand Up @@ -402,6 +405,7 @@ export class GitGraphView {
});
break;
}

this.repoFileWatcher.unmute();
}, null, this.disposables);

Expand Down
4 changes: 3 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ export interface DefaultColumnVisibility {

export interface DialogDefaults {
readonly addTag: {
readonly pushToRemote: boolean,
readonly type: 'annotated' | 'lightweight'
};
readonly createBranch: {
Expand Down Expand Up @@ -288,8 +289,9 @@ export interface RequestAddTag extends RepoRequest {
readonly tagName: string;
readonly lightweight: boolean;
readonly message: string;
readonly pushToRemote: string | null; // string => name of the remote to push the tag to, null => don't push to a remote
}
export interface ResponseAddTag extends ResponseWithErrorInfo {
export interface ResponseAddTag extends ResponseWithMultiErrorInfo {
readonly command: 'addTag';
}

Expand Down
24 changes: 15 additions & 9 deletions web/dialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@ class Dialog {
this.showForm(message, [{ type: 'checkbox', name: checkboxLabel, value: checkboxValue }], actionName, values => actioned(values[0] === 'checked'), sourceElem);
}

public showSelect(message: string, defaultValue: string, options: { name: string, value: string }[], actionName: string, actioned: (value: string) => void, sourceElem: HTMLElement | null) {
public showSelect(message: string, defaultValue: string, options: DialogSelectInputOption[], actionName: string, actioned: (value: string) => void, sourceElem: HTMLElement | null) {
this.showForm(message, [{ type: 'select', name: '', options: options, default: defaultValue }], actionName, values => actioned(values[0]), sourceElem);
}

public showForm(message: string, inputs: DialogInput[], actionName: string, actioned: (values: string[]) => void, sourceElem: HTMLElement | null) {
let textRefInput = -1, multiElement = inputs.length > 1;
let multiCheckbox = multiElement;
let multiCheckbox = multiElement, infoColumn = false;

if (multiElement) { // If has multiple elements, then check if they are all checkboxes. If so, then the form is a checkbox multi
for (let i = 0; i < inputs.length; i++) {
Expand All @@ -49,24 +49,30 @@ class Dialog {
}
}
}
for (let i = 0; i < inputs.length; i++) {
if (inputs[i].info && inputs[i].type !== 'checkbox') {
infoColumn = true;
break;
}
}

let html = message + '<br><table class="dialogForm ' + (multiElement ? multiCheckbox ? 'multiCheckbox' : 'multi' : 'single') + '">';
for (let i = 0; i < inputs.length; i++) {
let input = inputs[i];
html += '<tr>' + (multiElement && !multiCheckbox ? '<td>' + input.name + ': </td>' : '') + '<td>';
const input = inputs[i], infoHtml = input.info ? '<span class="dialogInfo" title="' + escapeHtml(input.info) + '">' + SVG_ICONS.info + '</span>' : '';
html += '<tr>' + (multiElement && !multiCheckbox ? '<td>' + input.name + ': </td>' : '');
if (input.type === 'select') {
html += '<select id="dialogInput' + i + '">';
html += '<td class="inputCol"><select id="dialogInput' + i + '">';
for (let j = 0; j < input.options.length; j++) {
html += '<option value="' + escapeHtml(input.options[j].value) + '"' + (input.options[j].value === input.default ? ' selected' : '') + '>' + escapeHtml(input.options[j].name) + '</option>';
}
html += '</select>';
html += '</select></td>' + (infoColumn ? '<td>' + infoHtml + '</td>' : '');
} else if (input.type === 'checkbox') {
html += '<span class="dialogFormCheckbox"><label><input id="dialogInput' + i + '" type="checkbox"' + (input.value ? ' checked' : '') + '/>' + (multiElement && !multiCheckbox ? '' : input.name) + '</label></span>';
html += '<td class="inputCol"' + (infoColumn ? ' colspan="2"' : '') + '><span class="dialogFormCheckbox"><label><input id="dialogInput' + i + '" type="checkbox"' + (input.value ? ' checked' : '') + '/>' + (multiElement && !multiCheckbox ? '' : input.name) + infoHtml + '</label></span></td>';
} else {
html += '<input id="dialogInput' + i + '" type="text" value="' + escapeHtml(input.default) + '"' + (input.type === 'text' && input.placeholder !== null ? ' placeholder="' + escapeHtml(input.placeholder) + '"' : '') + '/>';
html += '<td class="inputCol"><input id="dialogInput' + i + '" type="text" value="' + escapeHtml(input.default) + '"' + (input.type === 'text' && input.placeholder !== null ? ' placeholder="' + escapeHtml(input.placeholder) + '"' : '') + '/></td>' + (infoColumn ? '<td>' + infoHtml + '</td>' : '');
if (input.type === 'text-ref') textRefInput = i;
}
html += '</td></tr>';
html += '</tr>';
}
html += '</table>';

Expand Down
11 changes: 10 additions & 1 deletion web/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,25 +73,34 @@ declare global {
readonly name: string;
readonly default: string;
readonly placeholder: string | null;
readonly info?: string;
}

interface DialogTextRefInput {
readonly type: 'text-ref';
readonly name: string;
readonly default: string;
readonly info?: string;
}

interface DialogSelectInput {
readonly type: 'select';
readonly name: string;
readonly options: { name: string, value: string }[];
readonly options: DialogSelectInputOption[];
readonly default: string;
readonly info?: string;
}

interface DialogCheckboxInput {
readonly type: 'checkbox';
readonly name: string;
readonly value: boolean;
readonly info?: string;
}

interface DialogSelectInputOption {
readonly name: string;
readonly value: string;
}

type DialogInput = DialogTextInput | DialogTextRefInput | DialogSelectInput | DialogCheckboxInput;
Expand Down
37 changes: 32 additions & 5 deletions web/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -595,12 +595,39 @@ class GitGraphView {
{
title: 'Add Tag' + ELLIPSIS,
onClick: () => {
dialog.showForm('Add tag to commit <b><i>' + abbrevCommit(hash) + '</i></b>:', [
const dialogConfig = this.config.dialogDefaults.addTag;
let inputs: DialogInput[] = [
{ type: 'text-ref' as 'text-ref', name: 'Name', default: '' },
{ type: 'select' as 'select', name: 'Type', default: this.config.dialogDefaults.addTag.type, options: [{ name: 'Annotated', value: 'annotated' }, { name: 'Lightweight', value: 'lightweight' }] },
{ type: 'select' as 'select', name: 'Type', default: dialogConfig.type, options: [{ name: 'Annotated', value: 'annotated' }, { name: 'Lightweight', value: 'lightweight' }] },
{ type: 'text' as 'text', name: 'Message', default: '', placeholder: 'Optional' }
], 'Add Tag', values => {
runAction({ command: 'addTag', repo: this.currentRepo, tagName: values[0], commitHash: hash, lightweight: values[1] === 'lightweight', message: values[2] }, 'Adding Tag');
];
if (this.gitRemotes.length > 1) {
let options = [{ name: 'Don\'t push', value: '-1' }];
this.gitRemotes.forEach((remote, i) => options.push({ name: remote, value: i.toString() }));
let defaultOption = dialogConfig.pushToRemote
? this.gitRemotes.includes('origin')
? this.gitRemotes.indexOf('origin')
: 0
: -1;
inputs.push({ type: 'select', name: 'Push to remote', options: options, default: defaultOption.toString(), info: 'Once this tag has been added, push it to this remote.' });
} else if (this.gitRemotes.length === 1) {
inputs.push({ type: 'checkbox', name: 'Push to remote', value: dialogConfig.pushToRemote, info: 'Once this tag has been added, push it to the repositories remote.' });
}
dialog.showForm('Add tag to commit <b><i>' + abbrevCommit(hash) + '</i></b>:', inputs, 'Add Tag', values => {
let pushToRemote = this.gitRemotes.length > 1 && values[3] !== '-1'
? this.gitRemotes[parseInt(values[3])]
: this.gitRemotes.length === 1 && values[3] === 'checked'
? this.gitRemotes[0]
: null;
runAction({
command: 'addTag',
repo: this.currentRepo,
tagName: values[0],
commitHash: hash,
lightweight: values[1] === 'lightweight',
message: values[2],
pushToRemote: pushToRemote
}, 'Adding Tag');
}, sourceElem);
}
},
Expand Down Expand Up @@ -1845,7 +1872,7 @@ window.addEventListener('load', () => {
if (settingsWidget.isVisible()) settingsWidget.refresh();
break;
case 'addTag':
refreshOrDisplayError(msg.error, 'Unable to Add Tag');
refreshAndDisplayErrors(msg.errors, 'Unable to Add Tag');
break;
case 'applyStash':
refreshOrDisplayError(msg.error, 'Unable to Apply Stash');
Expand Down
8 changes: 2 additions & 6 deletions web/styles/dialog.css
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@
white-space:nowrap;
}

.dialog > table.dialogForm td:last-child{
.dialog > table.dialogForm td.inputCol{
width:100%;
}

.dialog > table.dialogForm.multi td:nth-child(1){
padding-right:5px;
}

.dialog > table.dialogForm.single select{
.dialog > table.dialogForm input[type=text], .dialog > table.dialogForm select{
width:100%;
}

Expand All @@ -46,10 +46,6 @@
width:100%;
}

.dialog > table.dialogForm input[type=text]{
width:100%;
}

.dialog > table.dialogForm input[type=checkbox]{
vertical-align:text-top;
outline-style:none;
Expand Down

0 comments on commit e862985

Please sign in to comment.