Browse Source

Refactors apps into a common base

Adds showWhatsNewAfterUpgrades setting
Removes messages.suppressUpdateNotice
Removes messages.suppressWelcomeNotice
main
Eric Amodio 7 years ago
parent
commit
e7e7eccb33
12 changed files with 301 additions and 302 deletions
  1. +3
    -2
      README.md
  2. +7
    -11
      package.json
  3. +18
    -27
      src/extension.ts
  4. +2
    -14
      src/messages.ts
  5. +9
    -9
      src/ui/config.ts
  6. +5
    -1
      src/ui/scss/main.scss
  7. +6
    -217
      src/ui/settings/app.ts
  8. +2
    -2
      src/ui/settings/index.ts
  9. +232
    -0
      src/ui/shared/app-base.ts
  10. +6
    -17
      src/ui/welcome/app.ts
  11. +9
    -0
      src/ui/welcome/index.html
  12. +2
    -2
      src/ui/welcome/index.ts

+ 3
- 2
README.md View File

@ -471,10 +471,11 @@ GitLens is highly customizable and provides many configuration settings to allow
|`gitlens.insiders`|Opts into the insiders channel — provides access to upcoming features
|`gitlens.keymap`|Specifies the keymap to use for GitLens shortcut keys<br />`standard` - adds a standard set of shortcut keys<br />`chorded` - adds a chorded set of shortcut keys that all start with `Ctrl+Shift+G` (`⌥⌘G` on macOS)<br />`none` - no shortcut keys will be added
|`gitlens.outputLevel`|Specifies how much (if any) output will be sent to the GitLens output channel
|`gitlens.showWhatsNewAfterUpgrades`|Specifies whether or not to show What's New after upgrading to new feature releases
### GitLens Explorer Settings
See also [Explorer Settings](#explorer-settings)
See also [Explorer Settings](#explorer-settings "Jump to the Explorer settings")
|Name | Description
|-----|------------
@ -489,7 +490,7 @@ See also [Explorer Settings](#explorer-settings)
### GitLens Results View Settings
See also [Explorer Settings](#explorer-settings)
See also [Explorer Settings](#explorer-settings "Jump to the Explorer settings")
|Name | Description
|-----|------------

+ 7
- 11
package.json View File

@ -677,6 +677,12 @@
"description": "Specifies when to switch between displaying files as a `tree` or `list` based on the number of files in a nesting level in the `GitLens Results` view\nOnly applies when displaying files as `auto`",
"scope": "window"
},
"gitlens.showWhatsNewAfterUpgrades": {
"type": "boolean",
"default": true,
"description": "Specifies whether or not to show What's New after upgrading to new feature releases",
"scope": "window"
},
"gitlens.statusBar.alignment": {
"type": "string",
"default": "right",
@ -937,9 +943,7 @@
"suppressGitVersionWarning": false,
"suppressLineUncommittedWarning": false,
"suppressNoRepositoryWarning": false,
"suppressResultsExplorerNotice": false,
"suppressUpdateNotice": false,
"suppressWelcomeNotice": false
"suppressResultsExplorerNotice": false
},
"properties": {
"suppressCommitHasNoPreviousCommitWarning": {
@ -969,14 +973,6 @@
"suppressResultsExplorerNotice": {
"type": "boolean",
"default": false
},
"suppressUpdateNotice": {
"type": "boolean",
"default": false
},
"suppressWelcomeNotice": {
"type": "boolean",
"default": false
}
},
"description": "Specifies which messages should be suppressed",

+ 18
- 27
src/extension.ts View File

@ -60,7 +60,7 @@ export async function activate(context: ExtensionContext) {
// Telemetry.setContext(telemetryContext);
notifyOnUnsupportedGitVersion(gitVersion);
notifyOnNewGitLensVersion(gitlensVersion, previousVersion);
showWelcomePage(gitlensVersion, previousVersion);
context.globalState.update(GlobalState.GitLensVersion, gitlensVersion);
@ -170,11 +170,6 @@ async function migrateSettings(context: ExtensionContext, previousVersion: strin
}
if (Versions.compare(previous, Versions.from(8, 0, 0, 'beta2')) !== 1) {
const section = configuration.name('advanced')('messages').value;
const messages = configuration.get<{ [key: string]: boolean }>(section);
messages[SuppressedMessages.WelcomeNotice] = false;
await configuration.update(section, messages, ConfigurationTarget.Global);
await configuration.migrate<boolean, OutputLevel>('debug', configuration.name('outputLevel').value, v => v ? OutputLevel.Debug : configuration.get(configuration.name('outputLevel').value));
await configuration.migrate('debug', configuration.name('debug').value, v => undefined);
}
@ -184,26 +179,29 @@ async function migrateSettings(context: ExtensionContext, previousVersion: strin
}
}
async function notifyOnNewGitLensVersion(version: string, previousVersion: string | undefined) {
function notifyOnUnsupportedGitVersion(version: string) {
if (GitService.validateGitVersion(2, 2)) return;
// If git is less than v2.2.0
Messages.showUnsupportedGitVersionErrorMessage(version);
}
async function showWelcomePage(version: string, previousVersion: string | undefined) {
if (previousVersion === undefined) {
Logger.log(`GitLens first-time install`);
}
else if (previousVersion !== version) {
Logger.log(`GitLens upgraded from v${previousVersion} to v${version}`);
}
if (!Container.config.advanced.messages.suppressWelcomeNotice) {
const section = configuration.name('advanced')('messages').value;
const messages = configuration.get<{ [key: string]: boolean }>(section);
messages[SuppressedMessages.WelcomeNotice] = true;
await configuration.update(section, messages, ConfigurationTarget.Global);
await commands.executeCommand(Commands.ShowWelcomePage);
if (Container.config.showWhatsNewAfterUpgrades) {
await commands.executeCommand(Commands.ShowWelcomePage);
}
return;
}
if (previousVersion === undefined || Container.config.advanced.messages.suppressUpdateNotice) return;
if (previousVersion !== version) {
Logger.log(`GitLens upgraded from v${previousVersion} to v${version}`);
}
if (!Container.config.showWhatsNewAfterUpgrades) return;
const [major, minor] = version.split('.');
const [prevMajor, prevMinor] = previousVersion.split('.');
@ -211,12 +209,5 @@ async function notifyOnNewGitLensVersion(version: string, previousVersion: strin
// Don't notify on downgrades
if (major < prevMajor || (major === prevMajor && minor < prevMinor)) return;
await Messages.showUpdateMessage(version);
await commands.executeCommand(Commands.ShowWelcomePage);
}
async function notifyOnUnsupportedGitVersion(version: string) {
if (GitService.validateGitVersion(2, 2)) return;
// If git is less than v2.2.0
await Messages.showUnsupportedGitVersionErrorMessage(version);
}

+ 2
- 14
src/messages.ts View File

@ -1,6 +1,5 @@
'use strict';
import { commands, ConfigurationTarget, Uri, window } from 'vscode';
import { BuiltInCommands } from './constants';
import { ConfigurationTarget, window } from 'vscode';
import { GitCommit } from './gitService';
import { Logger } from './logger';
import { configuration } from './configuration';
@ -12,9 +11,7 @@ export enum SuppressedMessages {
GitVersionWarning = 'suppressGitVersionWarning',
LineUncommittedWarning = 'suppressLineUncommittedWarning',
NoRepositoryWarning = 'suppressNoRepositoryWarning',
ResultsExplorerNotice = 'suppressResultsExplorerNotice',
UpdateNotice = 'suppressUpdateNotice',
WelcomeNotice = 'suppressWelcomeNotice'
ResultsExplorerNotice = 'suppressResultsExplorerNotice'
}
export class Messages {
@ -48,15 +45,6 @@ export class Messages {
return Messages.showMessage('error', `GitLens requires a newer version of Git (>= 2.2.0) than is currently installed (${version}). Please install a more recent version of Git`, SuppressedMessages.GitVersionWarning);
}
static async showUpdateMessage(version: string): Promise<string | undefined> {
const viewReleaseNotes = 'View Release Notes';
const result = await Messages.showMessage('info', `GitLens has been updated to v${version}`, SuppressedMessages.UpdateNotice, undefined, viewReleaseNotes);
if (result === viewReleaseNotes) {
commands.executeCommand(BuiltInCommands.Open, Uri.parse('https://marketplace.visualstudio.com/items/eamodio.gitlens/changelog'));
}
return result;
}
private static async showMessage(type: 'info' | 'warn' | 'error', message: string, suppressionKey: SuppressedMessages, dontShowAgain: string | null = 'Don\'t Show Again', ...actions: any[]): Promise<string | undefined> {
Logger.log(`ShowMessage(${type}, '${message}', ${suppressionKey}, ${dontShowAgain})`);

+ 9
- 9
src/ui/config.ts View File

@ -134,15 +134,13 @@ export interface IAdvancedConfig {
};
messages: {
suppressCommitHasNoPreviousCommitWarning: boolean,
suppressCommitNotFoundWarning: boolean,
suppressFileNotUnderSourceControlWarning: boolean,
suppressGitVersionWarning: boolean,
suppressLineUncommittedWarning: boolean,
suppressNoRepositoryWarning: boolean,
suppressResultsExplorerNotice: boolean,
suppressUpdateNotice: boolean,
suppressWelcomeNotice: boolean
suppressCommitHasNoPreviousCommitWarning: boolean;
suppressCommitNotFoundWarning: boolean;
suppressFileNotUnderSourceControlWarning: boolean;
suppressGitVersionWarning: boolean;
suppressLineUncommittedWarning: boolean;
suppressNoRepositoryWarning: boolean;
suppressResultsExplorerNotice: boolean;
};
quickPick: {
@ -291,6 +289,8 @@ export interface IConfig {
resultsExplorer: IResultsExplorerConfig;
showWhatsNewAfterUpgrades: boolean;
statusBar: {
enabled: boolean;
alignment: 'left' | 'right';

+ 5
- 1
src/ui/scss/main.scss View File

@ -193,7 +193,7 @@ ul {
.changelog__hint {
color: var(--color--75);
font-weight: 200;
margin: 0 1em 1em 1em;
margin: 0 1em 2em 1em;
}
.changelog__list {
@ -599,6 +599,10 @@ ul {
margin-bottom: 2em !important;
}
.ml-1 {
margin-left: 1em;
}
.ml-2 {
margin-left: 2em;
}

+ 6
- 217
src/ui/settings/app.ts View File

@ -1,232 +1,21 @@
'use strict';
import { DOM } from './../shared/dom';
import { initializeColorPalette } from '../shared/colors';
import { IConfig } from './../config';
import { App } from '../shared/app-base';
const config: IConfig = (window as any).gitlens.config;
export class App {
private readonly _commandRelay: HTMLAnchorElement;
private readonly _changes: { [key: string]: any } = Object.create(null);
export class SettingsApp extends App {
constructor() {
console.log('SettingsApp.ctor');
this._commandRelay = DOM.getElementById<HTMLAnchorElement>('commandRelay');
initializeColorPalette();
this.initializeState();
const onInputChecked = this.onInputChecked.bind(this);
DOM.listenAll('input[type="checkbox"],input[type="radio"]', 'change', function(this: HTMLInputElement) { onInputChecked(this); });
super('SettingsApp');
}
const onInputSelected = this.onInputSelected.bind(this);
DOM.listenAll('select', 'change', function(this: HTMLInputElement) { onInputSelected(this); });
protected bind() {
super.bind();
const onSectionHeaderClicked = this.onSectionHeaderClicked.bind(this);
DOM.listenAll('.section__header', 'click', function(this: HTMLInputElement) { onSectionHeaderClicked(this); });
}
private onInputChecked(element: HTMLInputElement) {
console.log(`SettingsApp.onChange: name=${element.name}, checked=${element.checked}, value=${element.value}`);
if (element.dataset.type === 'array') {
const setting = getSettingValue(element.name) || [];
if (Array.isArray(setting)) {
if (element.checked) {
if (!setting.includes(element.value)) {
setting.push(element.value);
}
}
else {
const i = setting.indexOf(element.value);
if (i !== -1) {
setting.splice(i, 1);
}
}
this._changes[element.name] = setting;
}
}
else {
if (element.checked) {
this._changes[element.name] = element.value === 'on' ? true : element.value;
}
else {
this._changes[element.name] = false;
}
}
this.setAdditionalSettings(element.checked ? element.dataset.addSettingsOn : element.dataset.addSettingsOff);
this.applyChanges();
}
private onInputSelected(element: HTMLSelectElement) {
const value = element.options[element.selectedIndex].value;
console.log(`SettingsApp.onSelected: name=${element.name}, value=${value}`);
this._changes[element.name] = ensureIfBoolean(value);
this.applyChanges();
}
private onSectionHeaderClicked(element: HTMLElement) {
element.classList.toggle('collapsed');
}
private applyChanges() {
const args = JSON.stringify(this._changes);
console.log(`SettingsApp.applyChanges: changes=${args}`);
const command = 'command:gitlens.saveSettings?' + encodeURI(args);
setTimeout(() => this.executeCommand(command), 0);
}
private executeCommand(command: string | undefined) {
if (command === undefined) return;
console.log(`SettingsApp.executeCommand: command=${command}`);
this._commandRelay.setAttribute('href', command);
this._commandRelay.click();
}
private initializeState() {
console.log('SettingsApp.initializeState');
for (const el of document.querySelectorAll<HTMLInputElement>('input[type="checkbox"]')) {
const checked = el.dataset.type === 'array'
? (getSettingValue<string[]>(el.name) || []).includes(el.value)
: getSettingValue<boolean>(el.name) || false;
el.checked = checked;
}
for (const el of document.querySelectorAll<HTMLSelectElement>('select')) {
const value = getSettingValue<string>(el.name);
el.querySelector<HTMLOptionElement>(`option[value='${value}']`)!.selected = true;
}
const state = flatten(config);
this.setVisibility(state);
this.setEnablement(state);
}
private setAdditionalSettings(expression: string | undefined) {
if (!expression) return;
const addSettings = parseAdditionalSettingsExpression(expression);
for (const [s, v] of addSettings) {
this._changes[s] = v;
}
}
private setEnablement(state: { [key: string]: string | boolean }) {
for (const el of document.querySelectorAll<HTMLElement>('[data-enablement]')) {
// Since everything starts disabled, kick out if it still is
if (!evaluateStateExpression(el.dataset.enablement!, state)) continue;
el.removeAttribute('disabled');
if (el.matches('input,select')) {
(el as HTMLInputElement | HTMLSelectElement).disabled = false;
}
else {
const input = el.querySelector<HTMLInputElement | HTMLSelectElement>('input,select');
if (input == null) continue;
input.disabled = false;
}
}
}
private setVisibility(state: { [key: string]: string | boolean }) {
for (const el of document.querySelectorAll<HTMLElement>('[data-visibility]')) {
// Since everything starts hidden, kick out if it still is
if (!evaluateStateExpression(el.dataset.visibility!, state)) continue;
el.classList.remove('hidden');
}
}
}
function ensureIfBoolean(value: string | boolean): string | boolean {
if (value === 'true') return true;
if (value === 'false') return false;
return value;
}
function evaluateStateExpression(expression: string, changes: { [key: string]: string | boolean }): boolean {
let state = false;
for (const expr of expression.trim().split('&')) {
const [lhs, op, rhs] = parseStateExpression(expr);
switch (op) {
case '=': { // Equals
let value = changes[lhs];
if (value === undefined) {
value = getSettingValue<string | boolean>(lhs) || false;
}
state = rhs !== undefined ? rhs === '' + value : !!value;
break;
}
case '!': { // Not equals
let value = changes[lhs];
if (value === undefined) {
value = getSettingValue<string | boolean>(lhs) || false;
}
state = rhs !== undefined ? rhs !== '' + value : !value;
break;
}
case '+': { // Contains
if (rhs !== undefined) {
const setting = getSettingValue<string[]>(lhs);
state = setting !== undefined ? setting.includes(rhs.toString()) : false;
}
break;
}
}
if (!state) break;
}
return state;
}
function get<T>(o: { [key: string ]: any}, path: string): T | undefined {
return path.split('.').reduce((o = {}, key) => o[key], o) as T;
}
function getSettingValue<T>(path: string): T | undefined {
return get<T>(config, path);
}
function parseAdditionalSettingsExpression(expression: string): [string, string | boolean][] {
const settingsExpression = expression.trim().split(',');
return settingsExpression.map<[string, string | boolean]>(s => {
const [setting, value] = s.split('=');
return [setting, ensureIfBoolean(value)];
});
}
function parseStateExpression(expression: string): [string, string, string | boolean | undefined] {
const [lhs, op, rhs] = expression.trim().split(/([=\+\!])/);
return [lhs.trim(), op !== undefined ? op.trim() : '=', rhs !== undefined ? rhs.trim() : rhs];
}
function flatten(o: { [key: string]: any }, path?: string): { [key: string]: any } {
const results: { [key: string]: any } = {};
for (const key in o) {
const value = o[key];
if (Array.isArray(value)) continue;
if (typeof value === 'object') {
Object.assign(results, flatten(value, path === undefined ? key : `${path}.${key}`));
}
else {
results[path === undefined ? key : `${path}.${key}`] = value;
}
}
return results;
}

+ 2
- 2
src/ui/settings/index.ts View File

@ -1,4 +1,4 @@
'use strict';
import { App } from './app';
import { SettingsApp } from './app';
new App();
new SettingsApp();

+ 232
- 0
src/ui/shared/app-base.ts View File

@ -0,0 +1,232 @@
'use strict';
import { DOM } from './../shared/dom';
import { initializeColorPalette } from '../shared/colors';
import { IConfig } from './../config';
const config: IConfig = (window as any).gitlens.config;
export abstract class App {
private readonly _commandRelay: HTMLAnchorElement;
private readonly _changes: { [key: string]: any } = Object.create(null);
constructor(private _appName: string) {
this.log(`${this._appName}.ctor`);
this._commandRelay = DOM.getElementById<HTMLAnchorElement>('commandRelay');
initializeColorPalette();
this.initialize();
this.bind();
}
protected initialize() {
this.log(`${this._appName}.initializeState`);
for (const el of document.querySelectorAll<HTMLInputElement>('input[type="checkbox"]')) {
const checked = el.dataset.type === 'array'
? (getSettingValue<string[]>(el.name) || []).includes(el.value)
: getSettingValue<boolean>(el.name) || false;
el.checked = checked;
}
for (const el of document.querySelectorAll<HTMLSelectElement>('select')) {
const value = getSettingValue<string>(el.name);
el.querySelector<HTMLOptionElement>(`option[value='${value}']`)!.selected = true;
}
const state = flatten(config);
this.setVisibility(state);
this.setEnablement(state);
}
protected bind() {
const onInputChecked = this.onInputChecked.bind(this);
DOM.listenAll('input[type="checkbox"],input[type="radio"]', 'change', function(this: HTMLInputElement) { onInputChecked(this); });
const onInputSelected = this.onInputSelected.bind(this);
DOM.listenAll('select', 'change', function(this: HTMLInputElement) { onInputSelected(this); });
}
protected log(message: string) {
console.log(message);
}
private onInputChecked(element: HTMLInputElement) {
this.log(`${this._appName}.onInputChecked: name=${element.name}, checked=${element.checked}, value=${element.value}`);
if (element.dataset.type === 'array') {
const setting = getSettingValue(element.name) || [];
if (Array.isArray(setting)) {
if (element.checked) {
if (!setting.includes(element.value)) {
setting.push(element.value);
}
}
else {
const i = setting.indexOf(element.value);
if (i !== -1) {
setting.splice(i, 1);
}
}
this._changes[element.name] = setting;
}
}
else {
if (element.checked) {
this._changes[element.name] = element.value === 'on' ? true : element.value;
}
else {
this._changes[element.name] = false;
}
}
this.setAdditionalSettings(element.checked ? element.dataset.addSettingsOn : element.dataset.addSettingsOff);
this.applyChanges();
}
private onInputSelected(element: HTMLSelectElement) {
const value = element.options[element.selectedIndex].value;
this.log(`${this._appName}.onInputSelected: name=${element.name}, value=${value}`);
this._changes[element.name] = ensureIfBoolean(value);
this.applyChanges();
}
private applyChanges() {
const args = JSON.stringify(this._changes);
this.log(`${this._appName}.applyChanges: changes=${args}`);
const command = 'command:gitlens.saveSettings?' + encodeURI(args);
setTimeout(() => this.executeCommand(command), 0);
}
protected executeCommand(command: string | undefined) {
if (command === undefined) return;
this.log(`${this._appName}.executeCommand: command=${command}`);
this._commandRelay.setAttribute('href', command);
this._commandRelay.click();
}
private setAdditionalSettings(expression: string | undefined) {
if (!expression) return;
const addSettings = parseAdditionalSettingsExpression(expression);
for (const [s, v] of addSettings) {
this._changes[s] = v;
}
}
private setEnablement(state: { [key: string]: string | boolean }) {
for (const el of document.querySelectorAll<HTMLElement>('[data-enablement]')) {
// Since everything starts disabled, kick out if it still is
if (!evaluateStateExpression(el.dataset.enablement!, state)) continue;
el.removeAttribute('disabled');
if (el.matches('input,select')) {
(el as HTMLInputElement | HTMLSelectElement).disabled = false;
}
else {
const input = el.querySelector<HTMLInputElement | HTMLSelectElement>('input,select');
if (input == null) continue;
input.disabled = false;
}
}
}
private setVisibility(state: { [key: string]: string | boolean }) {
for (const el of document.querySelectorAll<HTMLElement>('[data-visibility]')) {
// Since everything starts hidden, kick out if it still is
if (!evaluateStateExpression(el.dataset.visibility!, state)) continue;
el.classList.remove('hidden');
}
}
}
function ensureIfBoolean(value: string | boolean): string | boolean {
if (value === 'true') return true;
if (value === 'false') return false;
return value;
}
function evaluateStateExpression(expression: string, changes: { [key: string]: string | boolean }): boolean {
let state = false;
for (const expr of expression.trim().split('&')) {
const [lhs, op, rhs] = parseStateExpression(expr);
switch (op) {
case '=': { // Equals
let value = changes[lhs];
if (value === undefined) {
value = getSettingValue<string | boolean>(lhs) || false;
}
state = rhs !== undefined ? rhs === '' + value : !!value;
break;
}
case '!': { // Not equals
let value = changes[lhs];
if (value === undefined) {
value = getSettingValue<string | boolean>(lhs) || false;
}
state = rhs !== undefined ? rhs !== '' + value : !value;
break;
}
case '+': { // Contains
if (rhs !== undefined) {
const setting = getSettingValue<string[]>(lhs);
state = setting !== undefined ? setting.includes(rhs.toString()) : false;
}
break;
}
}
if (!state) break;
}
return state;
}
function get<T>(o: { [key: string ]: any}, path: string): T | undefined {
return path.split('.').reduce((o = {}, key) => o[key], o) as T;
}
function getSettingValue<T>(path: string): T | undefined {
return get<T>(config, path);
}
function parseAdditionalSettingsExpression(expression: string): [string, string | boolean][] {
const settingsExpression = expression.trim().split(',');
return settingsExpression.map<[string, string | boolean]>(s => {
const [setting, value] = s.split('=');
return [setting, ensureIfBoolean(value)];
});
}
function parseStateExpression(expression: string): [string, string, string | boolean | undefined] {
const [lhs, op, rhs] = expression.trim().split(/([=\+\!])/);
return [lhs.trim(), op !== undefined ? op.trim() : '=', rhs !== undefined ? rhs.trim() : rhs];
}
function flatten(o: { [key: string]: any }, path?: string): { [key: string]: any } {
const results: { [key: string]: any } = {};
for (const key in o) {
const value = o[key];
if (Array.isArray(value)) continue;
if (typeof value === 'object') {
Object.assign(results, flatten(value, path === undefined ? key : `${path}.${key}`));
}
else {
results[path === undefined ? key : `${path}.${key}`] = value;
}
}
return results;
}

+ 6
- 17
src/ui/welcome/app.ts View File

@ -1,17 +1,15 @@
'use strict';
import { DOM } from './../shared/dom';
import { initializeColorPalette } from '../shared/colors';
import { App } from '../shared/app-base';
export class App {
private readonly _commandRelay: HTMLAnchorElement;
export class WelcomeApp extends App {
constructor() {
console.log('WelcomeApp.ctor');
this._commandRelay = DOM.getElementById<HTMLAnchorElement>('commandRelay');
super('WelcomeApp');
}
initializeColorPalette();
protected bind() {
super.bind();
const onClicked = this.onClicked.bind(this);
DOM.listenAll('button[data-href]', 'click', function(this: HTMLButtonElement) { onClicked(this); });
@ -20,13 +18,4 @@ export class App {
private onClicked(element: HTMLButtonElement) {
this.executeCommand(element.dataset.href);
}
private executeCommand(command: string | undefined) {
if (command === undefined) return;
console.log(`WelcomeApp.executeCommand: command=${command}`);
this._commandRelay.setAttribute('href', command);
this._commandRelay.click();
}
}

+ 9
- 0
src/ui/welcome/index.html View File

@ -38,9 +38,15 @@
<li><span class="changelog__badge changelog__badge--added">NEW</span>Brand new WYSIWYG <a class="command" title="Open GitLens Settings" href="command:gitlens.showSettingsPage">GitLens Settings</a> editor &mdash; GitLens is easier than ever to customize to suit your needs</li>
<li><span class="changelog__badge changelog__badge--changed">IMPROVED</span>Reworked settings &mdash; clearer, simpler settings</li>
</ul>
<p class="changelog__hint">
See the <a title="Open Release Notes" href="https://github.com/eamodio/vscode-gitlens/blob/develop/CHANGELOG.md">Release Notes</a> for the full set of changes
</p>
<div class="settings-group__setting nowrap ml-1">
<input id="showWhatsNewAfterUpgrades" name="showWhatsNewAfterUpgrades" type="checkbox" />
<label for="showWhatsNewAfterUpgrades">Show What's New after upgrading to new feature releases</label>
</div>
</section>
<div class="section-groups">
@ -184,6 +190,9 @@
</div>
</div>
<a id="commandRelay" style="display: none"></a>
<script type="text/javascript">
window.gitlens = { config: '{{config}}' };
</script>
</body>
</html>

+ 2
- 2
src/ui/welcome/index.ts View File

@ -1,4 +1,4 @@
'use strict';
import { App } from './app';
import { WelcomeApp } from './app';
new App();
new WelcomeApp();

Loading…
Cancel
Save