Skip to content

Commit

Permalink
Improves rebase editor
Browse files Browse the repository at this point in the history
- adds committer info
- ensures focus is restored on long-running updates
- prevents offscreen rows from being rendered
- appends entries to the DOM instead of a DocumentFragment

Co-authored-by: Eric Amodio <eamodio@gmail.com>
  • Loading branch information
d13 and eamodio committed Nov 8, 2022
1 parent ffcaf31 commit f58c3ab
Show file tree
Hide file tree
Showing 10 changed files with 276 additions and 91 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -18,6 +18,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
- Adds a `gitlens.rebaseEditor.showDetailsView` setting to specify when to show the _Commit Details_ view for the selected row in the _Interactive Rebase Editor_
- Adds full (multiline) commit message
- Adds the `f` fixup shortcut key to UI
- Consolidates the UI for author and committer information into a stack of avatars
- Adds emoji support for commit messages &mdash; closes [#1789](https://github.com/gitkraken/vscode-gitlens/issues/1789)
- Ensures that large rebases show rich commit details
- Changes the _Home_ view to always be available
Expand Down
136 changes: 66 additions & 70 deletions src/webviews/apps/rebase/rebase.scss
Expand Up @@ -3,9 +3,17 @@
@import '../shared/utils';

body {
--avatar-size: 2.2rem;
overflow: overlay;
}

.vscode-dark {
--avatar-bg: var(--color-background--lighten-30);
}
.vscode-light {
--avatar-bg: var(--color-background--darken-30);
}

.container {
display: grid;
font-size: 1.3em;
Expand Down Expand Up @@ -80,16 +88,7 @@ footer {
}

.entries {
border-left: 2px solid;
margin-left: 10px;
padding-left: 4px;

.vscode-dark & {
border-color: var(--color-background--lighten-15);
}
.vscode-light & {
border-color: var(--color-background--darken-15);
}
padding: 0;
}

.entries--empty {
Expand Down Expand Up @@ -136,17 +135,42 @@ footer {
}
}

$entry-padding: 5px;
$entry-padding: 7px;

.entry {
.entry,
.entry-blocked {
display: flex;
align-items: center;
justify-content: space-between;
margin: 0px 5px 0px 10px;
padding: $entry-padding 0;
border: 2px solid transparent;
border-radius: 3px;
position: relative;
}

.entry {
padding-left: 26px;
margin: 0 5px 0 0;
content-visibility: auto;
contain-intrinsic-size: auto 36px;

&::before {
display: inline-block;
content: ' ';
background-color: var(--color-background);
border-right: 2px solid;
height: 100%;
position: absolute;
z-index: 0;
left: 10px;
top: 0;
transform: translateX(-50%);

.vscode-dark & {
border-right-color: var(--color-background--lighten-15);
}
.vscode-light & {
border-right-color: var(--color-background--darken-15);
}
}

&::after {
display: inline-block;
Expand All @@ -156,15 +180,14 @@ $entry-padding: 5px;
border-radius: 50%;
height: 12px;
width: 12px;
margin-left: -25px;
left: 2px;
position: absolute;
z-index: 2;
}

&:focus-within {
outline: none;
border: 2px solid var(--color-highlight--50);
border-radius: 3px;
outline: 2px solid var(--color-highlight--50);
outline-offset: -2px;
}

&.entry--edit,
Expand All @@ -175,14 +198,7 @@ $entry-padding: 5px;
}

&::before {
display: inline-block;
content: ' ';
background-color: var(--color-background);
border-right: 2px solid rgba(0, 153, 0, 1);
height: #{28px + ($entry-padding * 2)};
margin-left: -18px;
position: absolute;
z-index: 1;
border-right-color: rgba(0, 153, 0, 1);
}
}

Expand All @@ -193,15 +209,7 @@ $entry-padding: 5px;
}

&::before {
display: inline-block;
content: ' ';
background-color: var(--color-background);
border-right: 2px solid rgba(212, 153, 0, 1);
height: #{31px + ($entry-padding * 2)};
margin-left: -18px;
margin-top: 5px;
position: absolute;
z-index: 1;
border-right-color: rgba(212, 153, 0, 1);
}
}

