Browse Source

Adds context menus for column headers

main
Eric Amodio 2 years ago
parent
commit
9f0e74eb95
9 changed files with 325 additions and 300 deletions
  1. +85
    -1
      package.json
  2. +0
    -5
      src/config.ts
  3. +111
    -49
      src/plus/webviews/graph/graphWebview.ts
  4. +28
    -4
      src/plus/webviews/graph/protocol.ts
  5. +7
    -2
      src/storage.ts
  6. +50
    -109
      src/webviews/apps/plus/graph/GraphWrapper.tsx
  7. +22
    -123
      src/webviews/apps/plus/graph/graph.scss
  8. +18
    -3
      src/webviews/apps/plus/graph/graph.tsx
  9. +4
    -4
      yarn.lock

+ 85
- 1
package.json View File

@ -6378,6 +6378,36 @@
"title": "Create Pull Request...",
"category": "GitLens",
"icon": "$(git-pull-request-create)"
},
{
"command": "gitlens.graph.columnAuthorOn",
"title": "Show Author",
"category": "GitLens"
},
{
"command": "gitlens.graph.columnAuthorOff",
"title": "Hide Author",
"category": "GitLens"
},
{
"command": "gitlens.graph.columnDateTimeOn",
"title": "Show Date",
"category": "GitLens"
},
{
"command": "gitlens.graph.columnDateTimeOff",
"title": "Hide Date",
"category": "GitLens"
},
{
"command": "gitlens.graph.columnShaOn",
"title": "Show SHA",
"category": "GitLens"
},
{
"command": "gitlens.graph.columnShaOff",
"title": "Hide SHA",
"category": "GitLens"
}
],
"icons": {
@ -8258,6 +8288,30 @@
"when": "false"
},
{
"command": "gitlens.graph.columnAuthorOn",
"when": "false"
},
{
"command": "gitlens.graph.columnAuthorOff",
"when": "false"
},
{
"command": "gitlens.graph.columnDateTimeOn",
"when": "false"
},
{
"command": "gitlens.graph.columnDateTimeOff",
"when": "false"
},
{
"command": "gitlens.graph.columnShaOn",
"when": "false"
},
{
"command": "gitlens.graph.columnShaOff",
"when": "false"
},
{
"command": "gitlens.enableDebugLogging",
"when": "config.gitlens.outputLevel != debug"
},
@ -10819,6 +10873,36 @@
"command": "gitlens.graph.createBranch",
"when": "!gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && webviewItem =~ /gitlens:tag\\b/",
"group": "1_gitlens_actions@3"
},
{
"command": "gitlens.graph.columnAuthorOn",
"when": "webviewItem =~ /gitlens:graph:columns\\b/ && webviewItemValue =~ /\\bauthor\\b/",
"group": "1_columns@1"
},
{
"command": "gitlens.graph.columnAuthorOff",
"when": "webviewItem =~ /gitlens:graph:columns\\b/ && webviewItemValue =~ /^(?:(?!\\bauthor\\b).)*$/",
"group": "1_columns@1"
},
{
"command": "gitlens.graph.columnDateTimeOn",
"when": "webviewItem =~ /gitlens:graph:columns\\b/ && webviewItemValue =~ /\\bdatetime\\b/",
"group": "1_columns@2"
},
{
"command": "gitlens.graph.columnDateTimeOff",
"when": "webviewItem =~ /gitlens:graph:columns\\b/ && webviewItemValue =~ /^(?:(?!\\bdatetime\\b).)*$/",
"group": "1_columns@2"
},
{
"command": "gitlens.graph.columnShaOn",
"when": "webviewItem =~ /gitlens:graph:columns\\b/ && webviewItemValue =~ /\\bsha\\b/",
"group": "1_columns@3"
},
{
"command": "gitlens.graph.columnShaOff",
"when": "webviewItem =~ /gitlens:graph:columns\\b/ && webviewItemValue =~ /^(?:(?!\\bsha\\b).)*$/",
"group": "1_columns@3"
}
],
"gitlens/commit/browse": [
@ -12083,7 +12167,7 @@
"vscode:prepublish": "yarn run bundle"
},
"dependencies": {
"@gitkraken/gitkraken-components": "1.0.0-rc.16",
"@gitkraken/gitkraken-components": "1.0.0-rc.17",
"@microsoft/fast-element": "1.10.5",
"@microsoft/fast-react-wrapper": "0.3.14",
"@octokit/core": "4.0.5",

+ 0
- 5
src/config.ts View File

@ -373,11 +373,6 @@ export interface AdvancedConfig {
similarityThreshold: number | null;
}
export interface GraphColumnConfig {
width: number;
isHidden: boolean;
}
export interface GraphConfig {
avatars: boolean;
commitOrdering: 'date' | 'author-date' | 'topo';

+ 111
- 49
src/plus/webviews/graph/graphWebview.ts View File

@ -33,7 +33,7 @@ import { first, last } from '../../../system/iterable';
import { updateRecordValue } from '../../../system/object';
import { isDarkTheme, isLightTheme } from '../../../system/utils';
import type { WebviewItemContext } from '../../../system/webview';
import { isWebviewItemContext } from '../../../system/webview';
import { isWebviewItemContext, serializeWebviewItemContext } from '../../../system/webview';
import { RepositoryFolderNode } from '../../../views/nodes/viewNode';
import type { IpcMessage } from '../../../webviews/protocol';
import { onIpc } from '../../../webviews/protocol';
@ -45,6 +45,8 @@ import type {
EnsureCommitParams,
GetMissingAvatarsParams,
GetMoreCommitsParams,
GraphColumnConfig,
GraphColumnName,
GraphComponentConfig,
GraphRepository,
SearchCommitsParams,
@ -55,6 +57,7 @@ import type {
} from './protocol';
import {
DidChangeAvatarsNotificationType,
DidChangeColumnsNotificationType,
DidChangeCommitsNotificationType,
DidChangeGraphConfigurationNotificationType,
DidChangeNotificationType,
@ -233,6 +236,13 @@ export class GraphWebview extends WebviewBase {
registerCommand('gitlens.graph.createWorktree', this.createWorktree, this),
registerCommand('gitlens.graph.createPullRequest', this.createPullRequest, this),
registerCommand('gitlens.graph.columnAuthorOn', () => this.toggleColumn('author', true)),
registerCommand('gitlens.graph.columnAuthorOff', () => this.toggleColumn('author', false)),
registerCommand('gitlens.graph.columnDateTimeOn', () => this.toggleColumn('datetime', true)),
registerCommand('gitlens.graph.columnDateTimeOff', () => this.toggleColumn('datetime', false)),
registerCommand('gitlens.graph.columnShaOn', () => this.toggleColumn('sha', true)),
registerCommand('gitlens.graph.columnShaOff', () => this.toggleColumn('sha', false)),
];
}
@ -339,7 +349,7 @@ export class GraphWebview extends WebviewBase {
configuration.changed(e, 'graph.dateStyle') ||
configuration.changed(e, 'graph.highlightRowsOnRefHover')
) {
void this.notifyDidChangeGraphConfiguration();
void this.notifyDidChangeConfiguration();
}
}
@ -399,11 +409,7 @@ export class GraphWebview extends WebviewBase {
}
private onColumnUpdated(e: UpdateColumnParams) {
let columns = this.container.storage.getWorkspace('graph:columns');
columns = updateRecordValue(columns, e.name, e.config);
void this.container.storage.storeWorkspace('graph:columns', columns);
void this.notifyDidChangeGraphConfiguration();
this.updateColumn(e.name, e.config);
}
@debug()
@ -622,48 +628,32 @@ export class GraphWebview extends WebviewBase {
}
@debug()
private async notifyDidChangeState() {
if (!this.isReady || !this.visible) return false;
return this.notify(DidChangeNotificationType, { state: await this.getState() });
}
@debug()
private async notifyDidChangeGraphConfiguration() {
if (!this.isReady || !this.visible) return false;
return this.notify(DidChangeGraphConfigurationNotificationType, {
config: this.getComponentConfig(),
});
}
@debug()
private async notifyDidChangeSelection() {
private async notifyDidChangeAvatars() {
if (!this.isReady || !this.visible) return false;
return this.notify(DidChangeSelectionNotificationType, {
selection: this._selectedRows,
const data = this._graph!;
return this.notify(DidChangeAvatarsNotificationType, {
avatars: Object.fromEntries(data.avatars),
});
}
@debug()
private async notifyDidChangeSubscription() {
private async notifyDidChangeColumns() {
if (!this.isReady || !this.visible) return false;
const access = await this.getGraphAccess();
return this.notify(DidChangeSubscriptionNotificationType, {
subscription: access.subscription.current,
allowed: access.allowed,
const columns = this.getColumns();
return this.notify(DidChangeColumnsNotificationType, {
columns: columns,
context: this.getColumnHeaderContext(columns),
});
}
@debug()
private async notifyDidChangeAvatars() {
private async notifyDidChangeConfiguration() {
if (!this.isReady || !this.visible) return false;
const data = this._graph!;
return this.notify(DidChangeAvatarsNotificationType, {
avatars: Object.fromEntries(data.avatars),
return this.notify(DidChangeGraphConfigurationNotificationType, {
config: this.getComponentConfig(),
});
}
@ -692,10 +682,55 @@ export class GraphWebview extends WebviewBase {
return success;
}
@debug()
private async notifyDidChangeSelection() {
if (!this.isReady || !this.visible) return false;
return this.notify(DidChangeSelectionNotificationType, {
selection: this._selectedRows,
});
}
@debug()
private async notifyDidChangeSubscription() {
if (!this.isReady || !this.visible) return false;
const access = await this.getGraphAccess();
return this.notify(DidChangeSubscriptionNotificationType, {
subscription: access.subscription.current,
allowed: access.allowed,
});
}
@debug()
private async notifyDidChangeState() {
if (!this.isReady || !this.visible) return false;
return this.notify(DidChangeNotificationType, { state: await this.getState() });
}
private getColumns(): Record<GraphColumnName, GraphColumnConfig> | undefined {
return this.container.storage.getWorkspace('graph:columns');
}
private getColumnHeaderContext(columns: Record<GraphColumnName, GraphColumnConfig> | undefined): string {
const hidden: string[] = [];
if (columns != null) {
for (const [name, cfg] of Object.entries(columns)) {
if (cfg.isHidden) {
hidden.push(name);
}
}
}
return serializeWebviewItemContext<GraphItemContext>({
webviewItem: 'gitlens:graph:columns',
webviewItemValue: hidden.join(','),
});
}
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'),
@ -706,6 +741,18 @@ export class GraphWebview extends WebviewBase {
return config;
}
private async getGraphAccess() {
let access = await this.container.git.access(PlusFeatures.Graph, this.repository?.path);
this._etagSubscription = this.container.subscription.etag;
// If we don't have access to GitLens+, but the preview trial hasn't been started, auto-start it
if (!access.allowed && access.subscription.current.previewTrial == null) {
await this.container.subscription.startPreviewTrial(true);
access = await this.container.git.access(PlusFeatures.Graph, this.repository?.path);
}
return access;
}
private async getState(deferRows?: boolean): Promise<State> {
if (this.container.git.repositoryCount === 0) return { allowed: true, repositories: [] };
@ -758,6 +805,8 @@ export class GraphWebview extends WebviewBase {
this.setSelectedRows(data.sha);
}
const columns = this.getColumns();
return {
previewBanner: this.previewBanner,
trialBanner: this.trialBanner,
@ -777,21 +826,19 @@ export class GraphWebview extends WebviewBase {
hasMore: data.paging?.hasMore ?? false,
}
: undefined,
columns: columns,
config: this.getComponentConfig(),
context: {
header: this.getColumnHeaderContext(columns),
},
nonce: this.cspNonce,
};
}
private async getGraphAccess() {
let access = await this.container.git.access(PlusFeatures.Graph, this.repository?.path);
this._etagSubscription = this.container.subscription.etag;
// If we don't have access to GitLens+, but the preview trial hasn't been started, auto-start it
if (!access.allowed && access.subscription.current.previewTrial == null) {
await this.container.subscription.startPreviewTrial(true);
access = await this.container.git.access(PlusFeatures.Graph, this.repository?.path);
}
return access;
private updateColumn(name: GraphColumnName, cfg: GraphColumnConfig) {
let columns = this.container.storage.getWorkspace('graph:columns');
columns = updateRecordValue(columns, name, cfg);
void this.container.storage.storeWorkspace('graph:columns', columns);
}
private resetRepositoryState() {
@ -1096,6 +1143,22 @@ export class GraphWebview extends WebviewBase {
return Promise.resolve();
}
@debug()
private async toggleColumn(name: GraphColumnName, visible: boolean) {
let columns = this.container.storage.getWorkspace('graph:columns');
let column = columns?.[name];
if (column != null) {
column.isHidden = !visible;
} else {
column = { isHidden: !visible };
}
columns = updateRecordValue(columns, name, column);
await this.container.storage.storeWorkspace('graph:columns', columns);
void this.notifyDidChangeColumns();
}
}
function formatRepositories(repositories: Repository[]): GraphRepository[] {
@ -1123,9 +1186,7 @@ export interface GraphAvatarContextValue {
email: string;
}
export interface GraphColumnsContextValue {
type: 'columns';
}
export type GraphColumnsContextValue = string;
export interface GraphBranchContextValue {
type: 'branch';
@ -1166,6 +1227,7 @@ function isGraphItemRefContext(item: unknown, refType?: GitReference['refType'])
return (
isGraphItemContext(item) &&
typeof item.webviewItemValue === 'object' &&
'ref' in item.webviewItemValue &&
(refType == null || item.webviewItemValue.ref.refType === refType)
);

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

@ -1,5 +1,11 @@
import type { GraphRow, Remote } from '@gitkraken/gitkraken-components';
import type { DateStyle, GraphColumnConfig } from '../../../config';
import type {
GraphColumnSetting,
GraphContexts,
GraphRow,
GraphZoneType,
Remote,
} from '@gitkraken/gitkraken-components';
import type { DateStyle } from '../../../config';
import type { RepositoryVisibility } from '../../../git/gitProvider';
import type { GitGraphRowType } from '../../../git/models/graph';
import type { SearchQuery } from '../../../git/search';
@ -7,6 +13,8 @@ import type { Subscription } from '../../../subscription';
import type { DateTimeFormat } from '../../../system/date';
import { IpcCommandType, IpcNotificationType } from '../../../webviews/protocol';
export type GraphColumnsSettings = Record<GraphColumnName, GraphColumnSetting>;
export interface State {
repositories?: GraphRepository[];
selectedRepository?: string;
@ -18,7 +26,9 @@ export interface State {
loading?: boolean;
rows?: GraphRow[];
paging?: GraphPaging;
columns?: Record<GraphColumnName, GraphColumnConfig>;
config?: GraphComponentConfig;
context?: GraphContexts;
nonce?: string;
previewBanner?: boolean;
trialBanner?: boolean;
@ -61,7 +71,6 @@ export type GraphBranch = Record;
export interface GraphComponentConfig {
avatars?: boolean;
columns?: Record<string, GraphColumnConfig>;
dateFormat: DateTimeFormat | string;
dateStyle: DateStyle;
enableMultiSelection?: boolean;
@ -69,6 +78,13 @@ export interface GraphComponentConfig {
shaLength?: number;
}
export interface GraphColumnConfig {
isHidden?: boolean;
width?: number;
}
export type GraphColumnName = GraphZoneType;
export interface UpdateStateCallback {
(state: State): void;
}
@ -103,7 +119,7 @@ export interface SearchCommitsParams {
export const SearchCommitsCommandType = new IpcCommandType<SearchCommitsParams>('graph/searchCommits');
export interface UpdateColumnParams {
name: string;
name: GraphColumnName;
config: GraphColumnConfig;
}
export const UpdateColumnCommandType = new IpcCommandType<UpdateColumnParams>('graph/update/column');
@ -148,6 +164,14 @@ export const DidChangeAvatarsNotificationType = new IpcNotificationType
'graph/avatars/didChange',
);
export interface DidChangeColumnsParams {
columns: Record<GraphColumnName, GraphColumnConfig> | undefined;
context?: string;
}
export const DidChangeColumnsNotificationType = new IpcNotificationType<DidChangeColumnsParams>(
'graph/columns/didChange',
);
export interface DidChangeCommitsParams {
rows: GraphRow[];
avatars: { [email: string]: string };

+ 7
- 2
src/storage.ts View File

@ -1,6 +1,6 @@
import type { Disposable, Event, ExtensionContext, SecretStorageChangeEvent } from 'vscode';
import { EventEmitter } from 'vscode';
import type { GraphColumnConfig, ViewShowBranchComparison } from './config';
import type { ViewShowBranchComparison } from './config';
import type { StoredSearchQuery } from './git/search';
import type { Subscription } from './subscription';
import type { TrackedUsage, TrackedUsageKeys } from './usageTracker';
@ -163,7 +163,7 @@ export interface WorkspaceStorage {
banners: {
dismissed?: Record<string, boolean>;
};
columns?: Record<string, GraphColumnConfig>;
columns?: Record<string, StoredGraphColumn>;
};
remote: {
default?: string;
@ -212,6 +212,11 @@ export interface StoredBranchComparisons {
[id: string]: string | StoredBranchComparison;
}
export interface StoredGraphColumn {
isHidden?: boolean;
width?: number;
}
export interface StoredNamedRef {
label?: string;
ref: string;

+ 50
- 109
src/webviews/apps/plus/graph/GraphWrapper.tsx View File

@ -1,17 +1,14 @@
import type { OnFormatCommitDateTime } from '@gitkraken/gitkraken-components';
import GraphContainer, {
type CssVariables,
type GraphColumnSetting as GKGraphColumnSetting,
type GraphColumnsSettings as GKGraphColumnsSettings,
type GraphColumnSetting,
type GraphPlatform,
type GraphRow,
type GraphZoneType,
} from '@gitkraken/gitkraken-components';
import type { ReactElement } from 'react';
import React, { createElement, useEffect, useLayoutEffect, useMemo, 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 { SearchQuery } from '../../../../git/search';
@ -19,6 +16,9 @@ import type {
DidEnsureCommitParams,
DidSearchCommitsParams,
DismissBannerParams,
GraphColumnConfig,
GraphColumnName,
GraphColumnsSettings,
GraphComponentConfig,
GraphRepository,
State,
@ -36,7 +36,7 @@ export interface GraphWrapperProps extends State {
nonce?: string;
subscriber: (callback: UpdateStateCallback) => () => void;
onSelectRepository?: (repository: GraphRepository) => void;
onColumnChange?: (name: string, settings: GraphColumnConfig) => void;
onColumnChange?: (name: GraphColumnName, settings: GraphColumnConfig) => void;
onMissingAvatars?: (emails: { [email: string]: string }) => void;
onMoreCommits?: (id?: string) => void;
onSearchCommits?: (search: SearchQuery | undefined, options?: { limit?: number }) => void;
@ -74,21 +74,24 @@ const getStyleProps = (
};
};
const defaultGraphColumnsSettings: GKGraphColumnsSettings = {
commitAuthorZone: { width: 110, isHidden: false },
commitDateTimeZone: { width: 130, isHidden: false },
commitMessageZone: { width: 130, isHidden: false },
commitZone: { width: 170, isHidden: false },
refZone: { width: 150, isHidden: false },
const defaultGraphColumnsSettings: GraphColumnsSettings = {
ref: { width: 150, isHidden: false },
graph: { width: 150, isHidden: false },
message: { width: 300, isHidden: false },
author: { width: 130, isHidden: false },
datetime: { width: 130, isHidden: false },
sha: { width: 130, isHidden: false },
};
const getGraphColSettingsModel = (config?: GraphComponentConfig): GKGraphColumnsSettings => {
const columnsSettings: GKGraphColumnsSettings = { ...defaultGraphColumnsSettings };
if (config?.columns !== undefined) {
for (const column of Object.keys(config.columns)) {
const getGraphColumns = (columns?: Record<GraphColumnName, GraphColumnConfig> | undefined): GraphColumnsSettings => {
const columnsSettings: GraphColumnsSettings = {
...defaultGraphColumnsSettings,
};
if (columns != null) {
for (const [column, columnCfg] of Object.entries(columns) as [GraphColumnName, GraphColumnConfig][]) {
columnsSettings[column] = {
width: config.columns[column].width,
isHidden: config.columns[column].isHidden,
...defaultGraphColumnsSettings[column],
...columnCfg,
};
}
}
@ -163,33 +166,6 @@ const getClientPlatform = (): GraphPlatform => {
const clientPlatform = getClientPlatform();
const graphColumns: { [Key in GraphZoneType]: { name: string; hideable: boolean } } = {
refZone: {
name: 'Branch / Tag',
hideable: false,
},
commitZone: {
name: 'Graph',
hideable: false,
},
commitMessageZone: {
name: 'Commit Message',
hideable: false,
},
commitAuthorZone: {
name: 'Author',
hideable: true,
},
commitDateTimeZone: {
name: 'Commit Date / Time',
hideable: true,
},
commitShaZone: {
name: 'Sha',
hideable: true,
},
};
// eslint-disable-next-line @typescript-eslint/naming-convention
export function GraphWrapper({
subscriber,
@ -201,7 +177,9 @@ export function GraphWrapper({
selectedRepositoryVisibility,
allowed,
avatars,
columns,
config,
context,
loading,
paging,
onSelectRepository,
@ -228,7 +206,8 @@ export function GraphWrapper({
const [graphSelectedRows, setSelectedRows] = useState(selectedRows);
const [graphConfig, setGraphConfig] = useState(config);
// const [graphDateFormatter, setGraphDateFormatter] = useState(getGraphDateFormatter(config));
const [graphColSettings, setGraphColSettings] = useState(getGraphColSettingsModel(config));
const [graphColumns, setGraphColumns] = useState(getGraphColumns(columns));
const [graphContext, setGraphContext] = useState(context);
const [pagingState, setPagingState] = useState(paging);
const [isLoading, setIsLoading] = useState(loading);
const [styleProps, setStyleProps] = useState(getStyleProps(mixedColumnColors));
@ -246,8 +225,6 @@ export function GraphWrapper({
const [subscriptionSnapshot, setSubscriptionSnapshot] = useState<Subscription | undefined>(subscription);
// repo selection UI
const [repoExpanded, setRepoExpanded] = useState(false);
// column setting UI
const [columnSettingsExpanded, setColumnSettingsExpanded] = useState(false);
// search state
const [searchQuery, setSearchQuery] = useState<SearchQuery | undefined>(undefined);
const [searchResultKey, setSearchResultKey] = useState<string | undefined>(undefined);
@ -432,7 +409,8 @@ export function GraphWrapper({
}
setGraphConfig(state.config);
// setGraphDateFormatter(getGraphDateFormatter(config));
setGraphColSettings(getGraphColSettingsModel(state.config));
setGraphColumns(getGraphColumns(state.columns));
setGraphContext(state.context);
setPagingState(state.paging);
setStyleProps(getStyleProps(state.mixedColumnColors));
setIsAllowed(state.allowed ?? false);
@ -463,15 +441,15 @@ export function GraphWrapper({
onMissingAvatars?.(emails);
};
const handleSelectColumn = (graphZoneType: GraphZoneType) => {
onColumnChange?.(graphZoneType, {
...graphColSettings[graphZoneType],
isHidden: !graphColSettings[graphZoneType]?.isHidden,
const handleToggleColumnSettings = (event: React.MouseEvent<HTMLButtonElement, globalThis.MouseEvent>) => {
const e = event.nativeEvent;
const evt = new MouseEvent('contextmenu', {
bubbles: true,
clientX: e.clientX,
clientY: e.clientY,
});
};
const handleToggleColumnSettings = () => {
setColumnSettingsExpanded(!columnSettingsExpanded);
e.target?.dispatchEvent(evt);
e.stopImmediatePropagation();
};
const handleMoreCommits = () => {
@ -479,9 +457,9 @@ export function GraphWrapper({
onMoreCommits?.();
};
const handleOnColumnResized = (graphZoneType: GraphZoneType, columnSettings: GKGraphColumnSetting) => {
const handleOnColumnResized = (columnName: GraphColumnName, columnSettings: GraphColumnSetting) => {
if (columnSettings.width) {
onColumnChange?.(graphZoneType, {
onColumnChange?.(columnName, {
width: columnSettings.width,
isHidden: columnSettings.isHidden,
});
@ -698,7 +676,8 @@ export function GraphWrapper({
{mainWidth !== undefined && mainHeight !== undefined && (
<GraphContainer
avatarUrlByEmail={graphAvatars}
columnsSettings={graphColSettings}
columnsSettings={graphColumns}
contexts={graphContext}
cssVariables={styleProps.cssVariables}
enableMultiSelection={graphConfig?.enableMultiSelection}
formatCommitDateTime={getGraphDateFormatter(graphConfig)}
@ -726,56 +705,18 @@ export function GraphWrapper({
) : (
<p>No repository is selected</p>
)}
<div className="column-bar">
<div className="column-bar__group">
<div className="column-combo">
<button
type="button"
aria-controls="repo-columnsettings-list"
aria-expanded={columnSettingsExpanded}
aria-haspopup="listbox"
id="columns-column-combo-label"
className="column-combo__label"
role="combobox"
onClick={() => handleToggleColumnSettings()}
>
<span
className="codicon codicon-settings-gear columnsettings__icon"
aria-label="Column Settings"
></span>
</button>
<div
className="column-combo__list"
id="columns-column-combo-list"
role="listbox"
tabIndex={-1}
aria-labelledby="columns-column-combo-label"
>
{Object.entries(graphColumns).map(
([graphZoneType, column]) =>
column.hideable && (
<span
className="column-combo__item"
role="option"
data-value={graphZoneType}
id={`column-column-combo-item-${graphZoneType}`}
key={`column-column-combo-item-${graphZoneType}`}
aria-checked={false}
onClick={() => handleSelectColumn(graphZoneType as GraphZoneType)}
>
<span
className={`column-combo__item-check${
!graphColSettings[graphZoneType]?.isHidden ? ' icon--check' : ''
}`}
/>
{column.name}{' '}
</span>
),
)}
</div>
</div>
</div>
</div>
<button
className="column-button"
type="button"
role="button"
data-vscode-context={JSON.stringify({ webviewItem: 'gitlens:graph:columns' })}
onClick={handleToggleColumnSettings}
>
<span
className="codicon codicon-settings-gear columnsettings__icon"
aria-label="Column Settings"
></span>
</button>
</main>
<footer className={`actionbar graph-app__footer${!isAllowed ? ' is-gated' : ''}`} aria-hidden={!isAllowed}>
<div className="actionbar__group">

+ 22
- 123
src/webviews/apps/plus/graph/graph.scss View File

@ -143,143 +143,42 @@ a {
}
}
.column-bar {
--column-bar-height: 22px;
.column-button {
--column-button-height: 22px;
position: absolute;
top: 0;
right: 2px;
z-index: 10;
right: 0;
z-index: 2;
background-color: var(--actionbar-background-color);
color: var(--color-foreground);
padding: 0;
appearance: none;
font-family: inherit;
background-color: transparent;
border: none;
color: var(--text-disabled, hsla(0, 0%, 100%, 0.4));
margin: 0;
height: var(--column-bar-height);
&,
&__group {
display: flex;
flex-direction: row;
// justify-content: space-between;
align-items: center;
// gap: 0.75rem;
> * {
margin: 0;
}
}
padding: 0 2px;
height: var(--column-button-height);
cursor: pointer;
background-color: var(--actionbar-background-color);
text-align: left;
a {
color: inherit;
&:hover {
background-color: var(--actionbar-hover-background-color);
}
:focus {
&:focus {
outline: 1px solid var(--vscode-focusBorder);
outline-offset: -1px;
}
}
.column-combo {
$block: &;
$block-expanded: #{$block}--expanded;
--column-combo-height: 22px;
--column-combo-items: 1;
--column-combo-items-height: 2.2rem;
position: relative;
display: inline-flex;
flex-direction: row;
align-items: stretch;
font-size: 1.1rem;
gap: 0.25rem;
height: var(--column-combo-height);
line-height: var(--column-combo-height);
&__label {
appearance: none;
font-family: inherit;
background-color: transparent;
border: none;
color: var(--text-disabled, hsla(0, 0%, 100%, 0.4));
margin: 0;
padding: 0;
height: var(--column-combo-height);
cursor: pointer;
background-color: var(--actionbar-background-color);
text-align: left;
&:hover {
background-color: var(--actionbar-hover-background-color);
}
&[disabled] {
pointer-events: none;
opacity: 0.5;
}
.codicon[class*='codicon-'] {
font-size: inherit;
}
}
&__item {
display: flex;
align-items: center;
appearance: none;
font-family: inherit;
background-color: transparent;
border: none;
color: inherit;
padding: 0 0.75rem;
font-size: 1.3rem;
height: var(--column-combo-items-height);
line-height: var(--column-combo-items-height);
cursor: pointer;
background-color: var(--actionbar-background-color);
text-align: left;
&:hover {
background-color: var(--actionbar-hover-background-color);
}
&[disabled] {
pointer-events: none;
opacity: 0.5;
}
&-check {
display: inline-flex;
width: 16px;
height: 16px;
margin-right: 0.25rem;
margin-bottom: 0.5rem;
}
}
&__icon.codicon[class*='codicon-'] {
margin-right: 0.25rem;
}
&__list {
position: absolute;
right: 0;
top: 100%;
display: flex;
flex-direction: column;
justify-content: stretch;
min-width: 100%;
width: max-content;
z-index: 100;
background-color: var(--actionbar-background-color);
}
&__label:not([aria-expanded='true']) + &__list {
display: none;
&[disabled] {
pointer-events: none;
opacity: 0.5;
}
&__item {
.codicon[class*='codicon-'] {
font-size: inherit;
}
}

+ 18
- 3
src/webviews/apps/plus/graph/graph.tsx View File

@ -2,17 +2,19 @@
import type { CssVariables } from '@gitkraken/gitkraken-components';
import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import type { GraphColumnConfig } from '../../../../config';
import type { GitGraphRowType } from '../../../../git/models/graph';
import type { SearchQuery } from '../../../../git/search';
import type {
DismissBannerParams,
GraphColumnConfig,
GraphColumnName,
GraphRepository,
State,
UpdateStateCallback,
} from '../../../../plus/webviews/graph/protocol';
import {
DidChangeAvatarsNotificationType,
DidChangeColumnsNotificationType,
DidChangeCommitsNotificationType,
DidChangeGraphConfigurationNotificationType,
DidChangeNotificationType,
@ -68,7 +70,7 @@ export class GraphApp extends App {
<GraphWrapper
subscriber={(callback: UpdateStateCallback) => this.registerEvents(callback)}
onColumnChange={debounce(
(name: string, settings: GraphColumnConfig) => this.onColumnChanged(name, settings),
(name: GraphColumnName, settings: GraphColumnConfig) => this.onColumnChanged(name, settings),
250,
)}
onSelectRepository={debounce(
@ -116,6 +118,19 @@ export class GraphApp extends App {
});
break;
case DidChangeColumnsNotificationType.method:
onIpc(DidChangeColumnsNotificationType, msg, params => {
this.setState({
...this.state,
...(params.columns != null ? { columns: params.columns } : undefined),
...(params.context != null
? { context: { ...this.state.context, header: params.context } }
: undefined),
});
this.refresh(this.state);
});
break;
case DidChangeCommitsNotificationType.method:
onIpc(DidChangeCommitsNotificationType, msg, params => {
let rows;
@ -278,7 +293,7 @@ export class GraphApp extends App {
this.sendCommand(DismissBannerCommandType, { key: key });
}
private onColumnChanged(name: string, settings: GraphColumnConfig) {
private onColumnChanged(name: GraphColumnName, settings: GraphColumnConfig) {
this.sendCommand(UpdateColumnCommandType, {
name: name,
config: settings,

+ 4
- 4
yarn.lock View File

@ -85,10 +85,10 @@
resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6"
integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==
"@gitkraken/gitkraken-components@1.0.0-rc.16":
version "1.0.0-rc.16"
resolved "https://registry.yarnpkg.com/@gitkraken/gitkraken-components/-/gitkraken-components-1.0.0-rc.16.tgz#b51a7de977d173fa632e966d05d533890444ae04"
integrity sha512-PpEgkIECSSxYYtf3cpCyKs+QgmOCUfomgeIJXhmZexCBkdfYUaiXD894PSRBT2d66tMRHRd0si1JfujHpgBDQg==
"@gitkraken/gitkraken-components@1.0.0-rc.17":
version "1.0.0-rc.17"
resolved "https://registry.yarnpkg.com/@gitkraken/gitkraken-components/-/gitkraken-components-1.0.0-rc.17.tgz#698025c1430375bc743b10fd868cac64fffbbc38"
integrity sha512-wS3JvLm+48e6EiCx9+tkEaAIEgVPEGFqAJT6LsHbe5h9Jgfu4kyHDG0j3cmoSXNp6SpeQ3qHT59fnLhXew+niA==
dependencies:
"@axosoft/react-virtualized" "9.22.3-gitkraken.3"
classnames "2.2.3"

Loading…
Cancel
Save