From 0522cee48e56fc4c4a1db4f0edef3a294c1c0762 Mon Sep 17 00:00:00 2001
From: ericf-axosoft <90025366+ericf-axosoft@users.noreply.github.com>
Date: Wed, 30 Nov 2022 10:39:44 +0100
Subject: [PATCH] 84 - Graph: Allow column re-ordering (Gitlens side) (#2330)

* 84 - Graph: Allow column re-ordering

* Fixed formatting issue

* Avoid "forEach" loops

* Simplified loop code
---
 src/plus/webviews/graph/graphWebview.ts       | 19 +++++++++++--------
 src/plus/webviews/graph/protocol.ts           | 10 ++++++----
 src/webviews/apps/plus/graph/GraphWrapper.tsx | 27 ++++++++++++++++++++-------
 src/webviews/apps/plus/graph/graph.tsx        | 14 ++++++--------
 4 files changed, 43 insertions(+), 27 deletions(-)

diff --git a/src/plus/webviews/graph/graphWebview.ts b/src/plus/webviews/graph/graphWebview.ts
index a6b24c3..369f108 100644
--- a/src/plus/webviews/graph/graphWebview.ts
+++ b/src/plus/webviews/graph/graphWebview.ts
@@ -87,6 +87,7 @@ import type {
 	GetMoreRowsParams,
 	GraphColumnConfig,
 	GraphColumnName,
+	GraphColumnsConfig,
 	GraphColumnsSettings,
 	GraphComponentConfig,
 	GraphHiddenRef,
@@ -101,7 +102,7 @@ import type {
 	SearchOpenInViewParams,
 	SearchParams,
 	State,
-	UpdateColumnParams,
+	UpdateColumnsParams,
 	UpdateRefsVisibilityParams,
 	UpdateSelectedRepositoryParams,
 	UpdateSelectionParams,
@@ -127,7 +128,7 @@ import {
 	GetMoreRowsCommandType,
 	SearchCommandType,
 	SearchOpenInViewCommandType,
-	UpdateColumnCommandType,
+	UpdateColumnsCommandType,
 	UpdateRefsVisibilityCommandType,
 	UpdateSelectedRepositoryCommandType,
 	UpdateSelectionCommandType,
@@ -414,8 +415,8 @@ export class GraphWebview extends WebviewBase<State> {
 			case SearchOpenInViewCommandType.method:
 				onIpc(SearchOpenInViewCommandType, e, params => this.onSearchOpenInView(params));
 				break;
-			case UpdateColumnCommandType.method:
-				onIpc(UpdateColumnCommandType, e, params => this.onColumnChanged(params));
+			case UpdateColumnsCommandType.method:
+				onIpc(UpdateColumnsCommandType, e, params => this.onColumnsChanged(params));
 				break;
 			case UpdateRefsVisibilityCommandType.method:
 				onIpc(UpdateRefsVisibilityCommandType, e, params => this.onRefsVisibilityChanged(params));
@@ -587,8 +588,8 @@ export class GraphWebview extends WebviewBase<State> {
 		void this.container.storage.storeWorkspace('graph:banners:dismissed', banners);
 	}
 
-	private onColumnChanged(e: UpdateColumnParams) {
-		this.updateColumn(e.name, e.config);
+	private onColumnsChanged(e: UpdateColumnsParams) {
+		this.updateColumns(e.config);
 	}
 
 	private onRefsVisibilityChanged(e: UpdateRefsVisibilityParams) {
@@ -1436,9 +1437,11 @@ export class GraphWebview extends WebviewBase<State> {
 		};
 	}
 
-	private updateColumn(name: GraphColumnName, cfg: GraphColumnConfig) {
+	private updateColumns(columnsCfg: GraphColumnsConfig) {
 		let columns = this.container.storage.getWorkspace('graph:columns');
-		columns = updateRecordValue(columns, name, cfg);
+		for (const [key, value] of Object.entries(columnsCfg)) {
+			columns = updateRecordValue(columns, key, value);
+		}
 		void this.container.storage.storeWorkspace('graph:columns', columns);
 		void this.notifyDidChangeColumns();
 	}
diff --git a/src/plus/webviews/graph/protocol.ts b/src/plus/webviews/graph/protocol.ts
index 92546b3..d77361b 100644
--- a/src/plus/webviews/graph/protocol.ts
+++ b/src/plus/webviews/graph/protocol.ts
@@ -111,8 +111,11 @@ export interface GraphComponentConfig {
 export interface GraphColumnConfig {
 	isHidden?: boolean;
 	width?: number;
+	order?: number;
 }
 
+export type GraphColumnsConfig = {[name: string]: GraphColumnConfig};
+
 export type GraphHiddenRefs = HiddenRefsById;
 export type GraphHiddenRef = GraphRefOptData;
 
@@ -165,11 +168,10 @@ export interface SearchOpenInViewParams {
 }
 export const SearchOpenInViewCommandType = new IpcCommandType<SearchOpenInViewParams>('graph/search/openInView');
 
-export interface UpdateColumnParams {
-	name: GraphColumnName;
-	config: GraphColumnConfig;
+export interface UpdateColumnsParams {
+	config: GraphColumnsConfig;
 }
-export const UpdateColumnCommandType = new IpcCommandType<UpdateColumnParams>('graph/column/update');
+export const UpdateColumnsCommandType = new IpcCommandType<UpdateColumnsParams>('graph/columns/update');
 
 export interface UpdateRefsVisibilityParams {
 	refs: GraphHiddenRef[];
diff --git a/src/webviews/apps/plus/graph/GraphWrapper.tsx b/src/webviews/apps/plus/graph/GraphWrapper.tsx
index 15d035e..118d186 100644
--- a/src/webviews/apps/plus/graph/GraphWrapper.tsx
+++ b/src/webviews/apps/plus/graph/GraphWrapper.tsx
@@ -1,13 +1,14 @@
 import GraphContainer from '@gitkraken/gitkraken-components';
 import type {
 	GraphColumnSetting,
+	GraphColumnsSettings,
 	GraphContainerProps,
 	GraphPlatform,
 	GraphRef,
 	GraphRefGroup,
 	GraphRefOptData,
 	GraphRow,
-	OnFormatCommitDateTime,
+ 	OnFormatCommitDateTime
 } from '@gitkraken/gitkraken-components';
 import type { ReactElement } from 'react';
 import React, { createElement, useEffect, useMemo, useRef, useState } from 'react';
@@ -20,8 +21,8 @@ import type {
 	DidSearchParams,
 	DismissBannerParams,
 	GraphAvatars,
-	GraphColumnConfig,
 	GraphColumnName,
+	GraphColumnsConfig,
 	GraphComponentConfig,
 	GraphHiddenRef,
 	GraphMissingRefsMetadata,
@@ -59,7 +60,7 @@ export interface GraphWrapperProps {
 	state: State;
 	subscriber: (callback: UpdateStateCallback) => () => void;
 	onSelectRepository?: (repository: GraphRepository) => void;
-	onColumnChange?: (name: GraphColumnName, settings: GraphColumnConfig) => void;
+	onColumnsChange?: (colsSettings: GraphColumnsConfig) => void;
 	onDoubleClickRef?: (ref: GraphRef) => void;
 	onMissingAvatars?: (emails: { [email: string]: string }) => void;
 	onMissingRefsMetadata?: (metadata: GraphMissingRefsMetadata) => void;
@@ -131,7 +132,7 @@ export function GraphWrapper({
 	nonce,
 	state,
 	onSelectRepository,
-	onColumnChange,
+	onColumnsChange,
 	onDoubleClickRef,
 	onEnsureRowPromise,
 	onMissingAvatars,
@@ -473,13 +474,24 @@ export function GraphWrapper({
 
 	const handleOnColumnResized = (columnName: GraphColumnName, columnSettings: GraphColumnSetting) => {
 		if (columnSettings.width) {
-			onColumnChange?.(columnName, {
-				width: columnSettings.width,
-				isHidden: columnSettings.isHidden,
+			onColumnsChange?.({
+				[columnName]: {
+					width: columnSettings.width,
+					isHidden: columnSettings.isHidden,
+					order: columnSettings.order
+				}
 			});
 		}
 	};
 
+	const handleOnGraphColumnsReOrdered = (columnsSettings: GraphColumnsSettings) => {
+		const graphColumnsConfig: GraphColumnsConfig = {};
+		for (const [columnName, config] of Object.entries(columnsSettings as GraphColumnsConfig)) {
+			graphColumnsConfig[columnName] = { ...config };
+		}
+		onColumnsChange?.(graphColumnsConfig);
+	};
+
 	const handleOnToggleRefsVisibilityClick = (_event: any, refs: GraphRefOptData[], visible: boolean) => {
 		onRefsVisibilityChange?.(refs, visible);
 	};
@@ -736,6 +748,7 @@ export function GraphWrapper({
 							nonce={nonce}
 							onColumnResized={handleOnColumnResized}
 							onDoubleClickGraphRef={handleOnDoubleClickRef}
+							onGraphColumnsReOrdered={handleOnGraphColumnsReOrdered}
 							onSelectGraphRows={handleSelectGraphRows}
 							onToggleRefsVisibilityClick={handleOnToggleRefsVisibilityClick}
 							onEmailsMissingAvatarUrls={handleMissingAvatars}
diff --git a/src/webviews/apps/plus/graph/graph.tsx b/src/webviews/apps/plus/graph/graph.tsx
index a629921..c613c91 100644
--- a/src/webviews/apps/plus/graph/graph.tsx
+++ b/src/webviews/apps/plus/graph/graph.tsx
@@ -7,8 +7,7 @@ import type { SearchQuery } from '../../../../git/search';
 import type {
 	DismissBannerParams,
 	GraphAvatars,
-	GraphColumnConfig,
-	GraphColumnName,
+	GraphColumnsConfig,
 	GraphHiddenRef,
 	GraphMissingRefsMetadata,
 	GraphRepository,
@@ -37,7 +36,7 @@ import {
 	GetMoreRowsCommandType,
 	SearchCommandType,
 	SearchOpenInViewCommandType,
-	UpdateColumnCommandType,
+	UpdateColumnsCommandType,
 	UpdateRefsVisibilityCommandType,
 	UpdateSelectedRepositoryCommandType as UpdateRepositorySelectionCommandType,
 	UpdateSelectionCommandType,
@@ -84,8 +83,8 @@ export class GraphApp extends App<State> {
 					nonce={this.state.nonce}
 					state={this.state}
 					subscriber={(callback: UpdateStateCallback) => this.registerEvents(callback)}
-					onColumnChange={debounce<GraphApp['onColumnChanged']>(
-						(name, settings) => this.onColumnChanged(name, settings),
+					onColumnsChange={debounce<GraphApp['onColumnsChanged']>(
+						(settings) => this.onColumnsChanged(settings),
 						250,
 					)}
 					onRefsVisibilityChange={(refs: GraphHiddenRef[], visible: boolean) =>
@@ -378,9 +377,8 @@ export class GraphApp extends App<State> {
 		this.sendCommand(DismissBannerCommandType, { key: key });
 	}
 
-	private onColumnChanged(name: GraphColumnName, settings: GraphColumnConfig) {
-		this.sendCommand(UpdateColumnCommandType, {
-			name: name,
+	private onColumnsChanged(settings: GraphColumnsConfig) {
+		this.sendCommand(UpdateColumnsCommandType, {
 			config: settings,
 		});
 	}