Expand All @@ -211,14 +219,7 @@ $entry-padding: 5px;
}

&::before {
display: inline-block;
content: ' ';
background-color: var(--color-background);
border-right: 2px solid rgba(153, 0, 0, 1);
height: #{28px + ($entry-padding * 2)};
margin-left: -18px;
position: absolute;
z-index: 1;
border-right-color: rgba(153, 0, 0, 1);
}
}

Expand All @@ -229,18 +230,11 @@ $entry-padding: 5px;
}

&::before {
display: inline-block;
content: ' ';
background-color: var(--color-background);
border-right: 2px solid rgba(212, 153, 0, 1);
height: 40px;
margin-left: -18px;
margin-top: -5px;
position: absolute;
z-index: 1;
border-right-color: rgba(212, 153, 0, 1);
}
}

.entry-blocked,
&.entry--base,
&.entry--done {
& > .entry-action {
Expand All @@ -252,7 +246,6 @@ $entry-padding: 5px;
opacity: 0.4;
}

& > .entry-author,
& > .entry-date {
opacity: 0.3;
}
Expand Down Expand Up @@ -288,20 +281,12 @@ $entry-padding: 5px;

&.entry--base {
.entries--ascending & {
margin-bottom: 10px;
padding-top: 1px;
padding-bottom: 9px;
}
.entries:not(.entries--ascending) & {
margin-top: 10px;
}

.vscode-dark & {
background: rgba(255, 255, 255, 0.1);
box-shadow: 0px -1px 0px 0px rgba(255, 255, 255, 0.2);
}

.vscode-light & {
background: rgba(0, 0, 0, 0.1);
box-shadow: 0px -1px 0px 0px rgba(0, 0, 0, 0.2);
padding-top: 9px;
padding-bottom: 1px;
}
}

Expand All @@ -326,6 +311,20 @@ $entry-padding: 5px;
}
}

.entry-blocked {
width: 100%;

.vscode-dark & {
background: rgba(255, 255, 255, 0.1);
box-shadow: 0px -1px 0px 0px rgba(255, 255, 255, 0.2);
}

.vscode-light & {
background: rgba(0, 0, 0, 0.1);
box-shadow: 0px -1px 0px 0px rgba(0, 0, 0, 0.2);
}
}

.entry--drag {
opacity: 0 !important;
}
Expand Down Expand Up @@ -398,9 +397,7 @@ $entry-padding: 5px;

.entry-avatar {
flex: auto 0 0;
margin: 0 -5px 0 0;
max-height: 16px;
max-width: 16px;
margin: 0;

.entry--squash &,
.entry--fixup &,
Expand All @@ -409,7 +406,6 @@ $entry-padding: 5px;
}
}

