Browse Source

Adds new graph settings & settings UI

main
Eric Amodio 2 years ago
parent
commit
da3ed45758
11 changed files with 307 additions and 46 deletions
  1. +53
    -11
      package.json
  2. +4
    -0
      src/config.ts
  3. +33
    -10
      src/plus/webviews/graph/graphWebview.ts
  4. +11
    -4
      src/plus/webviews/graph/protocol.ts
  5. +2
    -2
      src/system/date.ts
  6. +31
    -6
      src/webviews/apps/plus/graph/GraphWrapper.tsx
  7. +145
    -0
      src/webviews/apps/settings/partials/commit-graph.html
  8. +11
    -13
      src/webviews/apps/settings/partials/rebase-editor.html
  9. +10
    -0
      src/webviews/apps/settings/settings.html
  10. +1
    -0
      src/webviews/apps/settings/settings.scss
  11. +6
    -0
      src/webviews/apps/shared/appWithConfigBase.ts

+ 53
- 11
package.json View File

@ -2092,6 +2092,34 @@
"title": "Commit Graph",
"order": 105,
"properties": {
"gitlens.graph.avatars": {
"type": "boolean",
"default": true,
"markdownDescription": "Specifies whether to show avatar images instead of author initials in the _Commit Graph_",
"scope": "window",
"order": 10
},
"gitlens.graph.highlightRowsOnRefHover": {
"type": "boolean",
"default": true,
"markdownDescription": "Specifies whether to highlight rows associated with the ref when hovering over it in the _Commit Graph_",
"scope": "window",
"order": 11
},
"gitlens.graph.defaultItemLimit": {
"type": "number",
"default": 500,
"markdownDescription": "Specifies the default number of items to show in the _Commit Graph_. Use 0 to specify no limit",
"scope": "window",
"order": 20
},
"gitlens.graph.pageItemLimit": {
"type": "number",
"default": 200,
"markdownDescription": "Specifies the number of additional items to fetch when paginating in the _Commit Graph_. Use 0 to specify no limit",
"scope": "window",
"order": 21
},
"gitlens.graph.commitOrdering": {
"type": "string",
"default": "date",
@ -2107,21 +2135,35 @@
],
"markdownDescription": "Specifies the order by which commits will be shown on the _Commit Graph_",
"scope": "window",
"order": 10
"order": 30
},
"gitlens.graph.defaultItemLimit": {
"type": "number",
"default": 500,
"markdownDescription": "Specifies the default number of items to show in the _Commit Graph_. Use 0 to specify no limit",
"gitlens.graph.dateStyle": {
"type": [
"string",
"null"
],
"default": "relative",
"enum": [
"relative",
"absolute"
],
"enumDescriptions": [
"e.g. 1 day ago",
"e.g. July 25th, 2018 7:18pm"
],
"markdownDescription": "Specifies how dates will be displayed in the _Commit Graph_",
"scope": "window",
"order": 20
"order": 40
},
"gitlens.graph.pageItemLimit": {
"type": "number",
"default": 200,
"markdownDescription": "Specifies the number of additional items to fetch when paginating in the _Commit Graph_. Use 0 to specify no limit",
"gitlens.graph.dateFormat": {
"type": [
"string",
"null"
],
"default": null,
"markdownDescription": "Specifies how absolute dates will be formatted in the _Commit Graph_. See the [Moment.js docs](https://momentjs.com/docs/#/displaying/format/) for supported formats",
"scope": "window",
"order": 21
"order": 41
},
"gitlens.graph.statusBar.enabled": {
"type": "boolean",

+ 4
- 0
src/config.ts View File

@ -378,8 +378,12 @@ export interface GraphColumnConfig {
}
export interface GraphConfig {
avatars: boolean;
commitOrdering: 'date' | 'author-date' | 'topo';
dateFormat: DateTimeFormat | string | null;
dateStyle: DateStyle | null;
defaultItemLimit: number;
highlightRowsOnRefHover: boolean;
pageItemLimit: number;
statusBar: {
enabled: boolean;

+ 33
- 10
src/plus/webviews/graph/graphWebview.ts View File

@ -27,7 +27,7 @@ import { onIpc } from '../../../webviews/protocol';
import { WebviewBase } from '../../../webviews/webviewBase';
import type { SubscriptionChangeEvent } from '../../subscription/subscriptionService';
import { ensurePlusFeaturesEnabled } from '../../subscription/utils';
import type { DismissBannerParams, GraphCompositeConfig, GraphRepository, State } from './protocol';
import type { DismissBannerParams, GraphComponentConfig, GraphRepository, State } from './protocol';
import {
DidChangeAvatarsNotificationType,
DidChangeCommitsNotificationType,
@ -254,6 +254,24 @@ export class GraphWebview extends WebviewBase {
this._statusBarItem = undefined;
}
}
if (configuration.changed(e, 'graph.commitOrdering')) {
this.updateState();
return;
}
if (
configuration.changed(e, 'defaultDateFormat') ||
configuration.changed(e, 'defaultDateStyle') ||
configuration.changed(e, 'advanced.abbreviatedShaLength') ||
configuration.changed(e, 'graph.avatars') ||
configuration.changed(e, 'graph.dateFormat') ||
configuration.changed(e, 'graph.dateStyle') ||
configuration.changed(e, 'graph.highlightRowsOnRefHover')
) {
void this.notifyDidChangeGraphConfiguration();
}
}
private onRepositoryChanged(e: RepositoryChangeEvent) {
@ -351,7 +369,7 @@ export class GraphWebview extends WebviewBase {
return;
}
const { defaultItemLimit, pageItemLimit } = this.getConfig();
const { defaultItemLimit, pageItemLimit } = configuration.get('graph');
const newGraph = await this._graph.more(pageItemLimit ?? defaultItemLimit);
if (newGraph != null) {
this.setGraph(newGraph);
@ -444,7 +462,7 @@ export class GraphWebview extends WebviewBase {
if (!this.isReady || !this.visible) return false;
return this.notify(DidChangeGraphConfigurationNotificationType, {
config: this.getConfig(),
config: this.getComponentConfig(),
});
}
@ -498,11 +516,16 @@ export class GraphWebview extends WebviewBase {
return success;
}
private getConfig(): GraphCompositeConfig {
const settings = configuration.get('graph');
const config: GraphCompositeConfig = {
...settings,
private getComponentConfig(): GraphComponentConfig {
const config: GraphComponentConfig = {
avatars: configuration.get('graph.avatars'),
columns: this.container.storage.getWorkspace('graph:columns'),
dateFormat:
configuration.get('graph.dateFormat') ?? configuration.get('defaultDateFormat') ?? 'short+short',
dateStyle: configuration.get('graph.dateStyle') ?? configuration.get('defaultDateStyle'),
enableMultiSelection: false,
highlightRowsOnRefHover: configuration.get('graph.highlightRowsOnRefHover'),
shaLength: configuration.get('advanced.abbreviatedShaLength'),
};
return config;
}
@ -528,10 +551,10 @@ export class GraphWebview extends WebviewBase {
this._etagRepository = this.repository?.etag;
this.title = `${this.originalTitle}: ${this.repository.formattedName}`;
const config = this.getConfig();
const { defaultItemLimit } = configuration.get('graph');
// If we have a set of data refresh to the same set
const limit = Math.max(config.defaultItemLimit, this._graph?.ids.size ?? config.defaultItemLimit);
const limit = Math.max(defaultItemLimit, this._graph?.ids.size ?? defaultItemLimit);
// Check for GitLens+ access
const access = await this.getGraphAccess();
@ -578,7 +601,7 @@ export class GraphWebview extends WebviewBase {
more: data.paging?.more ?? false,
}
: undefined,
config: config,
config: this.getComponentConfig(),
nonce: this.cspNonce,
};
}

+ 11
- 4
src/plus/webviews/graph/protocol.ts View File

@ -1,8 +1,9 @@
import type { GraphRow, Remote } from '@gitkraken/gitkraken-components';
import type { GraphColumnConfig, GraphConfig } from '../../../config';
import type { DateStyle, GraphColumnConfig } from '../../../config';
import type { RepositoryVisibility } from '../../../git/gitProvider';
import type { GitGraphRowType } from '../../../git/models/graph';
import type { Subscription } from '../../../subscription';
import type { DateTimeFormat } from '../../../system/date';
import { IpcCommandType, IpcNotificationType } from '../../../webviews/protocol';
export interface State {
@ -16,7 +17,7 @@ export interface State {
loading?: boolean;
rows?: GraphRow[];
paging?: GraphPaging;
config?: GraphCompositeConfig;
config?: GraphComponentConfig;
nonce?: string;
previewBanner?: boolean;
trialBanner?: boolean;
@ -56,8 +57,14 @@ export type GraphRemote = Remote;
export type GraphTag = Record<string, any>;
export type GraphBranch = Record<string, any>;
export interface GraphCompositeConfig extends GraphConfig {
export interface GraphComponentConfig {
avatars?: boolean;
columns?: Record<string, GraphColumnConfig>;
dateFormat: DateTimeFormat | string;
dateStyle: DateStyle;
enableMultiSelection?: boolean;
highlightRowsOnRefHover?: boolean;
shaLength?: number;
}
export interface UpdateStateCallback {
@ -102,7 +109,7 @@ export interface DidChangeParams {
export const DidChangeNotificationType = new IpcNotificationType<DidChangeParams>('graph/didChange');
export interface DidChangeGraphConfigurationParams {
config: GraphCompositeConfig;
config: GraphComponentConfig;
}
export const DidChangeGraphConfigurationNotificationType = new IpcNotificationType<DidChangeGraphConfigurationParams>(
'graph/configuration/didChange',

+ 2
- 2
src/system/date.ts View File

@ -72,8 +72,8 @@ export function createFromDateDelta(
return d;
}
export function fromNow(date: Date, short?: boolean): string {
const elapsed = date.getTime() - new Date().getTime();
export function fromNow(date: Date | number, short?: boolean): string {
const elapsed = (typeof date === 'number' ? date : date.getTime()) - new Date().getTime();
for (const [unit, threshold, divisor, shortUnit] of relativeUnitThresholds) {
const elapsedABS = Math.abs(elapsed);

+ 31
- 6
src/webviews/apps/plus/graph/GraphWrapper.tsx View File

@ -1,3 +1,4 @@
import type { OnFormatCommitDateTime } from '@gitkraken/gitkraken-components';
import GraphContainer, {
type CssVariables,
type GraphColumnSetting as GKGraphColumnSetting,
@ -9,12 +10,13 @@ import GraphContainer, {
import type { ReactElement } from 'react';
import React, { createElement, useEffect, useRef, useState } from 'react';
import { getPlatform } from '@env/platform';
import { DateStyle } from '../../../../config';
import type { GraphColumnConfig } from '../../../../config';
import { RepositoryVisibility } from '../../../../git/gitProvider';
import type { GitGraphRowType } from '../../../../git/models/graph';
import type {
DismissBannerParams,
GraphCompositeConfig,
GraphComponentConfig,
GraphRepository,
State,
UpdateStateCallback,
@ -22,6 +24,8 @@ import type {
import type { Subscription } from '../../../../subscription';
import { getSubscriptionTimeRemaining, SubscriptionState } from '../../../../subscription';
import { pluralize } from '../../../../system/string';
import type { DateTimeFormat } from '../../shared/date';
import { formatDate, fromNow } from '../../shared/date';
export interface GraphWrapperProps extends State {
nonce?: string;
@ -65,7 +69,7 @@ const defaultGraphColumnsSettings: GKGraphColumnsSettings = {
refZone: { width: 150 },
};
const getGraphColSettingsModel = (config?: GraphCompositeConfig): GKGraphColumnsSettings => {
const getGraphColSettingsModel = (config?: GraphComponentConfig): GKGraphColumnsSettings => {
const columnsSettings: GKGraphColumnsSettings = { ...defaultGraphColumnsSettings };
if (config?.columns !== undefined) {
for (const column of Object.keys(config.columns)) {
@ -77,6 +81,10 @@ const getGraphColSettingsModel = (config?: GraphCompositeConfig): GKGraphColumns
return columnsSettings;
};
const getGraphDateFormatter = (config?: GraphComponentConfig): OnFormatCommitDateTime => {
return (commitDateTime: number) => formatCommitDateTime(commitDateTime, config?.dateStyle, config?.dateFormat);
};
type DebouncableFn = (...args: any) => void;
type DebouncedFn = (...args: any) => void;
const debounceFrame = (func: DebouncableFn): DebouncedFn => {
@ -163,6 +171,8 @@ export function GraphWrapper({
reposList.find(item => item.path === selectedRepository),
);
const [graphSelectedRows, setSelectedRows] = useState(selectedRows);
const [graphConfig, setGraphConfig] = useState(config);
// const [graphDateFormatter, setGraphDateFormatter] = useState(getGraphDateFormatter(config));
const [graphColSettings, setGraphColSettings] = useState(getGraphColSettingsModel(config));
const [pagingState, setPagingState] = useState(paging);
const [isLoading, setIsLoading] = useState(loading);
@ -204,6 +214,8 @@ export function GraphWrapper({
setReposList(state.repositories ?? []);
setCurrentRepository(reposList.find(item => item.path === state.selectedRepository));
setSelectedRows(state.selectedRows);
setGraphConfig(state.config);
// setGraphDateFormatter(getGraphDateFormatter(config));
setGraphColSettings(getGraphColSettingsModel(state.config));
setPagingState(state.paging);
setStyleProps(getStyleProps(state.mixedColumnColors));
@ -429,23 +441,28 @@ export function GraphWrapper({
<>
{mainWidth !== undefined && mainHeight !== undefined && (
<GraphContainer
avatarUrlByEmail={graphAvatars}
columnsSettings={graphColSettings}
cssVariables={styleProps.cssVariables}
enableMultiSelection={graphConfig?.enableMultiSelection}
formatCommitDateTime={getGraphDateFormatter(graphConfig)}
getExternalIcon={getIconElementLibrary}
avatarUrlByEmail={graphAvatars}
graphRows={graphRows}
height={mainHeight}
isSelectedBySha={graphSelectedRows}
hasMoreCommits={pagingState?.more}
height={mainHeight}
// highlightRowssOnRefHover={graphConfig?.highlightRowsOnRefHover}
isLoadingRows={isLoading}
isSelectedBySha={graphSelectedRows}
nonce={nonce}
onColumnResized={handleOnColumnResized}
onSelectGraphRows={handleSelectGraphRows}
onEmailsMissingAvatarUrls={handleMissingAvatars}
onShowMoreCommits={handleMoreCommits}
platform={clientPlatform}
width={mainWidth}
shaLength={graphConfig?.shaLength}
themeOpacityFactor={styleProps.themeOpacityFactor}
useAuthorInitialsForAvatars={!graphConfig?.avatars}
width={mainWidth}
/>
)}
</>
@ -540,3 +557,11 @@ export function GraphWrapper({
</>
);
}
function formatCommitDateTime(
commitDateTime: number,
style: DateStyle = DateStyle.Absolute,
format: DateTimeFormat | string = 'short+short',
): string {
return style === DateStyle.Relative ? fromNow(commitDateTime) : formatDate(commitDateTime, format);
}

+ 145
- 0
src/webviews/apps/settings/partials/commit-graph.html View File

@ -0,0 +1,145 @@
<section id="commit-graph" class="section--settings section--collapsible">
<div class="section__header">
<h2>
Commit Graph
<a
class="link__learn-more"
title="Learn more"
href="https://github.com/gitkraken/vscode-gitlens/#commit-graph-"
>
<i class="icon icon__info"></i>
</a>
</h2>
<p class="section__header-hint">
Adds a
<a class="command command--show-view" title="Show Commit Graph" href="command:gitlens.showGraphPage"
>Commit Graph</a
>
to visualize, explore, and manage a Git repository ✨
</p>
</div>
<div class="section__collapsible">
<div class="section__group">
<div class="section__content">
<div class="settings settings--fixed ml-1">
<div class="setting">
<div class="setting__input">
<label for="graph.defaultItemLimit">Show </label>
<input
id="graph.defaultItemLimit"
name="graph.defaultItemLimit"
type="number"
placeholder="500"
data-setting
data-default-value="500"
/>
<label for="graph.defaultItemLimit"> rows initially</label>
</div>
</div>
<div class="setting">
<div class="setting__input">
<label for="graph.pageItemLimit">Show an additional </label>
<input
id="graph.pageItemLimit"
name="graph.pageItemLimit"
type="number"
placeholder="90"
data-setting
data-default-value="90"
/>
<label for="graph.pageItemLimit"> rows when scrolling</label>
</div>
</div>
<div class="setting">
<div class="setting__input">
<input id="graph.avatars" name="graph.avatars" type="checkbox" data-setting />
<label for="graph.avatars">Use author avatars</label>
</div>
</div>
<div class="setting">
<div class="setting__input">
<input
id="graph.highlightRowsOnRefHover"
name="graph.highlightRowsOnRefHover"
type="checkbox"
data-setting
/>
<label for="graph.highlightRowsOnRefHover"
>Highlight associated rows when hovering on a branch</label
>
</div>
</div>
<div class="setting">
<div class="setting__input">
<input
id="graph.dateStyle"
name="graph.dateStyle"
type="checkbox"
value="relative"
data-value-off="absolute"
data-setting
/>
<label for="graph.dateStyle">Allow relative date formatting</label>
</div>
<span class="setting__hint hidden" data-visibility="graph.dateStyle =relative"
>Shows some dates relatively, e.g. 1 day ago</span
>
<span class="setting__hint hidden" data-visibility="graph.dateStyle =absolute"
>Shows dates absolutely, e.g.
<span
data-setting-preview="graph.dateFormat"
data-setting-preview-type="date"
data-setting-preview-default-lookup="defaultDateFormat"
></span>
</span>
</div>
<div class="setting">
<div class="setting__input">
<label for="graph.dateFormat">Date&nbsp;format</label>
<input
id="graph.dateFormat"
name="graph.dateFormat"
type="text"
placeholder="defaults to `defaultDateFormat` value"
data-setting
data-setting-preview
/>
<a
class="link__learn-more"
title="See Moment.js docs for supported date formats"
href="https://momentjs.com/docs/#/displaying/format/"
>
<i class="icon icon__info"></i>
</a>
</div>
<span class="setting__hint"
>Example date:
<span
data-setting-preview="graph.dateFormat"
data-setting-preview-type="date"
data-setting-preview-default-lookup="defaultDateFormat"
></span>
</span>
</div>
</div>
</div>
<div class="section__preview">
<img
class="image__preview"
src="#{webroot}/media/plus-commit-graph-illustrated.webp"
loading="lazy"
width="850"
height="450"
/>
</div>
</div>
</div>
</section>

+ 11
- 13
src/webviews/apps/settings/partials/rebase-editor.html View File

@ -23,20 +23,18 @@
</p>
</div>
<div class="section__collapsible">
<div class="section__group">
<div class="section__content"></div>
<div class="section__group">
<div class="section__content hidden"></div>
<div class="section__preview">
<img
class="image__preview hidden"
src="#{webroot}/media/rebase-editor.webp"
data-visibility="rebaseEditor.enabled"
loading="lazy"
width="645"
height="441"
/>
</div>
<div class="section__preview">
<img
class="image__preview hidden"
src="#{webroot}/media/rebase-editor.webp"
data-visibility="rebaseEditor.enabled"
loading="lazy"
width="645"
height="441"
/>
</div>
</div>
</section>

+ 10
- 0
src/webviews/apps/settings/settings.html View File

@ -81,6 +81,7 @@
<%= require('html-loader?{"esModule":false}!./partials/blame.html') %>
<%= require('html-loader?{"esModule":false}!./partials/changes.html') %>
<%= require('html-loader?{"esModule":false}!./partials/heatmap.html') %>
<%= require('html-loader?{"esModule":false}!./partials/commit-graph.html') %>
<%= require('html-loader?{"esModule":false}!./partials/rebase-editor.html') %>
<%= require('html-loader?{"esModule":false}!./partials/autolinks.html') %>
<%= require('html-loader?{"esModule":false}!./partials/dates.html') %>
@ -271,6 +272,15 @@
<a
class="sidebar__jump-link"
data-action="jump"
href="#commit-graph"
title="Jump to Commit Graph settings"
>Commit Graph</a
>
</li>
<li>
<a
class="sidebar__jump-link"
data-action="jump"
href="#rebase-editor"
title="Jump to Interactive Rebase Editor settings"
>Interactive Rebase Editor</a

+ 1
- 0
src/webviews/apps/settings/settings.scss View File

@ -207,6 +207,7 @@ header {
border-radius: 8px;
box-shadow: 0px 0px 1px 0px rgba(0, 0, 0, 0.8), 0px 0px 12px 1px rgba(0, 0, 0, 0.5);
width: 600px;
height: auto;
}
.image__preview--fit {

+ 6
- 0
src/webviews/apps/shared/appWithConfigBase.ts View File

@ -520,6 +520,12 @@ export abstract class AppWithConfig extends Ap
if (!value) {
value = el.dataset.settingPreviewDefault;
if (value == null) {
const lookup = el.dataset.settingPreviewDefaultLookup;
if (lookup != null) {
value = this.getSettingValue<string>(lookup);
}
}
}
el.innerText = value == null ? '' : formatDate(date, value, undefined, false);

Loading…
Cancel
Save