.entry-author,
.entry-date,
.entry-sha {
flex: auto 0 0;
Expand Down
68 changes: 47 additions & 21 deletions src/webviews/apps/rebase/rebase.ts
Expand Up @@ -16,7 +16,10 @@ import {
UpdateSelectionCommandType,
} from '../../rebase/protocol';
import { App } from '../shared/appBase';
import type { AvatarItem } from '../shared/components/avatars/avatar-item';
import { DOM } from '../shared/dom';
import '../shared/components/avatars/avatar-item';
import '../shared/components/avatars/avatar-stack';

const rebaseActions = ['pick', 'reword', 'edit', 'squash', 'fixup', 'drop'];
const rebaseActionsMap = new Map<string, RebaseEntryAction>([
Expand Down Expand Up @@ -310,7 +313,9 @@ class RebaseEditor extends App<State> {
}

private setSelectedEntry(sha: string, focusSelect: boolean = false) {
document.querySelectorAll<HTMLLIElement>(`${focusSelect ? 'select' : 'li'}[data-sha="${sha}"]`)[0]?.focus();
window.requestAnimationFrame(() => {
document.querySelectorAll<HTMLLIElement>(`${focusSelect ? 'select' : 'li'}[data-sha="${sha}"]`)[0]?.focus();
});
}

protected override onMessageReceived(e: MessageEvent) {
Expand Down Expand Up @@ -386,7 +391,6 @@ class RebaseEditor extends App<State> {
let squashToHere = false;
let tabIndex = 0;

const $entries = document.createDocumentFragment();
for (const entry of state.entries) {
squashToHere = false;
if (entry.action === 'squash' || entry.action === 'fixup') {
Expand All @@ -401,9 +405,9 @@ class RebaseEditor extends App<State> {
[$el, tabIndex] = this.createEntry(entry, state, ++tabIndex, squashToHere);

if (state.ascending) {
$entries.prepend($el);
$container.prepend($el);
} else {
$entries.append($el);
$container.append($el);
}
}

Expand All @@ -422,9 +426,9 @@ class RebaseEditor extends App<State> {
false,
);
if (state.ascending) {
$entries.prepend($el);
$container.prepend($el);
} else {
$entries.appendChild($el);
$container.appendChild($el);
}
$container.classList.add('entries--base');
}
Expand All @@ -436,8 +440,6 @@ class RebaseEditor extends App<State> {
($checkbox as HTMLInputElement).checked = state.ascending;
}

$container.appendChild($entries);

this.setSelectedEntry(focusRef ?? state.entries[0].sha, focusSelect);
}

Expand All @@ -448,10 +450,18 @@ class RebaseEditor extends App<State> {
squashToHere: boolean,
): [HTMLLIElement, number] {
const $entry = document.createElement('li');
$entry.classList.add('entry', `entry--${entry.action ?? 'base'}`);
const action: string = entry.action ?? 'base';
$entry.classList.add('entry', `entry--${action}`);
$entry.classList.toggle('entry--squash-to', squashToHere);
$entry.dataset.sha = entry.sha;

let $content: HTMLElement = $entry;
if (action === 'base') {
$content = document.createElement('div');
$content.classList.add('entry-blocked');
$entry.appendChild($content);
}

if (entry.action != null) {
$entry.tabIndex = 0;

Expand Down Expand Up @@ -490,22 +500,38 @@ class RebaseEditor extends App<State> {
const message = commit?.message.trim() ?? entry.message.trim();
$message.textContent = message.replace(/\n+(?:\s+\n+)?/g, ' | ');
$message.title = message;
$entry.appendChild($message);
$content.appendChild($message);

if (commit != null) {
if (commit.author) {
const author = state.authors[commit.author];
if (author?.avatarUrl.length) {
const $avatar = document.createElement('img');
$avatar.classList.add('entry-avatar');
$avatar.src = author.avatarUrl;
$entry.appendChild($avatar);
}
const committer = state.authors[commit.committer];
if (author?.avatarUrl != null || committer?.avatarUrl != null) {
const $avatarStack = document.createElement('avatar-stack');
$avatarStack.classList.add('entry-avatar');

const hasAuthor = author?.avatarUrl.length;
const hasCommitter = author !== committer && committer?.avatarUrl.length;
if (hasAuthor) {
const $avatar = document.createElement('avatar-item') as AvatarItem;
$avatar.media = author.avatarUrl;
$avatar.ariaLabel = $avatar.title = hasCommitter
? `Authored by: ${author.author}`
: author.author;
$avatarStack.appendChild($avatar);
}

if (hasCommitter) {
const $avatar = document.createElement('avatar-item') as AvatarItem;
$avatar.media = committer.avatarUrl;
$avatar.ariaLabel = $avatar.title = hasAuthor
? `Committed by: ${committer.author}`
: committer.author;
$avatarStack.appendChild($avatar);
}

const $author = document.createElement('span');
$author.classList.add('entry-author');
$author.textContent = commit.author;
$entry.appendChild($author);
$entry.appendChild($avatarStack);
}
}

if (commit.dateFromNow) {
Expand All @@ -521,7 +547,7 @@ class RebaseEditor extends App<State> {
$sha.classList.add('entry-sha', 'icon--commit');
$sha.href = state.commands.commit.replace(this.commitTokenRegex, commit?.sha ?? entry.sha);
$sha.textContent = entry.sha.substr(0, 7);
$entry.appendChild($sha);
$content.appendChild($sha);

return [$entry, tabIndex];
}
Expand Down

0 comments on commit f58c3ab

Please sign in to comment.